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 &section);
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 &section);
632#endif
633};
634
635void dumpMainQueue();
636

--- 111 unchanged lines hidden ---