#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"
//! 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;
*/
class EventBase
{
- protected:
+ protected:
typedef unsigned short FlagsType;
typedef ::Flags<FlagsType> Flags;
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
bool
initialized() const
{
- return this && (flags & InitMask) == Initialized;
+ return (flags & InitMask) == Initialized;
}
protected:
// 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:
/*
/// 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; }
//! 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 §ion);
-
- //! 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 §ion,
- 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)
{
{
return l.when() != r.when() || l.priority() != r.priority();
}
-#endif
/**
* Queue of events sorted in time order
* otherwise they risk being scheduled in the past by
* handleAsyncInsertions().
*/
-class EventQueue : public Serializable
+class EventQueue
{
private:
std::string objName;
Tick _curTick;
//! Mutex to protect async queue.
- std::mutex *async_queue_mutex;
+ std::mutex async_queue_mutex;
//! List of events added by other threads to this event queue.
std::list<Event*> async_queue;
EventQueue(const EventQueue &);
public:
-#ifndef SWIG
/**
* Temporarily migrate execution to a different event queue.
*
* 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;
};
/**
private:
EventQueue &eq;
};
-#endif
EventQueue(const std::string &n);
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();
//! 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
void unlock() { service_mutex.unlock(); }
/**@}*/
-#ifndef SWIG
- virtual void serialize(std::ostream &os);
- virtual void unserialize(Checkpoint *cp, const std::string §ion);
-#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() { }
};
void dumpMainQueue();
-#ifndef SWIG
class EventManager
{
protected:
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
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__