eventq.hh (9983:2cce74fe359e) | eventq.hh (10153:936a3a8006f6) |
---|---|
1/* 2 * Copyright (c) 2000-2005 The Regents of The University of Michigan 3 * Copyright (c) 2013 Advanced Micro Devices, Inc. 4 * Copyright (c) 2013 Mark D. Hill and David A. Wood 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions are --- 384 unchanged lines hidden (view full) --- 393 394inline bool 395operator!=(const Event &l, const Event &r) 396{ 397 return l.when() != r.when() || l.priority() != r.priority(); 398} 399#endif 400 | 1/* 2 * Copyright (c) 2000-2005 The Regents of The University of Michigan 3 * Copyright (c) 2013 Advanced Micro Devices, Inc. 4 * Copyright (c) 2013 Mark D. Hill and David A. Wood 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions are --- 384 unchanged lines hidden (view full) --- 393 394inline bool 395operator!=(const Event &l, const Event &r) 396{ 397 return l.when() != r.when() || l.priority() != r.priority(); 398} 399#endif 400 |
401/* | 401/** |
402 * Queue of events sorted in time order | 402 * 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(). |
|
403 */ 404class EventQueue : public Serializable 405{ 406 private: 407 std::string objName; 408 Event *head; 409 Tick _curTick; 410 411 //! Mutex to protect async queue. 412 std::mutex *async_queue_mutex; 413 414 //! List of events added by other threads to this event queue. 415 std::list<Event*> async_queue; 416 | 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 |
|
417 //! Insert / remove event from the queue. Should only be called 418 //! by thread operating this queue. 419 void insert(Event *event); 420 void remove(Event *event); 421 422 //! Function for adding events to the async queue. The added events 423 //! are added to main event queue later. Threads, other than the 424 //! owning thread, should call this function instead of insert(). 425 void asyncInsert(Event *event); 426 427 EventQueue(const EventQueue &); 428 429 public: | 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 |
|
430 EventQueue(const std::string &n); 431 432 virtual const std::string name() const { return objName; } 433 void name(const std::string &st) { objName = st; } 434 435 //! Schedule the given event on this queue. Safe to call from any 436 //! thread. 437 void schedule(Event *event, Tick when, bool global = false); --- 48 unchanged lines hidden (view full) --- 486 * different set of events can run without disturbing events that have 487 * already been scheduled. Already scheduled events can be processed 488 * by replacing the original head back. 489 * USING THIS FUNCTION CAN BE DANGEROUS TO THE HEALTH OF THE SIMULATOR. 490 * NOT RECOMMENDED FOR USE. 491 */ 492 Event* replaceHead(Event* s); 493 | 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); --- 48 unchanged lines hidden (view full) --- 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 |
|
494#ifndef SWIG 495 virtual void serialize(std::ostream &os); 496 virtual void unserialize(Checkpoint *cp, const std::string §ion); 497#endif 498}; 499 500void dumpMainQueue(); 501 --- 111 unchanged lines hidden --- | 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 --- 111 unchanged lines hidden --- |