Added timer/timeout-event support (+ event handler for addition, deletion and triggering).
git-svn-id: https://www4.informatik.uni-erlangen.de/i4svn/danceos/trunk/devel/fail@1244 8c4709b5-6ec9-48aa-a5cd-a96041d1645a
This commit is contained in:
@ -1,8 +1,5 @@
|
||||
|
||||
// Author: Adrian Böckenkamp
|
||||
// Date: 08.06.2011
|
||||
|
||||
#include "Event.hpp"
|
||||
#include "../SAL/SALInst.hpp"
|
||||
|
||||
namespace fi
|
||||
{
|
||||
|
||||
@ -440,7 +440,7 @@ class GuestEvent : virtual public BaseEvent
|
||||
|
||||
/**
|
||||
* \class JumpEvent
|
||||
* JumpEvents are used to observe condition jumps (if...else if...else).
|
||||
* JumpEvents are used to observe conditional jumps (if...else if...else).
|
||||
*/
|
||||
class JumpEvent : virtual public BaseEvent
|
||||
{
|
||||
@ -481,6 +481,50 @@ class JumpEvent : virtual public BaseEvent
|
||||
{ m_FlagTriggered = flagTriggered; }
|
||||
};
|
||||
|
||||
/**
|
||||
* \class TimerEvent
|
||||
* This event type is used to create timeouts/timers within in an experiment.
|
||||
*/
|
||||
class TimerEvent : public BaseEvent
|
||||
{
|
||||
private:
|
||||
unsigned m_Timeout; //!< timeout interval in milliseconds
|
||||
sal::timer_id_t m_Id; //!< internal timer id (sim-specific)
|
||||
bool m_Once; //!< true, if the timer should be triggered only once
|
||||
public:
|
||||
/**
|
||||
* Creates a new timer event. This can be used to implement a timeout-
|
||||
* mechanism in the experiment-flow. The timer starts automatically when
|
||||
* added to the simulator backend (@see SimulatorController::addEvent)
|
||||
* @param timeout the time intervall in milliseconds (ms)
|
||||
* @param once \c true, if the TimerEvent should be triggered once,
|
||||
* \c false if it should occur regularly
|
||||
*/
|
||||
TimerEvent(unsigned timeout, bool once)
|
||||
: m_Timeout(timeout), m_Id(-1), m_Once(once) { }
|
||||
~TimerEvent() { }
|
||||
/**
|
||||
* Retrieves the internal timer id. Maybe useful for debug output.
|
||||
* @return the timer id
|
||||
*/
|
||||
sal::timer_id_t getId() const { return m_Id; }
|
||||
/**
|
||||
* Sets the internal timer id. This should not be used by the experiment.
|
||||
* @param id the new timer id, given by the underlying simulator-backend
|
||||
*/
|
||||
void setId(sal::timer_id_t id) { m_Id = id; }
|
||||
/**
|
||||
* Retrieves the timer's timeout value.
|
||||
* @return the timout in milliseconds
|
||||
*/
|
||||
unsigned getTimeout() const { return m_Timeout; }
|
||||
/**
|
||||
* Checks whether the timer occurs once or repetitive.
|
||||
* @return \c true if timer triggers once, \c false if repetitive
|
||||
*/
|
||||
bool getOnceFlag() const { return m_Once; }
|
||||
};
|
||||
|
||||
} // end-of-namespace: fi
|
||||
|
||||
#endif /* __EVENT_HPP__ */
|
||||
|
||||
@ -23,6 +23,10 @@ void EventList::remove(BaseEvent* ev)
|
||||
// * clear m_BufferList
|
||||
// * copy m_FireList to m_DeleteList
|
||||
if (ev == 0) {
|
||||
for (bufferlist_t::iterator it = m_BufferList.begin(); it != m_BufferList.end(); it++)
|
||||
sal::simulator.onEventDeletion(*it);
|
||||
for (firelist_t::iterator it = m_FireList.begin(); it != m_FireList.end(); it++)
|
||||
sal::simulator.onEventDeletion(*it);
|
||||
m_BufferList.clear();
|
||||
// all remaining active events must not fire anymore
|
||||
m_DeleteList.insert(m_DeleteList.end(), m_FireList.begin(), m_FireList.end());
|
||||
@ -31,6 +35,7 @@ void EventList::remove(BaseEvent* ev)
|
||||
// * find/remove ev in m_BufferList
|
||||
// * if ev in m_FireList, copy to m_DeleteList
|
||||
} else {
|
||||
sal::simulator.onEventDeletion(ev);
|
||||
m_BufferList.remove(ev);
|
||||
firelist_t::const_iterator it =
|
||||
std::find(m_FireList.begin(), m_FireList.end(), ev);
|
||||
@ -47,20 +52,40 @@ EventList::iterator EventList::remove(iterator it)
|
||||
|
||||
EventList::iterator EventList::m_remove(iterator it, bool skip_deletelist)
|
||||
{
|
||||
if(!skip_deletelist)
|
||||
if (!skip_deletelist) {
|
||||
// If skip_deletelist = true, m_remove was called from makeActive. Accordingly, we
|
||||
// are not going to delete an event, instead we are "moving" an event object (= *it)
|
||||
// from the buffer list to the fire-list. Therefor we only need to call the simulator's
|
||||
// event handler (m_onEventDeletion), if m_remove is called with the primary intention
|
||||
// to *delete* (not "move") an event.
|
||||
sal::simulator.onEventDeletion(*it);
|
||||
m_DeleteList.push_back(*it);
|
||||
}
|
||||
return (m_BufferList.erase(it));
|
||||
}
|
||||
|
||||
void EventList::remove(ExperimentFlow* flow)
|
||||
{
|
||||
// WARNING: (*it) (= all elements in the lists) can be an invalid ptr because
|
||||
// clearEvents will be called automatically when the allocating experiment (i.e.
|
||||
// run()) has already ended. Accordingly, we cannot call
|
||||
// sal::simulator.onEventDeletion(*it)
|
||||
// because a dynamic-cast of *it would cause a SEGFAULT. Therefor we require the
|
||||
// experiment flow to remove all residual events by calling clearEvents() (with-
|
||||
// in run()). As a consequence, we are now allowed to call the event-handler here.
|
||||
// See ExperimentFlow.hpp for more details.
|
||||
|
||||
// all events?
|
||||
if (flow == 0) {
|
||||
for (bufferlist_t::iterator it = m_BufferList.begin();
|
||||
it != m_BufferList.end(); it++)
|
||||
sal::simulator.onEventDeletion(*it); // invoke event handler
|
||||
m_BufferList.clear();
|
||||
} else {
|
||||
} else { // remove all events corresponding to a specific experiment ("flow"):
|
||||
for (bufferlist_t::iterator it = m_BufferList.begin();
|
||||
it != m_BufferList.end(); ) {
|
||||
if ((*it)->getParent() == flow) {
|
||||
sal::simulator.onEventDeletion(*it);
|
||||
it = m_BufferList.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
@ -72,11 +97,12 @@ void EventList::remove(ExperimentFlow* flow)
|
||||
it != m_FireList.end(); it++) {
|
||||
if (std::find(m_DeleteList.begin(), m_DeleteList.end(), *it)
|
||||
!= m_DeleteList.end()) {
|
||||
continue;
|
||||
continue; // (already in the delete-list? -> skip!)
|
||||
}
|
||||
// ... need to be pushed into m_DeleteList, as we're currently
|
||||
// iterating over m_FireList in fireActiveEvents() and cannot modify it
|
||||
if (flow == 0 || (*it)->getParent() == flow) {
|
||||
sal::simulator.onEventDeletion(*it);
|
||||
m_DeleteList.push_back(*it);
|
||||
}
|
||||
}
|
||||
@ -117,13 +143,14 @@ EventList::iterator EventList::makeActive(iterator it)
|
||||
|
||||
void EventList::fireActiveEvents()
|
||||
{
|
||||
for(firelist_t::iterator it = m_FireList.begin();
|
||||
it != m_FireList.end(); it++)
|
||||
{
|
||||
if(std::find(m_DeleteList.begin(), m_DeleteList.end(), *it)
|
||||
== m_DeleteList.end()) // not found in delete-list?
|
||||
{
|
||||
for (firelist_t::iterator it = m_FireList.begin();
|
||||
it != m_FireList.end(); it++) {
|
||||
if (std::find(m_DeleteList.begin(), m_DeleteList.end(), *it)
|
||||
== m_DeleteList.end()) { // not found in delete-list?
|
||||
m_pFired = *it;
|
||||
// Inform (call) the simulator's (internal) event handler that we are about
|
||||
// to trigger an event (*before* we actually toggle the experiment flow):
|
||||
sal::simulator.onEventTrigger(m_pFired);
|
||||
ExperimentFlow* pFlow = m_pFired->getParent();
|
||||
assert(pFlow && "FATAL ERROR: The event has no parent experiment (owner)!");
|
||||
sal::simulator.m_Flows.toggle(pFlow);
|
||||
@ -131,6 +158,7 @@ void EventList::fireActiveEvents()
|
||||
}
|
||||
m_FireList.clear();
|
||||
m_DeleteList.clear();
|
||||
// Note: Do NOT call any event handlers here!
|
||||
}
|
||||
|
||||
size_t EventList::getContextCount() const
|
||||
|
||||
@ -1,9 +1,6 @@
|
||||
#ifndef __EVENT_LIST_HPP__
|
||||
#define __EVENT_LIST_HPP__
|
||||
|
||||
// Author: Adrian Böckenkamp
|
||||
// Date: 04.02.2012
|
||||
|
||||
#include <cassert>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
@ -140,10 +137,11 @@ class EventList
|
||||
*/
|
||||
size_t getContextCount() const;
|
||||
/**
|
||||
* Retrieves the total number of events.
|
||||
* Retrieves the total number of buffered events. This doesn't include
|
||||
* the events in the fire- or delete-list.
|
||||
* @return the total event count (for all flows)
|
||||
*/
|
||||
size_t getEventCount() const { return (m_BufferList.size()); }
|
||||
size_t getEventCount() const { return m_BufferList.size(); }
|
||||
/**
|
||||
* Retrieves the recently triggered event object. To map this object to
|
||||
* it's context (id est, the related ExerimentFlow), use
|
||||
@ -168,7 +166,8 @@ class EventList
|
||||
* @return returns the updated iteration, pointing to the next element
|
||||
* after makeActive returns, "it" is invalid, so the returned
|
||||
* iterator should be used to continue the iteration
|
||||
* TODO: besserer Name statt "makeActive"?
|
||||
*
|
||||
* TODO: Improve naming (instead of "makeActive")?
|
||||
*/
|
||||
iterator makeActive(iterator it);
|
||||
/**
|
||||
@ -177,7 +176,8 @@ class EventList
|
||||
* makeActive() for more details. The recently triggered event can be
|
||||
* retrieved by calling \a getLastFired(). After all events have been
|
||||
* triggered, the (internal) fire- and delete-list will be cleared.
|
||||
* TODO: besserer Name statt "fireActiveEvents"?
|
||||
*
|
||||
* TODO: Improve naming (instead of "fireActiveEvents")?
|
||||
*/
|
||||
void fireActiveEvents();
|
||||
};
|
||||
|
||||
@ -1,9 +1,6 @@
|
||||
#ifndef __EXPERIMENT_FLOW_HPP__
|
||||
#define __EXPERIMENT_FLOW_HPP__
|
||||
|
||||
// Author: Adrian Böckenkamp
|
||||
// Date: 09.09.2011
|
||||
|
||||
#include "../SAL/SALInst.hpp"
|
||||
|
||||
namespace fi
|
||||
@ -11,9 +8,8 @@ namespace fi
|
||||
|
||||
/**
|
||||
* \class ExperimentFlow
|
||||
* Basic interface for user-defined experiments. To create a new
|
||||
* experiment, derive your own class from ExperimentFlow and
|
||||
* define the run method.
|
||||
* Basic interface for user-defined experiments. To create a new experiment,
|
||||
* derive your own class from ExperimentFlow and define the run method.
|
||||
*/
|
||||
class ExperimentFlow
|
||||
{
|
||||
@ -33,6 +29,9 @@ class ExperimentFlow
|
||||
{
|
||||
run();
|
||||
sal::simulator.clearEvents(this); // remove residual events
|
||||
// FIXME: Consider removing this call (see EventList.cc, void remove(ExperimentFlow* flow))
|
||||
// a) with the advantage that we will potentially prevent serious segfaults but
|
||||
// b) with the drawback that we cannot enforce any cleanups.
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user