eventq.hh revision 10153:936a3a8006f6
12381SN/A/*
210719SMarco.Balboni@ARM.com * Copyright (c) 2000-2005 The Regents of The University of Michigan
38711SN/A * Copyright (c) 2013 Advanced Micro Devices, Inc.
48711SN/A * Copyright (c) 2013 Mark D. Hill and David A. Wood
58711SN/A * All rights reserved.
68711SN/A *
78711SN/A * Redistribution and use in source and binary forms, with or without
88711SN/A * modification, are permitted provided that the following conditions are
98711SN/A * met: redistributions of source code must retain the above copyright
108711SN/A * notice, this list of conditions and the following disclaimer;
118711SN/A * redistributions in binary form must reproduce the above copyright
128711SN/A * notice, this list of conditions and the following disclaimer in the
138711SN/A * documentation and/or other materials provided with the distribution;
142381SN/A * neither the name of the copyright holders nor the names of its
152381SN/A * contributors may be used to endorse or promote products derived from
162381SN/A * this software without specific prior written permission.
172381SN/A *
182381SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
192381SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
202381SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
212381SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
222381SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
232381SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
242381SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
252381SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
262381SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
272381SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
282381SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
292381SN/A *
302381SN/A * Authors: Steve Reinhardt
312381SN/A *          Nathan Binkert
322381SN/A */
332381SN/A
342381SN/A/* @file
352381SN/A * EventQueue interfaces
362381SN/A */
372381SN/A
382381SN/A#ifndef __SIM_EVENTQ_HH__
392665SN/A#define __SIM_EVENTQ_HH__
402665SN/A
412772SN/A#include <algorithm>
428715SN/A#include <cassert>
438922SN/A#include <climits>
442381SN/A#include <iosfwd>
452381SN/A#include <mutex>
462381SN/A#include <string>
472982SN/A
4810405Sandreas.hansson@arm.com#include "base/flags.hh"
492381SN/A#include "base/misc.hh"
502381SN/A#include "base/types.hh"
5110405Sandreas.hansson@arm.com#include "debug/Event.hh"
5210405Sandreas.hansson@arm.com#include "sim/serialize.hh"
532381SN/A
5410402SN/Aclass EventQueue;       // forward declaration
5510405Sandreas.hansson@arm.comclass BaseGlobalEvent;
5610405Sandreas.hansson@arm.com
572381SN/A//! Simulation Quantum for multiple eventq simulation.
589036SN/A//! The quantum value is the period length after which the queues
5910405Sandreas.hansson@arm.com//! synchronize themselves with each other. This means that any
6010405Sandreas.hansson@arm.com//! event to scheduled on Queue A which is generated by an event on
6110405Sandreas.hansson@arm.com//! Queue B should be at least simQuantum ticks away in future.
6210405Sandreas.hansson@arm.comextern Tick simQuantum;
639036SN/A
6410405Sandreas.hansson@arm.com//! Current number of allocated main event queues.
6510405Sandreas.hansson@arm.comextern uint32_t numMainEventQueues;
6610405Sandreas.hansson@arm.com
6710405Sandreas.hansson@arm.com//! Array for main event queues.
689036SN/Aextern std::vector<EventQueue *> mainEventQueue;
6910405Sandreas.hansson@arm.com
702381SN/A#ifndef SWIG
719031SN/A//! The current event queue for the running thread. Access to this queue
729036SN/A//! does not require any locking from the thread.
739036SN/A
748922SN/Aextern __thread EventQueue *_curEventQueue;
7510405Sandreas.hansson@arm.com
7610405Sandreas.hansson@arm.com#endif
779092SN/A
789715SN/A//! Current mode of execution: parallel / serial
799715SN/Aextern bool inParallelMode;
8010713Sandreas.hansson@arm.com
819092SN/A//! Function for returning eventq queue for the provided
829092SN/A//! index. The function allocates a new queue in case one
8310405Sandreas.hansson@arm.com//! does not exist for the index, provided that the index
8410405Sandreas.hansson@arm.com//! is with in bounds.
8510405Sandreas.hansson@arm.comEventQueue *getEventQueue(uint32_t index);
868922SN/A
8710888Sandreas.hansson@arm.cominline EventQueue *curEventQueue() { return _curEventQueue; }
882381SN/Ainline void curEventQueue(EventQueue *q) { _curEventQueue = q; }
899036SN/A
908922SN/A/**
919036SN/A * Common base class for Event and GlobalEvent, so they can share flag
9210405Sandreas.hansson@arm.com * and priority definitions and accessor functions.  This class should
9310405Sandreas.hansson@arm.com * not be used directly.
942381SN/A */
9510888Sandreas.hansson@arm.comclass EventBase
9610888Sandreas.hansson@arm.com{
9710888Sandreas.hansson@arm.com  protected:
982381SN/A    typedef unsigned short FlagsType;
992381SN/A    typedef ::Flags<FlagsType> Flags;
10010405Sandreas.hansson@arm.com
10110405Sandreas.hansson@arm.com    static const FlagsType PublicRead    = 0x003f; // public readable flags
10210888Sandreas.hansson@arm.com    static const FlagsType PublicWrite   = 0x001d; // public writable flags
10310888Sandreas.hansson@arm.com    static const FlagsType Squashed      = 0x0001; // has been squashed
1048922SN/A    static const FlagsType Scheduled     = 0x0002; // has been scheduled
1058922SN/A    static const FlagsType AutoDelete    = 0x0004; // delete after dispatch
1068922SN/A    static const FlagsType AutoSerialize = 0x0008; // must be serialized
1078922SN/A    static const FlagsType IsExitEvent   = 0x0010; // special exit event
1088948SN/A    static const FlagsType IsMainQueue   = 0x0020; // on main event queue
10910405Sandreas.hansson@arm.com    static const FlagsType Initialized   = 0x7a40; // somewhat random bits
1108948SN/A    static const FlagsType InitMask      = 0xffc0; // mask for init bits
1118975SN/A
11210405Sandreas.hansson@arm.com  public:
1138922SN/A    typedef int8_t Priority;
1148948SN/A
11510405Sandreas.hansson@arm.com    /// Event priorities, to provide tie-breakers for events scheduled
1168948SN/A    /// at the same cycle.  Most events are scheduled at the default
1178975SN/A    /// priority; these values are used to control events that need to
11810405Sandreas.hansson@arm.com    /// be ordered within a cycle.
1198948SN/A
1208948SN/A    /// Minimum priority
12110405Sandreas.hansson@arm.com    static const Priority Minimum_Pri =          SCHAR_MIN;
1228948SN/A
1238922SN/A    /// If we enable tracing on a particular cycle, do that as the
12410405Sandreas.hansson@arm.com    /// very first thing so we don't miss any of the events on
1258922SN/A    /// that cycle (even if we enter the debugger).
1268948SN/A    static const Priority Debug_Enable_Pri =          -101;
12710405Sandreas.hansson@arm.com
1288948SN/A    /// Breakpoints should happen before anything else (except
1298922SN/A    /// enabling trace output), so we don't miss any action when
13010405Sandreas.hansson@arm.com    /// debugging.
1318922SN/A    static const Priority Debug_Break_Pri =           -100;
1328948SN/A
13310405Sandreas.hansson@arm.com    /// CPU switches schedule the new CPU's tick event for the
1349036SN/A    /// same cycle (after unscheduling the old CPU's tick event).
1359090SN/A    /// The switch needs to come before any tick events to make
13610405Sandreas.hansson@arm.com    /// sure we don't tick both CPUs in the same cycle.
1379036SN/A    static const Priority CPU_Switch_Pri =             -31;
1389036SN/A
1399036SN/A    /// For some reason "delayed" inter-cluster writebacks are
1409036SN/A    /// scheduled before regular writebacks (which have default
14110405Sandreas.hansson@arm.com    /// priority).  Steve?
1429036SN/A    static const Priority Delayed_Writeback_Pri =       -1;
14310405Sandreas.hansson@arm.com
1449036SN/A    /// Default is zero for historical reasons.
14510405Sandreas.hansson@arm.com    static const Priority Default_Pri =                  0;
1469036SN/A
1479036SN/A    /// Serailization needs to occur before tick events also, so
14810405Sandreas.hansson@arm.com    /// that a serialize/unserialize is identical to an on-line
14910405Sandreas.hansson@arm.com    /// CPU switch.
1509036SN/A    static const Priority Serialize_Pri =               32;
1519036SN/A
1529036SN/A    /// CPU ticks must come after other associated CPU events
15310405Sandreas.hansson@arm.com    /// (such as writebacks).
15410405Sandreas.hansson@arm.com    static const Priority CPU_Tick_Pri =                50;
15510405Sandreas.hansson@arm.com
1569036SN/A    /// Statistics events (dump, reset, etc.) come after
1579036SN/A    /// everything else, but before exit.
1589036SN/A    static const Priority Stat_Event_Pri =              90;
1599036SN/A
1609036SN/A    /// Progress events come at the end.
1619036SN/A    static const Priority Progress_Event_Pri =          95;
16210405Sandreas.hansson@arm.com
1639036SN/A    /// If we want to exit on this cycle, it's the very last thing
1649036SN/A    /// we do.
1659036SN/A    static const Priority Sim_Exit_Pri =               100;
1669036SN/A
1679036SN/A    /// Maximum priority
1689036SN/A    static const Priority Maximum_Pri =          SCHAR_MAX;
1699036SN/A};
17010405Sandreas.hansson@arm.com
1719036SN/A/*
1729036SN/A * An item on an event queue.  The action caused by a given
17310405Sandreas.hansson@arm.com * event is specified by deriving a subclass and overriding the
1749036SN/A * process() member function.
1759036SN/A *
17610405Sandreas.hansson@arm.com * Caution, the order of members is chosen to maximize data packing.
1779036SN/A */
1789036SN/Aclass Event : public EventBase, public Serializable
17910405Sandreas.hansson@arm.com{
1809036SN/A    friend class EventQueue;
1819036SN/A
18210405Sandreas.hansson@arm.com  private:
1839036SN/A    // The event queue is now a linked list of linked lists.  The
1849036SN/A    // 'nextBin' pointer is to find the bin, where a bin is defined as
18510405Sandreas.hansson@arm.com    // when+priority.  All events in the same bin will be stored in a
1869036SN/A    // second linked list (a stack) maintained by the 'nextInBin'
1879036SN/A    // pointer.  The list will be accessed in LIFO order.  The end
18810405Sandreas.hansson@arm.com    // result is that the insert/removal in 'nextBin' is
1899036SN/A    // linear/constant, and the lookup/removal in 'nextInBin' is
1909036SN/A    // constant/constant.  Hopefully this is a significant improvement
19110405Sandreas.hansson@arm.com    // over the current fully linear insertion.
1929036SN/A    Event *nextBin;
1939036SN/A    Event *nextInBin;
19410405Sandreas.hansson@arm.com
1959036SN/A    static Event *insertBefore(Event *event, Event *curr);
19610405Sandreas.hansson@arm.com    static Event *removeItem(Event *event, Event *last);
1979036SN/A
1989036SN/A    Tick _when;         //!< timestamp when event should be processed
19910405Sandreas.hansson@arm.com    Priority _priority; //!< event priority
20010713Sandreas.hansson@arm.com    Flags flags;
20110713Sandreas.hansson@arm.com
2028922SN/A#ifndef NDEBUG
2038922SN/A    /// Global counter to generate unique IDs for Event instances
2048922SN/A    static Counter instanceCounter;
2059716SN/A
2069716SN/A    /// This event's unique ID.  We can also use pointer values for
2079716SN/A    /// this but they're not consistent across runs making debugging
2089716SN/A    /// more difficult.  Thus we use a global counter value when
2099716SN/A    /// debugging.
2109716SN/A    Counter instance;
2119716SN/A
2129716SN/A    /// queue to which this event belongs (though it may or may not be
2139716SN/A    /// scheduled on this queue yet)
2149716SN/A    EventQueue *queue;
2159716SN/A#endif
21610888Sandreas.hansson@arm.com
2179716SN/A#ifdef EVENTQ_DEBUG
2189716SN/A    Tick whenCreated;   //!< time created
2199716SN/A    Tick whenScheduled; //!< time scheduled
2209716SN/A#endif
2219716SN/A
2229716SN/A    void
22310888Sandreas.hansson@arm.com    setWhen(Tick when, EventQueue *q)
22410405Sandreas.hansson@arm.com    {
2259778SN/A        _when = when;
2269716SN/A#ifndef NDEBUG
2279716SN/A        queue = q;
2289716SN/A#endif
2299716SN/A#ifdef EVENTQ_DEBUG
2309716SN/A        whenScheduled = curTick();
23110713Sandreas.hansson@arm.com#endif
23210713Sandreas.hansson@arm.com    }
23310713Sandreas.hansson@arm.com
2349716SN/A    bool
2359716SN/A    initialized() const
2369716SN/A    {
2379716SN/A        return this && (flags & InitMask) == Initialized;
2389716SN/A    }
23910713Sandreas.hansson@arm.com
2409716SN/A  protected:
2419716SN/A    /// Accessor for flags.
2429716SN/A    Flags
2439716SN/A    getFlags() const
2449716SN/A    {
2459716SN/A        return flags & PublicRead;
2469716SN/A    }
2479716SN/A
2489716SN/A    bool
2499716SN/A    isFlagSet(Flags _flags) const
2509716SN/A    {
2519716SN/A        assert(_flags.noneSet(~PublicRead));
2529716SN/A        return flags.isSet(_flags);
2539716SN/A    }
25410888Sandreas.hansson@arm.com
2554475SN/A    /// Accessor for flags.
2568948SN/A    void
25710656Sandreas.hansson@arm.com    setFlags(Flags _flags)
25810656Sandreas.hansson@arm.com    {
25910656Sandreas.hansson@arm.com        assert(_flags.noneSet(~PublicWrite));
2608948SN/A        flags.set(_flags);
26111168Sandreas.hansson@arm.com    }
2628948SN/A
2639524SN/A    void
2649524SN/A    clearFlags(Flags _flags)
2659524SN/A    {
2669524SN/A        assert(_flags.noneSet(~PublicWrite));
2679524SN/A        flags.clear(_flags);
2689524SN/A    }
26910402SN/A
27010402SN/A    void
27110402SN/A    clearFlags()
27210402SN/A    {
27310719SMarco.Balboni@ARM.com        flags.clear(PublicWrite);
27410719SMarco.Balboni@ARM.com    }
27510719SMarco.Balboni@ARM.com
27610883Sali.jafri@arm.com    // This function isn't really useful if TRACING_ON is not defined
27710883Sali.jafri@arm.com    virtual void trace(const char *action);     //!< trace event activity
27810883Sali.jafri@arm.com
27910883Sali.jafri@arm.com  public:
28010883Sali.jafri@arm.com
28110883Sali.jafri@arm.com    /*
28210883Sali.jafri@arm.com     * Event constructor
28310405Sandreas.hansson@arm.com     * @param queue that the event gets scheduled on
2848975SN/A     */
2859945SN/A    Event(Priority p = Default_Pri, Flags f = 0)
2868975SN/A        : nextBin(NULL), nextInBin(NULL), _priority(p),
28710405Sandreas.hansson@arm.com          flags(Initialized | f)
2888975SN/A    {
2899945SN/A        assert(f.noneSet(~PublicWrite));
2904475SN/A#ifndef NDEBUG
29110405Sandreas.hansson@arm.com        instance = ++instanceCounter;
2928975SN/A        queue = NULL;
2939945SN/A#endif
2948975SN/A#ifdef EVENTQ_DEBUG
29510405Sandreas.hansson@arm.com        whenCreated = curTick();
2968975SN/A        whenScheduled = 0;
2979945SN/A#endif
2988948SN/A    }
2999092SN/A
3009092SN/A    virtual ~Event();
30110713Sandreas.hansson@arm.com    virtual const std::string name() const;
3029092SN/A
3038948SN/A    /// Return a C string describing the event.  This string should
3048948SN/A    /// *not* be dynamically allocated; just a const char array
3058948SN/A    /// describing the event class.
3068948SN/A    virtual const char *description() const;
3078948SN/A
3088948SN/A    /// Dump the current event data
3098948SN/A    void dump() const;
3108948SN/A
31110402SN/A  public:
31210402SN/A    /*
31310402SN/A     * This member function is invoked when the event is processed
31410402SN/A     * (occurs).  There is no default implementation; each subclass
31510402SN/A     * must provide its own implementation.  The event is not
31610402SN/A     * automatically deleted after it is processed (to allow for
31710402SN/A     * statically allocated event objects).
31810402SN/A     *
31910402SN/A     * If the AutoDestroy flag is set, the object is deleted once it
32010402SN/A     * is processed.
32110402SN/A     */
32210402SN/A    virtual void process() = 0;
32310402SN/A
32410402SN/A    /// Determine if the current event is scheduled
32510888Sandreas.hansson@arm.com    bool scheduled() const { return flags.isSet(Scheduled); }
3268948SN/A
32710405Sandreas.hansson@arm.com    /// Squash the current event
3284475SN/A    void squash() { flags.set(Squashed); }
3299032SN/A
3304475SN/A    /// Check whether the event is squashed
33110405Sandreas.hansson@arm.com    bool squashed() const { return flags.isSet(Squashed); }
3328948SN/A
3339032SN/A    /// See if this is a SimExitEvent (without resorting to RTTI)
3348948SN/A    bool isExitEvent() const { return flags.isSet(IsExitEvent); }
3358948SN/A
3368948SN/A    /// Get the time that the event is scheduled
3378948SN/A    Tick when() const { return _when; }
3388948SN/A
3398948SN/A    /// Get the event priority
3408948SN/A    Priority priority() const { return _priority; }
3418948SN/A
3428948SN/A    //! If this is part of a GlobalEvent, return the pointer to the
3438948SN/A    //! Global Event.  By default, there is no GlobalEvent, so return
3448948SN/A    //! NULL.  (Overridden in GlobalEvent::BarrierEvent.)
3458948SN/A    virtual BaseGlobalEvent *globalEvent() { return NULL; }
34610402SN/A
34710402SN/A#ifndef SWIG
34810888Sandreas.hansson@arm.com    virtual void serialize(std::ostream &os);
34910888Sandreas.hansson@arm.com    virtual void unserialize(Checkpoint *cp, const std::string &section);
35010402SN/A
35110402SN/A    //! This function is required to support restoring from checkpoints
35210402SN/A    //! when running with multiple queues. Since we still have not thrashed
35310402SN/A    //! out all the details on checkpointing, this function is most likely
35410402SN/A    //! to be revisited in future.
35510402SN/A    virtual void unserialize(Checkpoint *cp, const std::string &section,
35610402SN/A                     EventQueue *eventq);
35710402SN/A#endif
35810402SN/A};
35910402SN/A
36010402SN/A#ifndef SWIG
36110402SN/Ainline bool
36210402SN/Aoperator<(const Event &l, const Event &r)
36310402SN/A{
36410402SN/A    return l.when() < r.when() ||
36510402SN/A        (l.when() == r.when() && l.priority() < r.priority());
36610402SN/A}
36710888Sandreas.hansson@arm.com
36810888Sandreas.hansson@arm.cominline bool
3698948SN/Aoperator>(const Event &l, const Event &r)
37010405Sandreas.hansson@arm.com{
3714475SN/A    return l.when() > r.when() ||
3729032SN/A        (l.when() == r.when() && l.priority() > r.priority());
3734475SN/A}
37410405Sandreas.hansson@arm.com
3758948SN/Ainline bool
3769032SN/Aoperator<=(const Event &l, const Event &r)
3778948SN/A{
3788948SN/A    return l.when() < r.when() ||
3798948SN/A        (l.when() == r.when() && l.priority() <= r.priority());
3808948SN/A}
3818948SN/Ainline bool
3828948SN/Aoperator>=(const Event &l, const Event &r)
3838948SN/A{
3848948SN/A    return l.when() > r.when() ||
3858948SN/A        (l.when() == r.when() && l.priority() >= r.priority());
3869031SN/A}
3878948SN/A
38810405Sandreas.hansson@arm.cominline bool
38910401SN/Aoperator==(const Event &l, const Event &r)
3909712SN/A{
3912381SN/A    return l.when() == r.when() && l.priority() == r.priority();
3922381SN/A}
3939036SN/A
3942568SN/Ainline bool
39510405Sandreas.hansson@arm.comoperator!=(const Event &l, const Event &r)
3969092SN/A{
39710405Sandreas.hansson@arm.com    return l.when() != r.when() || l.priority() != r.priority();
3989715SN/A}
3999712SN/A#endif
4002381SN/A
4012381SN/A/**
40210405Sandreas.hansson@arm.com * Queue of events sorted in time order
403 *
404 * Events are scheduled (inserted into the event queue) using the
405 * schedule() method. This method either inserts a <i>synchronous</i>
406 * or <i>asynchronous</i> event.
407 *
408 * Synchronous events are scheduled using schedule() method with the
409 * argument 'global' set to false (default). This should only be done
410 * from a thread holding the event queue lock
411 * (EventQueue::service_mutex). The lock is always held when an event
412 * handler is called, it can therefore always insert events into its
413 * own event queue unless it voluntarily releases the lock.
414 *
415 * Events can be scheduled across thread (and event queue borders) by
416 * either scheduling asynchronous events or taking the target event
417 * queue's lock. However, the lock should <i>never</i> be taken
418 * directly since this is likely to cause deadlocks. Instead, code
419 * that needs to schedule events in other event queues should
420 * temporarily release its own queue and lock the new queue. This
421 * prevents deadlocks since a single thread never owns more than one
422 * event queue lock. This functionality is provided by the
423 * ScopedMigration helper class. Note that temporarily migrating
424 * between event queues can make the simulation non-deterministic, it
425 * should therefore be limited to cases where that can be tolerated
426 * (e.g., handling asynchronous IO or fast-forwarding in KVM).
427 *
428 * Asynchronous events can also be scheduled using the normal
429 * schedule() method with the 'global' parameter set to true. Unlike
430 * the previous queue migration strategy, this strategy is fully
431 * deterministic. This causes the event to be inserted in a separate
432 * queue of asynchronous events (async_queue), which is merged main
433 * event queue at the end of each simulation quantum (by calling the
434 * handleAsyncInsertions() method). Note that this implies that such
435 * events must happen at least one simulation quantum into the future,
436 * otherwise they risk being scheduled in the past by
437 * handleAsyncInsertions().
438 */
439class EventQueue : public Serializable
440{
441  private:
442    std::string objName;
443    Event *head;
444    Tick _curTick;
445
446    //! Mutex to protect async queue.
447    std::mutex *async_queue_mutex;
448
449    //! List of events added by other threads to this event queue.
450    std::list<Event*> async_queue;
451
452    /**
453     * Lock protecting event handling.
454     *
455     * This lock is always taken when servicing events. It is assumed
456     * that the thread scheduling new events (not asynchronous events
457     * though) have taken this lock. This is normally done by
458     * serviceOne() since new events are typically scheduled as a
459     * response to an earlier event.
460     *
461     * This lock is intended to be used to temporarily steal an event
462     * queue to support inter-thread communication when some
463     * deterministic timing can be sacrificed for speed. For example,
464     * the KVM CPU can use this support to access devices running in a
465     * different thread.
466     *
467     * @see EventQueue::ScopedMigration.
468     * @see EventQueue::ScopedRelease
469     * @see EventQueue::lock()
470     * @see EventQueue::unlock()
471     */
472    std::mutex service_mutex;
473
474    //! Insert / remove event from the queue. Should only be called
475    //! by thread operating this queue.
476    void insert(Event *event);
477    void remove(Event *event);
478
479    //! Function for adding events to the async queue. The added events
480    //! are added to main event queue later. Threads, other than the
481    //! owning thread, should call this function instead of insert().
482    void asyncInsert(Event *event);
483
484    EventQueue(const EventQueue &);
485
486  public:
487#ifndef SWIG
488    /**
489     * Temporarily migrate execution to a different event queue.
490     *
491     * An instance of this class temporarily migrates execution to a
492     * different event queue by releasing the current queue, locking
493     * the new queue, and updating curEventQueue(). This can, for
494     * example, be useful when performing IO across thread event
495     * queues when timing is not crucial (e.g., during fast
496     * forwarding).
497     */
498    class ScopedMigration
499    {
500      public:
501        ScopedMigration(EventQueue *_new_eq)
502            :  new_eq(*_new_eq), old_eq(*curEventQueue())
503        {
504            old_eq.unlock();
505            new_eq.lock();
506            curEventQueue(&new_eq);
507        }
508
509        ~ScopedMigration()
510        {
511            new_eq.unlock();
512            old_eq.lock();
513            curEventQueue(&old_eq);
514        }
515
516      private:
517        EventQueue &new_eq;
518        EventQueue &old_eq;
519    };
520
521    /**
522     * Temporarily release the event queue service lock.
523     *
524     * There are cases where it is desirable to temporarily release
525     * the event queue lock to prevent deadlocks. For example, when
526     * waiting on the global barrier, we need to release the lock to
527     * prevent deadlocks from happening when another thread tries to
528     * temporarily take over the event queue waiting on the barrier.
529     */
530    class ScopedRelease
531    {
532      public:
533        ScopedRelease(EventQueue *_eq)
534            :  eq(*_eq)
535        {
536            eq.unlock();
537        }
538
539        ~ScopedRelease()
540        {
541            eq.lock();
542        }
543
544      private:
545        EventQueue &eq;
546    };
547#endif
548
549    EventQueue(const std::string &n);
550
551    virtual const std::string name() const { return objName; }
552    void name(const std::string &st) { objName = st; }
553
554    //! Schedule the given event on this queue. Safe to call from any
555    //! thread.
556    void schedule(Event *event, Tick when, bool global = false);
557
558    //! Deschedule the specified event. Should be called only from the
559    //! owning thread.
560    void deschedule(Event *event);
561
562    //! Reschedule the specified event. Should be called only from
563    //! the owning thread.
564    void reschedule(Event *event, Tick when, bool always = false);
565
566    Tick nextTick() const { return head->when(); }
567    void setCurTick(Tick newVal) { _curTick = newVal; }
568    Tick getCurTick() { return _curTick; }
569
570    Event *serviceOne();
571
572    // process all events up to the given timestamp.  we inline a
573    // quick test to see if there are any events to process; if so,
574    // call the internal out-of-line version to process them all.
575    void
576    serviceEvents(Tick when)
577    {
578        while (!empty()) {
579            if (nextTick() > when)
580                break;
581
582            /**
583             * @todo this assert is a good bug catcher.  I need to
584             * make it true again.
585             */
586            //assert(head->when() >= when && "event scheduled in the past");
587            serviceOne();
588        }
589
590        setCurTick(when);
591    }
592
593    // return true if no events are queued
594    bool empty() const { return head == NULL; }
595
596    void dump() const;
597
598    bool debugVerify() const;
599
600    //! Function for moving events from the async_queue to the main queue.
601    void handleAsyncInsertions();
602
603    /**
604     *  function for replacing the head of the event queue, so that a
605     *  different set of events can run without disturbing events that have
606     *  already been scheduled. Already scheduled events can be processed
607     *  by replacing the original head back.
608     *  USING THIS FUNCTION CAN BE DANGEROUS TO THE HEALTH OF THE SIMULATOR.
609     *  NOT RECOMMENDED FOR USE.
610     */
611    Event* replaceHead(Event* s);
612
613    /**@{*/
614    /**
615     * Provide an interface for locking/unlocking the event queue.
616     *
617     * @warn Do NOT use these methods directly unless you really know
618     * what you are doing. Incorrect use can easily lead to simulator
619     * deadlocks.
620     *
621     * @see EventQueue::ScopedMigration.
622     * @see EventQueue::ScopedRelease
623     * @see EventQueue
624     */
625    void lock() { service_mutex.lock(); }
626    void unlock() { service_mutex.unlock(); }
627    /**@}*/
628
629#ifndef SWIG
630    virtual void serialize(std::ostream &os);
631    virtual void unserialize(Checkpoint *cp, const std::string &section);
632#endif
633};
634
635void dumpMainQueue();
636
637#ifndef SWIG
638class EventManager
639{
640  protected:
641    /** A pointer to this object's event queue */
642    EventQueue *eventq;
643
644  public:
645    EventManager(EventManager &em) : eventq(em.eventq) {}
646    EventManager(EventManager *em) : eventq(em->eventq) {}
647    EventManager(EventQueue *eq) : eventq(eq) {}
648
649    EventQueue *
650    eventQueue() const
651    {
652        return eventq;
653    }
654
655    void
656    schedule(Event &event, Tick when)
657    {
658        eventq->schedule(&event, when);
659    }
660
661    void
662    deschedule(Event &event)
663    {
664        eventq->deschedule(&event);
665    }
666
667    void
668    reschedule(Event &event, Tick when, bool always = false)
669    {
670        eventq->reschedule(&event, when, always);
671    }
672
673    void
674    schedule(Event *event, Tick when)
675    {
676        eventq->schedule(event, when);
677    }
678
679    void
680    deschedule(Event *event)
681    {
682        eventq->deschedule(event);
683    }
684
685    void
686    reschedule(Event *event, Tick when, bool always = false)
687    {
688        eventq->reschedule(event, when, always);
689    }
690
691    void setCurTick(Tick newVal) { eventq->setCurTick(newVal); }
692};
693
694template <class T, void (T::* F)()>
695void
696DelayFunction(EventQueue *eventq, Tick when, T *object)
697{
698    class DelayEvent : public Event
699    {
700      private:
701        T *object;
702
703      public:
704        DelayEvent(T *o)
705            : Event(Default_Pri, AutoDelete), object(o)
706        { }
707        void process() { (object->*F)(); }
708        const char *description() const { return "delay"; }
709    };
710
711    eventq->schedule(new DelayEvent(object), when);
712}
713
714template <class T, void (T::* F)()>
715class EventWrapper : public Event
716{
717  private:
718    T *object;
719
720  public:
721    EventWrapper(T *obj, bool del = false, Priority p = Default_Pri)
722        : Event(p), object(obj)
723    {
724        if (del)
725            setFlags(AutoDelete);
726    }
727
728    EventWrapper(T &obj, bool del = false, Priority p = Default_Pri)
729        : Event(p), object(&obj)
730    {
731        if (del)
732            setFlags(AutoDelete);
733    }
734
735    void process() { (object->*F)(); }
736
737    const std::string
738    name() const
739    {
740        return object->name() + ".wrapped_event";
741    }
742
743    const char *description() const { return "EventWrapped"; }
744};
745#endif
746
747#endif // __SIM_EVENTQ_HH__
748