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 §ion); 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 §ion, 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 §ion); 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