eventq.hh revision 9554:406fbcf60223
14120Sgblack@eecs.umich.edu/*
24120Sgblack@eecs.umich.edu * Copyright (c) 2000-2005 The Regents of The University of Michigan
37087Snate@binkert.org * All rights reserved.
47087Snate@binkert.org *
57087Snate@binkert.org * Redistribution and use in source and binary forms, with or without
67087Snate@binkert.org * modification, are permitted provided that the following conditions are
77087Snate@binkert.org * met: redistributions of source code must retain the above copyright
87087Snate@binkert.org * notice, this list of conditions and the following disclaimer;
97087Snate@binkert.org * redistributions in binary form must reproduce the above copyright
107087Snate@binkert.org * notice, this list of conditions and the following disclaimer in the
117087Snate@binkert.org * documentation and/or other materials provided with the distribution;
127087Snate@binkert.org * neither the name of the copyright holders nor the names of its
137087Snate@binkert.org * contributors may be used to endorse or promote products derived from
147087Snate@binkert.org * this software without specific prior written permission.
154120Sgblack@eecs.umich.edu *
164120Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
174120Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
184120Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
194120Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
204120Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
214120Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
224120Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
234120Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
244120Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
254120Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
264120Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
274120Sgblack@eecs.umich.edu *
284120Sgblack@eecs.umich.edu * Authors: Steve Reinhardt
294120Sgblack@eecs.umich.edu *          Nathan Binkert
304120Sgblack@eecs.umich.edu */
314120Sgblack@eecs.umich.edu
324120Sgblack@eecs.umich.edu/* @file
334120Sgblack@eecs.umich.edu * EventQueue interfaces
344120Sgblack@eecs.umich.edu */
354120Sgblack@eecs.umich.edu
364120Sgblack@eecs.umich.edu#ifndef __SIM_EVENTQ_HH__
374120Sgblack@eecs.umich.edu#define __SIM_EVENTQ_HH__
384120Sgblack@eecs.umich.edu
394120Sgblack@eecs.umich.edu#include <algorithm>
404120Sgblack@eecs.umich.edu#include <cassert>
414120Sgblack@eecs.umich.edu#include <climits>
424120Sgblack@eecs.umich.edu#include <iosfwd>
434202Sbinkertn@umich.edu#include <string>
445069Sgblack@eecs.umich.edu
454202Sbinkertn@umich.edu#include "base/flags.hh"
465659Sgblack@eecs.umich.edu#include "base/misc.hh"
479022Sgblack@eecs.umich.edu#include "base/types.hh"
489023Sgblack@eecs.umich.edu#include "debug/Event.hh"
494601Sgblack@eecs.umich.edu#include "sim/serialize.hh"
505124Sgblack@eecs.umich.edu
517966Sgblack@eecs.umich.educlass EventQueue;       // forward declaration
525083Sgblack@eecs.umich.edu
534679Sgblack@eecs.umich.eduextern EventQueue mainEventQueue;
546515Sgblack@eecs.umich.edu
555083Sgblack@eecs.umich.edu/*
564679Sgblack@eecs.umich.edu * An item on an event queue.  The action caused by a given
574679Sgblack@eecs.umich.edu * event is specified by deriving a subclass and overriding the
588745Sgblack@eecs.umich.edu * process() member function.
596313Sgblack@eecs.umich.edu *
608771Sgblack@eecs.umich.edu * Caution, the order of members is chosen to maximize data packing.
618771Sgblack@eecs.umich.edu */
628771Sgblack@eecs.umich.educlass Event : public Serializable
636365Sgblack@eecs.umich.edu{
645124Sgblack@eecs.umich.edu    friend class EventQueue;
658752Sgblack@eecs.umich.edu
668771Sgblack@eecs.umich.edu  protected:
6710553Salexandru.dutu@amd.com    typedef unsigned short FlagsType;
684202Sbinkertn@umich.edu    typedef ::Flags<FlagsType> Flags;
698771Sgblack@eecs.umich.edu
708771Sgblack@eecs.umich.edu    static const FlagsType PublicRead    = 0x003f; // public readable flags
714997Sgblack@eecs.umich.edu    static const FlagsType PublicWrite   = 0x001d; // public writable flags
727624Sgblack@eecs.umich.edu    static const FlagsType Squashed      = 0x0001; // has been squashed
735135Sgblack@eecs.umich.edu    static const FlagsType Scheduled     = 0x0002; // has been scheduled
748753Sgblack@eecs.umich.edu    static const FlagsType AutoDelete    = 0x0004; // delete after dispatch
754997Sgblack@eecs.umich.edu    static const FlagsType AutoSerialize = 0x0008; // must be serialized
769384SAndreas.Sandberg@arm.com    static const FlagsType IsExitEvent   = 0x0010; // special exit event
778745Sgblack@eecs.umich.edu    static const FlagsType IsMainQueue   = 0x0020; // on main event queue
786365Sgblack@eecs.umich.edu    static const FlagsType Initialized   = 0x7a40; // somewhat random bits
798771Sgblack@eecs.umich.edu    static const FlagsType InitMask      = 0xffc0; // mask for init bits
808740Sgblack@eecs.umich.edu
816365Sgblack@eecs.umich.edu    bool
828740Sgblack@eecs.umich.edu    initialized() const
838745Sgblack@eecs.umich.edu    {
848752Sgblack@eecs.umich.edu        return this && (flags & InitMask) == Initialized;
858752Sgblack@eecs.umich.edu    }
869023Sgblack@eecs.umich.edu
878335Snate@binkert.org  public:
884120Sgblack@eecs.umich.edu    typedef int8_t Priority;
895069Sgblack@eecs.umich.edu
905081Sgblack@eecs.umich.edu  private:
915081Sgblack@eecs.umich.edu    // The event queue is now a linked list of linked lists.  The
925081Sgblack@eecs.umich.edu    // 'nextBin' pointer is to find the bin, where a bin is defined as
935081Sgblack@eecs.umich.edu    // when+priority.  All events in the same bin will be stored in a
945081Sgblack@eecs.umich.edu    // second linked list (a stack) maintained by the 'nextInBin'
955081Sgblack@eecs.umich.edu    // pointer.  The list will be accessed in LIFO order.  The end
965081Sgblack@eecs.umich.edu    // result is that the insert/removal in 'nextBin' is
975081Sgblack@eecs.umich.edu    // linear/constant, and the lookup/removal in 'nextInBin' is
985081Sgblack@eecs.umich.edu    // constant/constant.  Hopefully this is a significant improvement
995081Sgblack@eecs.umich.edu    // over the current fully linear insertion.
1005081Sgblack@eecs.umich.edu    Event *nextBin;
1015081Sgblack@eecs.umich.edu    Event *nextInBin;
1025081Sgblack@eecs.umich.edu
1035081Sgblack@eecs.umich.edu    static Event *insertBefore(Event *event, Event *curr);
1045081Sgblack@eecs.umich.edu    static Event *removeItem(Event *event, Event *last);
1055081Sgblack@eecs.umich.edu
1065081Sgblack@eecs.umich.edu    Tick _when;         //!< timestamp when event should be processed
1075081Sgblack@eecs.umich.edu    Priority _priority; //!< event priority
1085081Sgblack@eecs.umich.edu    Flags flags;
1095081Sgblack@eecs.umich.edu
1105081Sgblack@eecs.umich.edu#ifndef NDEBUG
1115081Sgblack@eecs.umich.edu    /// Global counter to generate unique IDs for Event instances
1125081Sgblack@eecs.umich.edu    static Counter instanceCounter;
1135081Sgblack@eecs.umich.edu
1145081Sgblack@eecs.umich.edu    /// This event's unique ID.  We can also use pointer values for
1155081Sgblack@eecs.umich.edu    /// this but they're not consistent across runs making debugging
1165081Sgblack@eecs.umich.edu    /// more difficult.  Thus we use a global counter value when
1175081Sgblack@eecs.umich.edu    /// debugging.
1185081Sgblack@eecs.umich.edu    Counter instance;
1195081Sgblack@eecs.umich.edu
1205081Sgblack@eecs.umich.edu    /// queue to which this event belongs (though it may or may not be
1215081Sgblack@eecs.umich.edu    /// scheduled on this queue yet)
1225081Sgblack@eecs.umich.edu    EventQueue *queue;
1235081Sgblack@eecs.umich.edu#endif
1245081Sgblack@eecs.umich.edu
1255081Sgblack@eecs.umich.edu#ifdef EVENTQ_DEBUG
1265081Sgblack@eecs.umich.edu    Tick whenCreated;   //!< time created
1275081Sgblack@eecs.umich.edu    Tick whenScheduled; //!< time scheduled
1285081Sgblack@eecs.umich.edu#endif
1295081Sgblack@eecs.umich.edu
1305081Sgblack@eecs.umich.edu    void
1315081Sgblack@eecs.umich.edu    setWhen(Tick when, EventQueue *q)
1325081Sgblack@eecs.umich.edu    {
1335081Sgblack@eecs.umich.edu        _when = when;
1345081Sgblack@eecs.umich.edu#ifndef NDEBUG
1355081Sgblack@eecs.umich.edu        queue = q;
1365081Sgblack@eecs.umich.edu#endif
1375081Sgblack@eecs.umich.edu#ifdef EVENTQ_DEBUG
1385081Sgblack@eecs.umich.edu        whenScheduled = curTick();
1395081Sgblack@eecs.umich.edu#endif
1405081Sgblack@eecs.umich.edu    }
1415081Sgblack@eecs.umich.edu
1425081Sgblack@eecs.umich.edu  protected:
1435081Sgblack@eecs.umich.edu    /// Accessor for flags.
1445081Sgblack@eecs.umich.edu    Flags
1455680Sgblack@eecs.umich.edu    getFlags() const
1465081Sgblack@eecs.umich.edu    {
1475933Sgblack@eecs.umich.edu        return flags & PublicRead;
1485173Sgblack@eecs.umich.edu    }
1495359Sgblack@eecs.umich.edu
1505081Sgblack@eecs.umich.edu    bool
1515149Sgblack@eecs.umich.edu    isFlagSet(Flags _flags) const
1525298Sgblack@eecs.umich.edu    {
1535081Sgblack@eecs.umich.edu        assert(_flags.noneSet(~PublicRead));
1545081Sgblack@eecs.umich.edu        return flags.isSet(_flags);
1555081Sgblack@eecs.umich.edu    }
1565081Sgblack@eecs.umich.edu
1575081Sgblack@eecs.umich.edu    /// Accessor for flags.
1585081Sgblack@eecs.umich.edu    void
1595081Sgblack@eecs.umich.edu    setFlags(Flags _flags)
1605081Sgblack@eecs.umich.edu    {
1615081Sgblack@eecs.umich.edu        assert(_flags.noneSet(~PublicWrite));
1625081Sgblack@eecs.umich.edu        flags.set(_flags);
1635081Sgblack@eecs.umich.edu    }
1645081Sgblack@eecs.umich.edu
1655081Sgblack@eecs.umich.edu    void
1665081Sgblack@eecs.umich.edu    clearFlags(Flags _flags)
1675081Sgblack@eecs.umich.edu    {
1685081Sgblack@eecs.umich.edu        assert(_flags.noneSet(~PublicWrite));
1695081Sgblack@eecs.umich.edu        flags.clear(_flags);
1705081Sgblack@eecs.umich.edu    }
1715081Sgblack@eecs.umich.edu
1725081Sgblack@eecs.umich.edu    void
1735081Sgblack@eecs.umich.edu    clearFlags()
1745081Sgblack@eecs.umich.edu    {
1755081Sgblack@eecs.umich.edu        flags.clear(PublicWrite);
1765081Sgblack@eecs.umich.edu    }
1775081Sgblack@eecs.umich.edu
1785081Sgblack@eecs.umich.edu    // This function isn't really useful if TRACING_ON is not defined
1795081Sgblack@eecs.umich.edu    virtual void trace(const char *action);     //!< trace event activity
1805081Sgblack@eecs.umich.edu
1815081Sgblack@eecs.umich.edu  public:
1825081Sgblack@eecs.umich.edu    /// Event priorities, to provide tie-breakers for events scheduled
1835081Sgblack@eecs.umich.edu    /// at the same cycle.  Most events are scheduled at the default
1845081Sgblack@eecs.umich.edu    /// priority; these values are used to control events that need to
1855081Sgblack@eecs.umich.edu    /// be ordered within a cycle.
1865081Sgblack@eecs.umich.edu
1875081Sgblack@eecs.umich.edu    /// Minimum priority
1885081Sgblack@eecs.umich.edu    static const Priority Minimum_Pri =          SCHAR_MIN;
1895081Sgblack@eecs.umich.edu
1905081Sgblack@eecs.umich.edu    /// If we enable tracing on a particular cycle, do that as the
1915081Sgblack@eecs.umich.edu    /// very first thing so we don't miss any of the events on
1925081Sgblack@eecs.umich.edu    /// that cycle (even if we enter the debugger).
1935081Sgblack@eecs.umich.edu    static const Priority Trace_Enable_Pri =          -101;
1945081Sgblack@eecs.umich.edu
1955081Sgblack@eecs.umich.edu    /// Breakpoints should happen before anything else (except
1965081Sgblack@eecs.umich.edu    /// enabling trace output), so we don't miss any action when
1975081Sgblack@eecs.umich.edu    /// debugging.
1985081Sgblack@eecs.umich.edu    static const Priority Debug_Break_Pri =           -100;
1995081Sgblack@eecs.umich.edu
2005081Sgblack@eecs.umich.edu    /// CPU switches schedule the new CPU's tick event for the
2015081Sgblack@eecs.umich.edu    /// same cycle (after unscheduling the old CPU's tick event).
2025081Sgblack@eecs.umich.edu    /// The switch needs to come before any tick events to make
2035081Sgblack@eecs.umich.edu    /// sure we don't tick both CPUs in the same cycle.
2045081Sgblack@eecs.umich.edu    static const Priority CPU_Switch_Pri =             -31;
2055081Sgblack@eecs.umich.edu
2065081Sgblack@eecs.umich.edu    /// For some reason "delayed" inter-cluster writebacks are
2075081Sgblack@eecs.umich.edu    /// scheduled before regular writebacks (which have default
2085081Sgblack@eecs.umich.edu    /// priority).  Steve?
2095081Sgblack@eecs.umich.edu    static const Priority Delayed_Writeback_Pri =       -1;
2105081Sgblack@eecs.umich.edu
2115081Sgblack@eecs.umich.edu    /// Default is zero for historical reasons.
2125081Sgblack@eecs.umich.edu    static const Priority Default_Pri =                  0;
2135081Sgblack@eecs.umich.edu
2145081Sgblack@eecs.umich.edu    /// Serailization needs to occur before tick events also, so
2155081Sgblack@eecs.umich.edu    /// that a serialize/unserialize is identical to an on-line
2165081Sgblack@eecs.umich.edu    /// CPU switch.
2175081Sgblack@eecs.umich.edu    static const Priority Serialize_Pri =               32;
2185081Sgblack@eecs.umich.edu
2195081Sgblack@eecs.umich.edu    /// CPU ticks must come after other associated CPU events
2205081Sgblack@eecs.umich.edu    /// (such as writebacks).
2215081Sgblack@eecs.umich.edu    static const Priority CPU_Tick_Pri =                50;
2225081Sgblack@eecs.umich.edu
2235081Sgblack@eecs.umich.edu    /// Statistics events (dump, reset, etc.) come after
2245081Sgblack@eecs.umich.edu    /// everything else, but before exit.
2255081Sgblack@eecs.umich.edu    static const Priority Stat_Event_Pri =              90;
2265081Sgblack@eecs.umich.edu
2275081Sgblack@eecs.umich.edu    /// Progress events come at the end.
2285081Sgblack@eecs.umich.edu    static const Priority Progress_Event_Pri =          95;
2295081Sgblack@eecs.umich.edu
2305081Sgblack@eecs.umich.edu    /// If we want to exit on this cycle, it's the very last thing
2315081Sgblack@eecs.umich.edu    /// we do.
2325081Sgblack@eecs.umich.edu    static const Priority Sim_Exit_Pri =               100;
2335081Sgblack@eecs.umich.edu
2345081Sgblack@eecs.umich.edu    /// Maximum priority
2355081Sgblack@eecs.umich.edu    static const Priority Maximum_Pri =          SCHAR_MAX;
2365081Sgblack@eecs.umich.edu
2375081Sgblack@eecs.umich.edu    /*
2385081Sgblack@eecs.umich.edu     * Event constructor
2395081Sgblack@eecs.umich.edu     * @param queue that the event gets scheduled on
2405081Sgblack@eecs.umich.edu     */
2415081Sgblack@eecs.umich.edu    Event(Priority p = Default_Pri, Flags f = 0)
2425081Sgblack@eecs.umich.edu        : nextBin(NULL), nextInBin(NULL), _priority(p),
2435081Sgblack@eecs.umich.edu          flags(Initialized | f)
2445081Sgblack@eecs.umich.edu    {
2455081Sgblack@eecs.umich.edu        assert(f.noneSet(~PublicWrite));
2465081Sgblack@eecs.umich.edu#ifndef NDEBUG
2475081Sgblack@eecs.umich.edu        instance = ++instanceCounter;
2485081Sgblack@eecs.umich.edu        queue = NULL;
2495081Sgblack@eecs.umich.edu#endif
2505081Sgblack@eecs.umich.edu#ifdef EVENTQ_DEBUG
2515081Sgblack@eecs.umich.edu        whenCreated = curTick();
2525081Sgblack@eecs.umich.edu        whenScheduled = 0;
2535081Sgblack@eecs.umich.edu#endif
2545081Sgblack@eecs.umich.edu    }
2555081Sgblack@eecs.umich.edu
2565081Sgblack@eecs.umich.edu    virtual ~Event();
2575081Sgblack@eecs.umich.edu    virtual const std::string name() const;
2585081Sgblack@eecs.umich.edu
2595081Sgblack@eecs.umich.edu    /// Return a C string describing the event.  This string should
2605081Sgblack@eecs.umich.edu    /// *not* be dynamically allocated; just a const char array
2615081Sgblack@eecs.umich.edu    /// describing the event class.
2625081Sgblack@eecs.umich.edu    virtual const char *description() const;
2635081Sgblack@eecs.umich.edu
2645081Sgblack@eecs.umich.edu    /// Dump the current event data
2655081Sgblack@eecs.umich.edu    void dump() const;
2665081Sgblack@eecs.umich.edu
2675081Sgblack@eecs.umich.edu  public:
2685081Sgblack@eecs.umich.edu    /*
2695081Sgblack@eecs.umich.edu     * This member function is invoked when the event is processed
2705081Sgblack@eecs.umich.edu     * (occurs).  There is no default implementation; each subclass
2715081Sgblack@eecs.umich.edu     * must provide its own implementation.  The event is not
2725081Sgblack@eecs.umich.edu     * automatically deleted after it is processed (to allow for
2735081Sgblack@eecs.umich.edu     * statically allocated event objects).
2745081Sgblack@eecs.umich.edu     *
2755081Sgblack@eecs.umich.edu     * If the AutoDestroy flag is set, the object is deleted once it
2765081Sgblack@eecs.umich.edu     * is processed.
2775081Sgblack@eecs.umich.edu     */
2785081Sgblack@eecs.umich.edu    virtual void process() = 0;
2795081Sgblack@eecs.umich.edu
2805081Sgblack@eecs.umich.edu    /// Determine if the current event is scheduled
2815081Sgblack@eecs.umich.edu    bool scheduled() const { return flags.isSet(Scheduled); }
2825081Sgblack@eecs.umich.edu
2835081Sgblack@eecs.umich.edu    /// Squash the current event
2845081Sgblack@eecs.umich.edu    void squash() { flags.set(Squashed); }
2855081Sgblack@eecs.umich.edu
2865081Sgblack@eecs.umich.edu    /// Check whether the event is squashed
2875081Sgblack@eecs.umich.edu    bool squashed() const { return flags.isSet(Squashed); }
2885081Sgblack@eecs.umich.edu
2895081Sgblack@eecs.umich.edu    /// See if this is a SimExitEvent (without resorting to RTTI)
2905081Sgblack@eecs.umich.edu    bool isExitEvent() const { return flags.isSet(IsExitEvent); }
2915081Sgblack@eecs.umich.edu
2925081Sgblack@eecs.umich.edu    /// Get the time that the event is scheduled
2935081Sgblack@eecs.umich.edu    Tick when() const { return _when; }
2945081Sgblack@eecs.umich.edu
2955081Sgblack@eecs.umich.edu    /// Get the event priority
2965081Sgblack@eecs.umich.edu    Priority priority() const { return _priority; }
2975081Sgblack@eecs.umich.edu
2985081Sgblack@eecs.umich.edu#ifndef SWIG
2995081Sgblack@eecs.umich.edu    virtual void serialize(std::ostream &os);
3005081Sgblack@eecs.umich.edu    virtual void unserialize(Checkpoint *cp, const std::string &section);
3015081Sgblack@eecs.umich.edu#endif
3025081Sgblack@eecs.umich.edu};
3035081Sgblack@eecs.umich.edu
3045081Sgblack@eecs.umich.edu#ifndef SWIG
3055081Sgblack@eecs.umich.eduinline bool
3065081Sgblack@eecs.umich.eduoperator<(const Event &l, const Event &r)
3075081Sgblack@eecs.umich.edu{
3085069Sgblack@eecs.umich.edu    return l.when() < r.when() ||
3094202Sbinkertn@umich.edu        (l.when() == r.when() && l.priority() < r.priority());
3104202Sbinkertn@umich.edu}
3114202Sbinkertn@umich.edu
3125069Sgblack@eecs.umich.eduinline bool
3135069Sgblack@eecs.umich.eduoperator>(const Event &l, const Event &r)
3145069Sgblack@eecs.umich.edu{
315    return l.when() > r.when() ||
316        (l.when() == r.when() && l.priority() > r.priority());
317}
318
319inline bool
320operator<=(const Event &l, const Event &r)
321{
322    return l.when() < r.when() ||
323        (l.when() == r.when() && l.priority() <= r.priority());
324}
325inline bool
326operator>=(const Event &l, const Event &r)
327{
328    return l.when() > r.when() ||
329        (l.when() == r.when() && l.priority() >= r.priority());
330}
331
332inline bool
333operator==(const Event &l, const Event &r)
334{
335    return l.when() == r.when() && l.priority() == r.priority();
336}
337
338inline bool
339operator!=(const Event &l, const Event &r)
340{
341    return l.when() != r.when() || l.priority() != r.priority();
342}
343#endif
344
345/*
346 * Queue of events sorted in time order
347 */
348class EventQueue : public Serializable
349{
350  private:
351    std::string objName;
352    Event *head;
353    Tick _curTick;
354
355    void insert(Event *event);
356    void remove(Event *event);
357
358    EventQueue(const EventQueue &);
359    const EventQueue &operator=(const EventQueue &);
360
361  public:
362    EventQueue(const std::string &n);
363
364    virtual const std::string name() const { return objName; }
365
366    // schedule the given event on this queue
367    void schedule(Event *event, Tick when);
368    void deschedule(Event *event);
369    void reschedule(Event *event, Tick when, bool always = false);
370
371    Tick nextTick() const { return head->when(); }
372    void setCurTick(Tick newVal) { _curTick = newVal; }
373    Tick getCurTick() { return _curTick; }
374
375    Event *serviceOne();
376
377    // process all events up to the given timestamp.  we inline a
378    // quick test to see if there are any events to process; if so,
379    // call the internal out-of-line version to process them all.
380    void
381    serviceEvents(Tick when)
382    {
383        while (!empty()) {
384            if (nextTick() > when)
385                break;
386
387            /**
388             * @todo this assert is a good bug catcher.  I need to
389             * make it true again.
390             */
391            //assert(head->when() >= when && "event scheduled in the past");
392            serviceOne();
393        }
394
395        setCurTick(when);
396    }
397
398    // return true if no events are queued
399    bool empty() const { return head == NULL; }
400
401    void dump() const;
402
403    bool debugVerify() const;
404
405    /**
406     *  function for replacing the head of the event queue, so that a
407     *  different set of events can run without disturbing events that have
408     *  already been scheduled. Already scheduled events can be processed
409     *  by replacing the original head back.
410     *  USING THIS FUNCTION CAN BE DANGEROUS TO THE HEALTH OF THE SIMULATOR.
411     *  NOT RECOMMENDED FOR USE.
412     */
413    Event* replaceHead(Event* s);
414
415#ifndef SWIG
416    virtual void serialize(std::ostream &os);
417    virtual void unserialize(Checkpoint *cp, const std::string &section);
418#endif
419};
420
421void dumpMainQueue();
422
423#ifndef SWIG
424class EventManager
425{
426  protected:
427    /** A pointer to this object's event queue */
428    EventQueue *eventq;
429
430  public:
431    EventManager(EventManager &em) : eventq(em.eventq) {}
432    EventManager(EventManager *em) : eventq(em->eventq) {}
433    EventManager(EventQueue *eq) : eventq(eq) {}
434
435    EventQueue *
436    eventQueue() const
437    {
438        return eventq;
439    }
440
441    void
442    schedule(Event &event, Tick when)
443    {
444        eventq->schedule(&event, when);
445    }
446
447    void
448    deschedule(Event &event)
449    {
450        eventq->deschedule(&event);
451    }
452
453    void
454    reschedule(Event &event, Tick when, bool always = false)
455    {
456        eventq->reschedule(&event, when, always);
457    }
458
459    void
460    schedule(Event *event, Tick when)
461    {
462        eventq->schedule(event, when);
463    }
464
465    void
466    deschedule(Event *event)
467    {
468        eventq->deschedule(event);
469    }
470
471    void
472    reschedule(Event *event, Tick when, bool always = false)
473    {
474        eventq->reschedule(event, when, always);
475    }
476
477    void setCurTick(Tick newVal) { eventq->setCurTick(newVal); }
478};
479
480template <class T, void (T::* F)()>
481void
482DelayFunction(EventQueue *eventq, Tick when, T *object)
483{
484    class DelayEvent : public Event
485    {
486      private:
487        T *object;
488
489      public:
490        DelayEvent(T *o)
491            : Event(Default_Pri, AutoDelete), object(o)
492        { }
493        void process() { (object->*F)(); }
494        const char *description() const { return "delay"; }
495    };
496
497    eventq->schedule(new DelayEvent(object), when);
498}
499
500template <class T, void (T::* F)()>
501class EventWrapper : public Event
502{
503  private:
504    T *object;
505
506  public:
507    EventWrapper(T *obj, bool del = false, Priority p = Default_Pri)
508        : Event(p), object(obj)
509    {
510        if (del)
511            setFlags(AutoDelete);
512    }
513
514    EventWrapper(T &obj, bool del = false, Priority p = Default_Pri)
515        : Event(p), object(&obj)
516    {
517        if (del)
518            setFlags(AutoDelete);
519    }
520
521    void process() { (object->*F)(); }
522
523    const std::string
524    name() const
525    {
526        return object->name() + ".wrapped_event";
527    }
528
529    const char *description() const { return "EventWrapped"; }
530};
531#endif
532
533#endif // __SIM_EVENTQ_HH__
534