arch-arm: Do not check MustBeOne flag for TLB requests from the prefetcher
[gem5.git] / src / sim / eventq.hh
index c390d2155c8bd70e6823b17d6bdd85b49b63c26d..895f69424af2c31c0178799a05d10daf645fee93 100644 (file)
 #include <algorithm>
 #include <cassert>
 #include <climits>
+#include <functional>
 #include <iosfwd>
 #include <memory>
 #include <mutex>
 #include <string>
 
 #include "base/flags.hh"
-#include "base/misc.hh"
 #include "base/types.hh"
 #include "debug/Event.hh"
 #include "sim/serialize.hh"
@@ -68,14 +68,11 @@ extern uint32_t numMainEventQueues;
 //! Array for main event queues.
 extern std::vector<EventQueue *> mainEventQueue;
 
-#ifndef SWIG
 //! The current event queue for the running thread. Access to this queue
 //! does not require any locking from the thread.
 
 extern __thread EventQueue *_curEventQueue;
 
-#endif
-
 //! Current mode of execution: parallel / serial
 extern bool inParallelMode;
 
@@ -95,7 +92,7 @@ inline void curEventQueue(EventQueue *q) { _curEventQueue = q; }
  */
 class EventBase
 {
-  protected:   
+  protected:
     typedef unsigned short FlagsType;
     typedef ::Flags<FlagsType> Flags;
 
@@ -103,8 +100,14 @@ class EventBase
     static const FlagsType PublicWrite   = 0x001d; // public writable flags
     static const FlagsType Squashed      = 0x0001; // has been squashed
     static const FlagsType Scheduled     = 0x0002; // has been scheduled
-    static const FlagsType AutoDelete    = 0x0004; // delete after dispatch
-    static const FlagsType AutoSerialize = 0x0008; // must be serialized
+    static const FlagsType Managed       = 0x0004; // Use life cycle manager
+    static const FlagsType AutoDelete    = Managed; // delete after dispatch
+    /**
+     * This used to be AutoSerialize. This value can't be reused
+     * without changing the checkpoint version since the flag field
+     * gets serialized.
+     */
+    static const FlagsType Reserved0     = 0x0008;
     static const FlagsType IsExitEvent   = 0x0010; // special exit event
     static const FlagsType IsMainQueue   = 0x0020; // on main event queue
     static const FlagsType Initialized   = 0x7a40; // somewhat random bits
@@ -158,6 +161,9 @@ class EventBase
     /// (such as writebacks).
     static const Priority CPU_Tick_Pri =                50;
 
+    /// If we want to exit a thread in a CPU, it comes after CPU_Tick_Pri
+    static const Priority CPU_Exit_Pri =                64;
+
     /// Statistics events (dump, reset, etc.) come after
     /// everything else, but before exit.
     static const Priority Stat_Event_Pri =              90;
@@ -239,7 +245,7 @@ class Event : public EventBase, public Serializable
     bool
     initialized() const
     {
-        return this && (flags & InitMask) == Initialized;
+        return (flags & InitMask) == Initialized;
     }
 
   protected:
@@ -281,6 +287,55 @@ class Event : public EventBase, public Serializable
     // This function isn't really useful if TRACING_ON is not defined
     virtual void trace(const char *action);     //!< trace event activity
 
+  protected: /* Memory management */
+    /**
+     * @{
+     * Memory management hooks for events that have the Managed flag set
+     *
+     * Events can use automatic memory management by setting the
+     * Managed flag. The default implementation automatically deletes
+     * events once they have been removed from the event queue. This
+     * typically happens when events are descheduled or have been
+     * triggered and not rescheduled.
+     *
+     * The methods below may be overridden by events that need custom
+     * memory management. For example, events exported to Python need
+     * to impement reference counting to ensure that the Python
+     * implementation of the event is kept alive while it lives in the
+     * event queue.
+     *
+     * @note Memory managers are responsible for implementing
+     * reference counting (by overriding both acquireImpl() and
+     * releaseImpl()) or checking if an event is no longer scheduled
+     * in releaseImpl() before deallocating it.
+     */
+
+    /**
+     * Managed event scheduled and being held in the event queue.
+     */
+    void acquire()
+    {
+        if (flags.isSet(Event::Managed))
+            acquireImpl();
+    }
+
+    /**
+     * Managed event removed from the event queue.
+     */
+    void release() {
+        if (flags.isSet(Event::Managed))
+            releaseImpl();
+    }
+
+    virtual void acquireImpl() {}
+
+    virtual void releaseImpl() {
+        if (!scheduled())
+            delete this;
+    }
+
+    /** @} */
+
   public:
 
     /*
@@ -338,6 +393,10 @@ class Event : public EventBase, public Serializable
     /// See if this is a SimExitEvent (without resorting to RTTI)
     bool isExitEvent() const { return flags.isSet(IsExitEvent); }
 
+    /// Check whether this event will auto-delete
+    bool isManaged() const { return flags.isSet(Managed); }
+    bool isAutoDelete() const { return isManaged(); }
+
     /// Get the time that the event is scheduled
     Tick when() const { return _when; }
 
@@ -349,20 +408,10 @@ class Event : public EventBase, public Serializable
     //! NULL.  (Overridden in GlobalEvent::BarrierEvent.)
     virtual BaseGlobalEvent *globalEvent() { return NULL; }
 
-#ifndef SWIG
-    virtual void serialize(std::ostream &os);
-    virtual void unserialize(Checkpoint *cp, const std::string &section);
-
-    //! This function is required to support restoring from checkpoints
-    //! when running with multiple queues. Since we still have not thrashed
-    //! out all the details on checkpointing, this function is most likely
-    //! to be revisited in future.
-    virtual void unserialize(Checkpoint *cp, const std::string &section,
-                     EventQueue *eventq);
-#endif
+    void serialize(CheckpointOut &cp) const override;
+    void unserialize(CheckpointIn &cp) override;
 };
 
-#ifndef SWIG
 inline bool
 operator<(const Event &l, const Event &r)
 {
@@ -401,7 +450,6 @@ operator!=(const Event &l, const Event &r)
 {
     return l.when() != r.when() || l.priority() != r.priority();
 }
-#endif
 
 /**
  * Queue of events sorted in time order
@@ -441,7 +489,7 @@ operator!=(const Event &l, const Event &r)
  * otherwise they risk being scheduled in the past by
  * handleAsyncInsertions().
  */
-class EventQueue : public Serializable
+class EventQueue
 {
   private:
     std::string objName;
@@ -489,7 +537,6 @@ class EventQueue : public Serializable
     EventQueue(const EventQueue &);
 
   public:
-#ifndef SWIG
     /**
      * Temporarily migrate execution to a different event queue.
      *
@@ -499,28 +546,36 @@ class EventQueue : public Serializable
      * example, be useful when performing IO across thread event
      * queues when timing is not crucial (e.g., during fast
      * forwarding).
+     *
+     * ScopedMigration does nothing if both eqs are the same
      */
     class ScopedMigration
     {
       public:
-        ScopedMigration(EventQueue *_new_eq)
-            :  new_eq(*_new_eq), old_eq(*curEventQueue())
+        ScopedMigration(EventQueue *_new_eq, bool _doMigrate = true)
+            :new_eq(*_new_eq), old_eq(*curEventQueue()),
+             doMigrate((&new_eq != &old_eq)&&_doMigrate)
         {
-            old_eq.unlock();
-            new_eq.lock();
-            curEventQueue(&new_eq);
+            if (doMigrate){
+                old_eq.unlock();
+                new_eq.lock();
+                curEventQueue(&new_eq);
+            }
         }
 
         ~ScopedMigration()
         {
-            new_eq.unlock();
-            old_eq.lock();
-            curEventQueue(&old_eq);
+            if (doMigrate){
+                new_eq.unlock();
+                old_eq.lock();
+                curEventQueue(&old_eq);
+            }
         }
 
       private:
         EventQueue &new_eq;
         EventQueue &old_eq;
+        bool doMigrate;
     };
 
     /**
@@ -549,7 +604,6 @@ class EventQueue : public Serializable
       private:
         EventQueue &eq;
     };
-#endif
 
     EventQueue(const std::string &n);
 
@@ -570,7 +624,8 @@ class EventQueue : public Serializable
 
     Tick nextTick() const { return head->when(); }
     void setCurTick(Tick newVal) { _curTick = newVal; }
-    Tick getCurTick() { return _curTick; }
+    Tick getCurTick() const { return _curTick; }
+    Event *getHead() const { return head; }
 
     Event *serviceOne();
 
@@ -605,6 +660,21 @@ class EventQueue : public Serializable
     //! Function for moving events from the async_queue to the main queue.
     void handleAsyncInsertions();
 
+    /**
+     *  Function to signal that the event loop should be woken up because
+     *  an event has been scheduled by an agent outside the gem5 event
+     *  loop(s) whose event insertion may not have been noticed by gem5.
+     *  This function isn't needed by the usual gem5 event loop but may
+     *  be necessary in derived EventQueues which host gem5 onto other
+     *  schedulers.
+     *
+     *  @param when Time of a delayed wakeup (if known). This parameter
+     *  can be used by an implementation to schedule a wakeup in the
+     *  future if it is sure it will remain active until then.
+     *  Or it can be ignored and the event queue can be woken up now.
+     */
+    virtual void wakeup(Tick when = (Tick)-1) { }
+
     /**
      *  function for replacing the head of the event queue, so that a
      *  different set of events can run without disturbing events that have
@@ -631,15 +701,28 @@ class EventQueue : public Serializable
     void unlock() { service_mutex.unlock(); }
     /**@}*/
 
-#ifndef SWIG
-    virtual void serialize(std::ostream &os);
-    virtual void unserialize(Checkpoint *cp, const std::string &section);
-#endif
+    /**
+     * Reschedule an event after a checkpoint.
+     *
+     * Since events don't know which event queue they belong to,
+     * parent objects need to reschedule events themselves. This
+     * method conditionally schedules an event that has the Scheduled
+     * flag set. It should be called by parent objects after
+     * unserializing an object.
+     *
+     * @warn Only use this method after unserializing an Event.
+     */
+    void checkpointReschedule(Event *event);
+
+    virtual ~EventQueue()
+    {
+        while (!empty())
+            deschedule(getHead());
+    }
 };
 
 void dumpMainQueue();
 
-#ifndef SWIG
 class EventManager
 {
   protected:
@@ -693,28 +776,13 @@ class EventManager
         eventq->reschedule(event, when, always);
     }
 
-    void setCurTick(Tick newVal) { eventq->setCurTick(newVal); }
-};
-
-template <class T, void (T::* F)()>
-void
-DelayFunction(EventQueue *eventq, Tick when, T *object)
-{
-    class DelayEvent : public Event
+    void wakeupEventQueue(Tick when = (Tick)-1)
     {
-      private:
-        T *object;
-
-      public:
-        DelayEvent(T *o)
-            : Event(Default_Pri, AutoDelete), object(o)
-        { }
-        void process() { (object->*F)(); }
-        const char *description() const { return "delay"; }
-    };
+        eventq->wakeup(when);
+    }
 
-    eventq->schedule(new DelayEvent(object), when);
-}
+    void setCurTick(Tick newVal) { eventq->setCurTick(newVal); }
+};
 
 template <class T, void (T::* F)()>
 class EventWrapper : public Event
@@ -747,6 +815,33 @@ class EventWrapper : public Event
 
     const char *description() const { return "EventWrapped"; }
 };
-#endif
+
+class EventFunctionWrapper : public Event
+{
+  private:
+      std::function<void(void)> callback;
+      std::string _name;
+
+  public:
+    EventFunctionWrapper(const std::function<void(void)> &callback,
+                         const std::string &name,
+                         bool del = false,
+                         Priority p = Default_Pri)
+        : Event(p), callback(callback), _name(name)
+    {
+        if (del)
+            setFlags(AutoDelete);
+    }
+
+    void process() { callback(); }
+
+    const std::string
+    name() const
+    {
+        return _name + ".wrapped_function_event";
+    }
+
+    const char *description() const { return "EventFunctionWrapped"; }
+};
 
 #endif // __SIM_EVENTQ_HH__