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,7 +1,3 @@
|
|||||||
|
|
||||||
// Author: Adrian Böckenkamp
|
|
||||||
// Date: 23.01.2012
|
|
||||||
|
|
||||||
#include "SimulatorController.hpp"
|
#include "SimulatorController.hpp"
|
||||||
#include "SALInst.hpp"
|
#include "SALInst.hpp"
|
||||||
#include "../controller/Event.hpp"
|
#include "../controller/Event.hpp"
|
||||||
@ -14,7 +10,14 @@ ConcreteSimulatorController simulator;
|
|||||||
|
|
||||||
fi::EventId SimulatorController::addEvent(fi::BaseEvent* ev)
|
fi::EventId SimulatorController::addEvent(fi::BaseEvent* ev)
|
||||||
{
|
{
|
||||||
return (m_EvList.add(ev, m_Flows.getCurrent()));
|
assert(ev != NULL && "FATAL ERROR: ev pointer cannot be NULL!");
|
||||||
|
fi::EventId ret = m_EvList.add(ev, m_Flows.getCurrent());
|
||||||
|
// Call the common postprocessing function:
|
||||||
|
if (!onEventAddition(ev)) { // If the return value signals "false"...,
|
||||||
|
m_EvList.remove(ev); // ...skip the addition
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
fi::BaseEvent* SimulatorController::waitAny(void)
|
fi::BaseEvent* SimulatorController::waitAny(void)
|
||||||
@ -30,9 +33,6 @@ void SimulatorController::startup()
|
|||||||
// Some greetings to the user:
|
// Some greetings to the user:
|
||||||
std::cout << "[SimulatorController] Initializing..." << std::endl;
|
std::cout << "[SimulatorController] Initializing..." << std::endl;
|
||||||
|
|
||||||
// TODO: Retrieve ExperimentData from the job-server (*before* each
|
|
||||||
// experiment-routine gets started)...!
|
|
||||||
|
|
||||||
// Activate previously added experiments to allow initialization:
|
// Activate previously added experiments to allow initialization:
|
||||||
initExperiments();
|
initExperiments();
|
||||||
}
|
}
|
||||||
@ -47,11 +47,11 @@ void SimulatorController::onBreakpointEvent(address_t instrPtr)
|
|||||||
assert(false &&
|
assert(false &&
|
||||||
"FIXME: SimulatorController::onBreakpointEvent() has not been tested before");
|
"FIXME: SimulatorController::onBreakpointEvent() has not been tested before");
|
||||||
|
|
||||||
// FIXME: Performanz verbessern
|
// FIXME: Improve performance
|
||||||
|
|
||||||
// Loop through all events of type BP*Event:
|
// Loop through all events of type BP*Event:
|
||||||
fi::EventList::iterator it = m_EvList.begin();
|
fi::EventList::iterator it = m_EvList.begin();
|
||||||
while(it != m_EvList.end())
|
while (it != m_EvList.end())
|
||||||
{
|
{
|
||||||
fi::BaseEvent* pev = *it;
|
fi::BaseEvent* pev = *it;
|
||||||
fi::BPEvent* pbp; fi::BPRangeEvent* pbpr;
|
fi::BPEvent* pbp; fi::BPRangeEvent* pbpr;
|
||||||
@ -78,8 +78,7 @@ void SimulatorController::onBreakpointEvent(address_t instrPtr)
|
|||||||
void SimulatorController::onMemoryAccessEvent(address_t addr, size_t len,
|
void SimulatorController::onMemoryAccessEvent(address_t addr, size_t len,
|
||||||
bool is_write, address_t instrPtr)
|
bool is_write, address_t instrPtr)
|
||||||
{
|
{
|
||||||
// FIXME: Performanz verbessern (falls Iteratorlogik bleibt, wäre
|
// FIXME: Improve performance
|
||||||
// ein "hasMoreOf(typeid(MemEvents))" denkbar...
|
|
||||||
|
|
||||||
fi::MemAccessEvent::accessType_t accesstype =
|
fi::MemAccessEvent::accessType_t accesstype =
|
||||||
is_write ? fi::MemAccessEvent::MEM_WRITE
|
is_write ? fi::MemAccessEvent::MEM_WRITE
|
||||||
|
|||||||
@ -119,8 +119,35 @@ class SimulatorController
|
|||||||
* @param opcode the opcode of the conrecete jump instruction
|
* @param opcode the opcode of the conrecete jump instruction
|
||||||
*/
|
*/
|
||||||
void onJumpEvent(bool flagTriggered, unsigned opcode);
|
void onJumpEvent(bool flagTriggered, unsigned opcode);
|
||||||
|
/**
|
||||||
|
* This method is called when an experiment flow adds a new event by
|
||||||
|
* calling \c simulator.addEvent(pev) or \c simulator.addEventAndWait(pev).
|
||||||
|
* More specifically, the event will be added to the event-list first
|
||||||
|
* (buffer-list, to be precise) and then this event handler is called.
|
||||||
|
* @param pev the event which has been added
|
||||||
|
* @return You should return \c true to continue and \c false to prevent
|
||||||
|
* the addition of the event \a pev, yielding an error in the
|
||||||
|
* experiment flow (i.e. -1 is returned).
|
||||||
|
*/
|
||||||
|
virtual bool onEventAddition(fi::BaseEvent* pev) { return true; }
|
||||||
|
/**
|
||||||
|
* This method is called when an experiment flow removes an event from
|
||||||
|
* the event-management by calling \c removeEvent(prev), \c clearEvents()
|
||||||
|
* or by deleting a complete flow (\c removeFlow). More specifically, this
|
||||||
|
* event handler will be called *before* the event is actually deleted.
|
||||||
|
* @param pev the event to be deleted when returning from the event handler
|
||||||
|
*/
|
||||||
|
virtual void onEventDeletion(fi::BaseEvent* pev) { }
|
||||||
|
/**
|
||||||
|
* This method is called when an previously added event is about to be
|
||||||
|
* triggered by the simulator-backend. More specifically, this event handler
|
||||||
|
* will be called *before* the event is actually triggered, i.e. before the
|
||||||
|
* corresponding coroutine is toggled.
|
||||||
|
* @param pev the event to be triggered when returning from the event handler
|
||||||
|
*/
|
||||||
|
virtual void onEventTrigger(fi::BaseEvent* pev) { }
|
||||||
/* ********************************************************************
|
/* ********************************************************************
|
||||||
* Simulator Controller & Access API (SCA-API):
|
* Simulator Controller & Access API:
|
||||||
* ********************************************************************/
|
* ********************************************************************/
|
||||||
/**
|
/**
|
||||||
* Save simulator state.
|
* Save simulator state.
|
||||||
@ -186,7 +213,7 @@ class SimulatorController
|
|||||||
*/
|
*/
|
||||||
void setMemoryManager(MemoryManager* pMem) { m_Mem = pMem; }
|
void setMemoryManager(MemoryManager* pMem) { m_Mem = pMem; }
|
||||||
/* ********************************************************************
|
/* ********************************************************************
|
||||||
* Experiment-Flow & Event Management API (EFEM-API):
|
* Experiment-Flow & Event Management API:
|
||||||
* ********************************************************************/
|
* ********************************************************************/
|
||||||
/**
|
/**
|
||||||
* Adds the specified experiment or plugin and creates a coroutine to
|
* Adds the specified experiment or plugin and creates a coroutine to
|
||||||
@ -204,7 +231,8 @@ class SimulatorController
|
|||||||
* Add event ev to the event management. This causes the event to be
|
* Add event ev to the event management. This causes the event to be
|
||||||
* active.
|
* active.
|
||||||
* @param ev the event pointer to be added for the current flow
|
* @param ev the event pointer to be added for the current flow
|
||||||
* @return the id of the event used to identify the object on occurrence
|
* @return the id of the event used to identify the object on occurrence;
|
||||||
|
* -1 is returned on errors
|
||||||
*/
|
*/
|
||||||
fi::EventId addEvent(fi::BaseEvent* ev);
|
fi::EventId addEvent(fi::BaseEvent* ev);
|
||||||
/**
|
/**
|
||||||
@ -221,9 +249,11 @@ class SimulatorController
|
|||||||
void clearEvents(fi::ExperimentFlow *flow = 0) { m_EvList.remove(flow); }
|
void clearEvents(fi::ExperimentFlow *flow = 0) { m_EvList.remove(flow); }
|
||||||
/**
|
/**
|
||||||
* Waits on any events which have been added to the event management. If
|
* Waits on any events which have been added to the event management. If
|
||||||
* one of those events occour, waitAny() will return the id of that
|
* one of those events occour, waitAny() will return the id of that event.
|
||||||
* event.
|
|
||||||
* @return the previously occurred event
|
* @return the previously occurred event
|
||||||
|
*
|
||||||
|
* FIXME: Maybe this should return immediately if there are not events?
|
||||||
|
* (additional parameter flag?)
|
||||||
*/
|
*/
|
||||||
fi::BaseEvent* waitAny();
|
fi::BaseEvent* waitAny();
|
||||||
/**
|
/**
|
||||||
@ -232,9 +262,21 @@ class SimulatorController
|
|||||||
* @param ev the event pointer to be added
|
* @param ev the event pointer to be added
|
||||||
* @return the pointer of the occurred event (it is not guaranteed that
|
* @return the pointer of the occurred event (it is not guaranteed that
|
||||||
* this pointer will be equal to ev)
|
* this pointer will be equal to ev)
|
||||||
* FIXME rename to make clear this returns when *any* event occurs
|
*
|
||||||
|
* FIXME: Rename to make clear this returns when *any* event occurs
|
||||||
*/
|
*/
|
||||||
fi::BaseEvent* addEventAndWait(fi::BaseEvent* ev);
|
fi::BaseEvent* addEventAndWait(fi::BaseEvent* ev);
|
||||||
|
/**
|
||||||
|
* Checks whether any experiment flow has events in the event-list.
|
||||||
|
* @return \c true if there are still events, or \c false otherwise
|
||||||
|
*/
|
||||||
|
bool hasEvents() const { return getEventCount() > 0; }
|
||||||
|
/**
|
||||||
|
* Determines the number of (stored) events in the event-list which have
|
||||||
|
* not been triggered so far.
|
||||||
|
* @return the actual number of events
|
||||||
|
*/
|
||||||
|
unsigned getEventCount() const { return m_EvList.getEventCount(); }
|
||||||
/**
|
/**
|
||||||
* Fetches data for the experiments from the Job-Server.
|
* Fetches data for the experiments from the Job-Server.
|
||||||
* @return the Experiment-Data from the Job-Server.
|
* @return the Experiment-Data from the Job-Server.
|
||||||
|
|||||||
@ -1,7 +1,10 @@
|
|||||||
|
#include <sstream>
|
||||||
|
|
||||||
#include "BochsController.hpp"
|
#include "BochsController.hpp"
|
||||||
#include "BochsMemory.hpp"
|
#include "BochsMemory.hpp"
|
||||||
#include "BochsRegister.hpp"
|
#include "BochsRegister.hpp"
|
||||||
#include "../Register.hpp"
|
#include "../Register.hpp"
|
||||||
|
#include "../SALInst.hpp"
|
||||||
|
|
||||||
namespace sal
|
namespace sal
|
||||||
{
|
{
|
||||||
@ -94,8 +97,7 @@ void BochsController::onInstrPtrChanged(address_t instrPtr)
|
|||||||
fi::EventList::iterator it = m_EvList.begin();
|
fi::EventList::iterator it = m_EvList.begin();
|
||||||
while(it != m_EvList.end())
|
while(it != m_EvList.end())
|
||||||
{
|
{
|
||||||
// FIXME: Performance verbessern (dazu muss entsprechend auch die Speicherung
|
// FIXME: Maybe we need to improve the performance of this check.
|
||||||
// in EventList(.cc|.hpp) angepasst bzw. verbessert werden).
|
|
||||||
fi::BPEvent* pEvBreakpt = dynamic_cast<fi::BPEvent*>(*it);
|
fi::BPEvent* pEvBreakpt = dynamic_cast<fi::BPEvent*>(*it);
|
||||||
if(pEvBreakpt && (instrPtr == pEvBreakpt->getWatchInstructionPointer() ||
|
if(pEvBreakpt && (instrPtr == pEvBreakpt->getWatchInstructionPointer() ||
|
||||||
pEvBreakpt->getWatchInstructionPointer() == fi::ANY_ADDR))
|
pEvBreakpt->getWatchInstructionPointer() == fi::ANY_ADDR))
|
||||||
@ -184,4 +186,71 @@ void BochsController::fireInterruptDone()
|
|||||||
m_Flows.toggle(m_CurrFlow);
|
m_Flows.toggle(m_CurrFlow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BochsController::m_onTimerTrigger(void* thisPtr)
|
||||||
|
{
|
||||||
|
// FIXME: The timer logic can be modified to use only one timer in Bochs.
|
||||||
|
// (For now, this suffices.)
|
||||||
|
fi::TimerEvent* pTmEv = static_cast<fi::TimerEvent*>(thisPtr);
|
||||||
|
// Check for a matching TimerEvent. (In fact, we are only
|
||||||
|
// interessted in the iterator pointing at pTmEv.):
|
||||||
|
fi::EventList::iterator it = std::find(simulator.m_EvList.begin(),
|
||||||
|
simulator.m_EvList.end(), pTmEv);
|
||||||
|
// TODO: This has O(|m_EvList|) time complexity. We can further improve this
|
||||||
|
// by creating a method such that makeActive(pTmEv) works as well,
|
||||||
|
// reducing the time complexity to O(1).
|
||||||
|
simulator.m_EvList.makeActive(it);
|
||||||
|
simulator.m_EvList.fireActiveEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
timer_id_t BochsController::m_registerTimer(fi::TimerEvent* pev)
|
||||||
|
{
|
||||||
|
assert(pev != NULL);
|
||||||
|
return static_cast<timer_id_t>(
|
||||||
|
bx_pc_system.register_timer(pev, m_onTimerTrigger, pev->getTimeout(), !pev->getOnceFlag(),
|
||||||
|
1/*start immediately*/, "Fail*: BochsController"/*name*/));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BochsController::m_unregisterTimer(fi::TimerEvent* pev)
|
||||||
|
{
|
||||||
|
assert(pev != NULL);
|
||||||
|
bx_pc_system.deactivate_timer(static_cast<unsigned>(pev->getId()));
|
||||||
|
return bx_pc_system.unregisterTimer(static_cast<unsigned>(pev->getId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BochsController::onEventAddition(fi::BaseEvent* pev)
|
||||||
|
{
|
||||||
|
fi::TimerEvent* tmev;
|
||||||
|
// Register the timer event in the Bochs simulator:
|
||||||
|
if ((tmev = dynamic_cast<fi::TimerEvent*>(pev)) != NULL) {
|
||||||
|
tmev->setId(m_registerTimer(tmev));
|
||||||
|
if(tmev->getId() == -1)
|
||||||
|
return false; // unable to register the timer (error in Bochs' function call)
|
||||||
|
}
|
||||||
|
// Note: Maybe more stuff to do here for other event types.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BochsController::onEventDeletion(fi::BaseEvent* pev)
|
||||||
|
{
|
||||||
|
fi::TimerEvent* tmev;
|
||||||
|
// Unregister the time event:
|
||||||
|
if ((tmev = dynamic_cast<fi::TimerEvent*>(pev)) != NULL) {
|
||||||
|
m_unregisterTimer(tmev);
|
||||||
|
}
|
||||||
|
// Note: Maybe more stuff to do here for other event types.
|
||||||
|
}
|
||||||
|
|
||||||
|
void BochsController::onEventTrigger(fi::BaseEvent* pev)
|
||||||
|
{
|
||||||
|
fi::TimerEvent* tmev;
|
||||||
|
// Unregister the time event, if once-flag is true:
|
||||||
|
if ((tmev = dynamic_cast<fi::TimerEvent*>(pev)) != NULL) {
|
||||||
|
if (tmev->getOnceFlag()) // deregister the timer (timer = single timeout)
|
||||||
|
m_unregisterTimer(tmev);
|
||||||
|
else // re-add the event (repetitive timer), tunneling the onEventAddition-handler
|
||||||
|
m_EvList.add(tmev, tmev->getParent());
|
||||||
|
}
|
||||||
|
// Note: Maybe more stuff to do here for other event types.
|
||||||
|
}
|
||||||
|
|
||||||
} // end-of-namespace: sal
|
} // end-of-namespace: sal
|
||||||
|
|||||||
@ -18,6 +18,7 @@
|
|||||||
#include "../../../bochs/cpu/cpu.h"
|
#include "../../../bochs/cpu/cpu.h"
|
||||||
#include "../../../bochs/config.h"
|
#include "../../../bochs/config.h"
|
||||||
#include "../../../bochs/iodev/iodev.h"
|
#include "../../../bochs/iodev/iodev.h"
|
||||||
|
#include "../../../bochs/pc_system.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
@ -34,31 +35,87 @@ namespace sal
|
|||||||
class BochsController : public SimulatorController
|
class BochsController : public SimulatorController
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
/**
|
fi::ExperimentFlow* m_CurrFlow; //!< Stores the current flow for save/restore-operations
|
||||||
* stores the current flow for save/restore-operations
|
|
||||||
*/
|
|
||||||
fi::ExperimentFlow* m_CurrFlow;
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
unsigned m_Regularity;
|
unsigned m_Regularity;
|
||||||
unsigned m_Counter;
|
unsigned m_Counter;
|
||||||
std::ostream* m_pDest;
|
std::ostream* m_pDest;
|
||||||
#endif
|
#endif
|
||||||
|
/**
|
||||||
|
* Static internal event handler for TimerEvents. This static function is
|
||||||
|
* called when a previously registered (Bochs) timer triggers. This function
|
||||||
|
* searches for the provided TimerEvent object within the EventList and
|
||||||
|
* fires such an event by calling \c fireActiveEvents().
|
||||||
|
* @param thisPtr a pointer to the TimerEvent-object triggered
|
||||||
|
*
|
||||||
|
* FIXME: Due to Bochs internal timer and ips-configuration related stuff,
|
||||||
|
* the simulator sometimes panics with "keyboard error:21" (see line
|
||||||
|
* 1777 in bios/rombios.c, function keyboard_init()) if a TimerEvent
|
||||||
|
* is added *before* the bios has been loaded and initialized. To
|
||||||
|
* reproduce this error, try adding a TimerEvent as the initial step
|
||||||
|
* in your experiment code and wait for it (addEventAndWait()).
|
||||||
|
*/
|
||||||
|
static void m_onTimerTrigger(void *thisPtr);
|
||||||
|
/**
|
||||||
|
* Registers a timer in the Bochs simulator. This timer fires \a TimerEvents
|
||||||
|
* to inform the corresponding experiment-flow. Note that the number of timers
|
||||||
|
* (in Bochs) is limited to \c BX_MAX_TIMERS (defaults to 64 in v2.4.6).
|
||||||
|
* @param pev a pointer to the (experiment flow-) allocated TimerEvent object,
|
||||||
|
* providing all required information to start the time, e.g. the
|
||||||
|
* timeout value.
|
||||||
|
* @return \c The unique id of the timer recently created. This id is carried
|
||||||
|
* along with the TimerEvent, @see getId(). On error, -1 is returned
|
||||||
|
* (e.g. because a timer with the same id is already existing)
|
||||||
|
*/
|
||||||
|
timer_id_t m_registerTimer(fi::TimerEvent* pev);
|
||||||
|
/**
|
||||||
|
* Deletes a timer. No further events will be triggered by the timer.
|
||||||
|
* @param pev a pointer to the TimerEvent-object to be removed
|
||||||
|
* @return \c true if the timer with \a pev->getId() has been removed
|
||||||
|
* successfully, \c false otherwise
|
||||||
|
*/
|
||||||
|
bool m_unregisterTimer(fi::TimerEvent* pev);
|
||||||
public:
|
public:
|
||||||
// Initialize the controller.
|
// Initialize the controller.
|
||||||
BochsController();
|
BochsController();
|
||||||
~BochsController();
|
~BochsController();
|
||||||
/* ********************************************************************
|
/* ********************************************************************
|
||||||
* Standard Event Handler API (SEH-API):
|
* Standard Event Handler API:
|
||||||
* ********************************************************************/
|
* ********************************************************************/
|
||||||
/**
|
/**
|
||||||
* Instruction pointer modification handler. This method is called
|
* Instruction pointer modification handler. This method is called (from
|
||||||
* (from the Breakpoints aspect) every time when the Bochs-internal IP
|
* the Breakpoints aspect) every time when the Bochs-internal IP changes.
|
||||||
* changes.
|
* @param instrPtr the new instruction pointer
|
||||||
* @param instrPtr
|
|
||||||
*/
|
*/
|
||||||
void onInstrPtrChanged(address_t instrPtr);
|
void onInstrPtrChanged(address_t instrPtr);
|
||||||
|
/**
|
||||||
|
* This method is called when an experiment flow adds a new event by
|
||||||
|
* calling \c simulator.addEvent(pev) or \c simulator.addEventAndWait(pev).
|
||||||
|
* More specifically, the event will be added to the event-list first
|
||||||
|
* (buffer-list, to be precise) and then this event handler is called.
|
||||||
|
* @param pev the event which has been added
|
||||||
|
* @return You should return \c true to continue and \c false to prevent
|
||||||
|
* the addition of the event \a pev.
|
||||||
|
*/
|
||||||
|
bool onEventAddition(fi::BaseEvent* pev);
|
||||||
|
/**
|
||||||
|
* This method is called when an experiment flow removes an event from
|
||||||
|
* the event-management by calling \c removeEvent(prev), \c clearEvents()
|
||||||
|
* or by deleting a complete flow (\c removeFlow). More specifically,
|
||||||
|
* this event handler will be called *before* the event is actually deleted.
|
||||||
|
* @param pev the event to be deleted when returning from the event handler
|
||||||
|
*/
|
||||||
|
void onEventDeletion(fi::BaseEvent* pev);
|
||||||
|
/**
|
||||||
|
* This method is called when an previously added event is about to be
|
||||||
|
* triggered by the simulator-backend. More specifically, this event handler
|
||||||
|
* will be called *before* the event is actually triggered, i.e. before the
|
||||||
|
* corresponding coroutine is toggled.
|
||||||
|
* @param pev the event to be triggered when returning from the event handler
|
||||||
|
*/
|
||||||
|
void onEventTrigger(fi::BaseEvent* pev);
|
||||||
/* ********************************************************************
|
/* ********************************************************************
|
||||||
* Simulator Controller & Access API (SCA-API):
|
* Simulator Controller & Access API:
|
||||||
* ********************************************************************/
|
* ********************************************************************/
|
||||||
/**
|
/**
|
||||||
* Save simulator state.
|
* Save simulator state.
|
||||||
|
|||||||
@ -1,8 +1,5 @@
|
|||||||
|
|
||||||
// Author: Adrian Böckenkamp
|
|
||||||
// Date: 08.06.2011
|
|
||||||
|
|
||||||
#include "Event.hpp"
|
#include "Event.hpp"
|
||||||
|
#include "../SAL/SALInst.hpp"
|
||||||
|
|
||||||
namespace fi
|
namespace fi
|
||||||
{
|
{
|
||||||
|
|||||||
@ -440,7 +440,7 @@ class GuestEvent : virtual public BaseEvent
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* \class JumpEvent
|
* \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
|
class JumpEvent : virtual public BaseEvent
|
||||||
{
|
{
|
||||||
@ -481,6 +481,50 @@ class JumpEvent : virtual public BaseEvent
|
|||||||
{ m_FlagTriggered = flagTriggered; }
|
{ 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
|
} // end-of-namespace: fi
|
||||||
|
|
||||||
#endif /* __EVENT_HPP__ */
|
#endif /* __EVENT_HPP__ */
|
||||||
|
|||||||
@ -23,6 +23,10 @@ void EventList::remove(BaseEvent* ev)
|
|||||||
// * clear m_BufferList
|
// * clear m_BufferList
|
||||||
// * copy m_FireList to m_DeleteList
|
// * copy m_FireList to m_DeleteList
|
||||||
if (ev == 0) {
|
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();
|
m_BufferList.clear();
|
||||||
// all remaining active events must not fire anymore
|
// all remaining active events must not fire anymore
|
||||||
m_DeleteList.insert(m_DeleteList.end(), m_FireList.begin(), m_FireList.end());
|
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
|
// * find/remove ev in m_BufferList
|
||||||
// * if ev in m_FireList, copy to m_DeleteList
|
// * if ev in m_FireList, copy to m_DeleteList
|
||||||
} else {
|
} else {
|
||||||
|
sal::simulator.onEventDeletion(ev);
|
||||||
m_BufferList.remove(ev);
|
m_BufferList.remove(ev);
|
||||||
firelist_t::const_iterator it =
|
firelist_t::const_iterator it =
|
||||||
std::find(m_FireList.begin(), m_FireList.end(), ev);
|
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)
|
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);
|
m_DeleteList.push_back(*it);
|
||||||
|
}
|
||||||
return (m_BufferList.erase(it));
|
return (m_BufferList.erase(it));
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventList::remove(ExperimentFlow* flow)
|
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?
|
// all events?
|
||||||
if (flow == 0) {
|
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();
|
m_BufferList.clear();
|
||||||
} else {
|
} else { // remove all events corresponding to a specific experiment ("flow"):
|
||||||
for (bufferlist_t::iterator it = m_BufferList.begin();
|
for (bufferlist_t::iterator it = m_BufferList.begin();
|
||||||
it != m_BufferList.end(); ) {
|
it != m_BufferList.end(); ) {
|
||||||
if ((*it)->getParent() == flow) {
|
if ((*it)->getParent() == flow) {
|
||||||
|
sal::simulator.onEventDeletion(*it);
|
||||||
it = m_BufferList.erase(it);
|
it = m_BufferList.erase(it);
|
||||||
} else {
|
} else {
|
||||||
++it;
|
++it;
|
||||||
@ -72,11 +97,12 @@ void EventList::remove(ExperimentFlow* flow)
|
|||||||
it != m_FireList.end(); it++) {
|
it != m_FireList.end(); it++) {
|
||||||
if (std::find(m_DeleteList.begin(), m_DeleteList.end(), *it)
|
if (std::find(m_DeleteList.begin(), m_DeleteList.end(), *it)
|
||||||
!= m_DeleteList.end()) {
|
!= m_DeleteList.end()) {
|
||||||
continue;
|
continue; // (already in the delete-list? -> skip!)
|
||||||
}
|
}
|
||||||
// ... need to be pushed into m_DeleteList, as we're currently
|
// ... need to be pushed into m_DeleteList, as we're currently
|
||||||
// iterating over m_FireList in fireActiveEvents() and cannot modify it
|
// iterating over m_FireList in fireActiveEvents() and cannot modify it
|
||||||
if (flow == 0 || (*it)->getParent() == flow) {
|
if (flow == 0 || (*it)->getParent() == flow) {
|
||||||
|
sal::simulator.onEventDeletion(*it);
|
||||||
m_DeleteList.push_back(*it);
|
m_DeleteList.push_back(*it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -117,13 +143,14 @@ EventList::iterator EventList::makeActive(iterator it)
|
|||||||
|
|
||||||
void EventList::fireActiveEvents()
|
void EventList::fireActiveEvents()
|
||||||
{
|
{
|
||||||
for(firelist_t::iterator it = m_FireList.begin();
|
for (firelist_t::iterator it = m_FireList.begin();
|
||||||
it != m_FireList.end(); it++)
|
it != m_FireList.end(); it++) {
|
||||||
{
|
if (std::find(m_DeleteList.begin(), m_DeleteList.end(), *it)
|
||||||
if(std::find(m_DeleteList.begin(), m_DeleteList.end(), *it)
|
== m_DeleteList.end()) { // not found in delete-list?
|
||||||
== m_DeleteList.end()) // not found in delete-list?
|
|
||||||
{
|
|
||||||
m_pFired = *it;
|
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();
|
ExperimentFlow* pFlow = m_pFired->getParent();
|
||||||
assert(pFlow && "FATAL ERROR: The event has no parent experiment (owner)!");
|
assert(pFlow && "FATAL ERROR: The event has no parent experiment (owner)!");
|
||||||
sal::simulator.m_Flows.toggle(pFlow);
|
sal::simulator.m_Flows.toggle(pFlow);
|
||||||
@ -131,6 +158,7 @@ void EventList::fireActiveEvents()
|
|||||||
}
|
}
|
||||||
m_FireList.clear();
|
m_FireList.clear();
|
||||||
m_DeleteList.clear();
|
m_DeleteList.clear();
|
||||||
|
// Note: Do NOT call any event handlers here!
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t EventList::getContextCount() const
|
size_t EventList::getContextCount() const
|
||||||
|
|||||||
@ -1,9 +1,6 @@
|
|||||||
#ifndef __EVENT_LIST_HPP__
|
#ifndef __EVENT_LIST_HPP__
|
||||||
#define __EVENT_LIST_HPP__
|
#define __EVENT_LIST_HPP__
|
||||||
|
|
||||||
// Author: Adrian Böckenkamp
|
|
||||||
// Date: 04.02.2012
|
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -140,10 +137,11 @@ class EventList
|
|||||||
*/
|
*/
|
||||||
size_t getContextCount() const;
|
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)
|
* @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
|
* Retrieves the recently triggered event object. To map this object to
|
||||||
* it's context (id est, the related ExerimentFlow), use
|
* 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
|
* @return returns the updated iteration, pointing to the next element
|
||||||
* after makeActive returns, "it" is invalid, so the returned
|
* after makeActive returns, "it" is invalid, so the returned
|
||||||
* iterator should be used to continue the iteration
|
* iterator should be used to continue the iteration
|
||||||
* TODO: besserer Name statt "makeActive"?
|
*
|
||||||
|
* TODO: Improve naming (instead of "makeActive")?
|
||||||
*/
|
*/
|
||||||
iterator makeActive(iterator it);
|
iterator makeActive(iterator it);
|
||||||
/**
|
/**
|
||||||
@ -177,7 +176,8 @@ class EventList
|
|||||||
* makeActive() for more details. The recently triggered event can be
|
* makeActive() for more details. The recently triggered event can be
|
||||||
* retrieved by calling \a getLastFired(). After all events have been
|
* retrieved by calling \a getLastFired(). After all events have been
|
||||||
* triggered, the (internal) fire- and delete-list will be cleared.
|
* triggered, the (internal) fire- and delete-list will be cleared.
|
||||||
* TODO: besserer Name statt "fireActiveEvents"?
|
*
|
||||||
|
* TODO: Improve naming (instead of "fireActiveEvents")?
|
||||||
*/
|
*/
|
||||||
void fireActiveEvents();
|
void fireActiveEvents();
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,9 +1,6 @@
|
|||||||
#ifndef __EXPERIMENT_FLOW_HPP__
|
#ifndef __EXPERIMENT_FLOW_HPP__
|
||||||
#define __EXPERIMENT_FLOW_HPP__
|
#define __EXPERIMENT_FLOW_HPP__
|
||||||
|
|
||||||
// Author: Adrian Böckenkamp
|
|
||||||
// Date: 09.09.2011
|
|
||||||
|
|
||||||
#include "../SAL/SALInst.hpp"
|
#include "../SAL/SALInst.hpp"
|
||||||
|
|
||||||
namespace fi
|
namespace fi
|
||||||
@ -11,9 +8,8 @@ namespace fi
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* \class ExperimentFlow
|
* \class ExperimentFlow
|
||||||
* Basic interface for user-defined experiments. To create a new
|
* Basic interface for user-defined experiments. To create a new experiment,
|
||||||
* experiment, derive your own class from ExperimentFlow and
|
* derive your own class from ExperimentFlow and define the run method.
|
||||||
* define the run method.
|
|
||||||
*/
|
*/
|
||||||
class ExperimentFlow
|
class ExperimentFlow
|
||||||
{
|
{
|
||||||
@ -33,6 +29,9 @@ class ExperimentFlow
|
|||||||
{
|
{
|
||||||
run();
|
run();
|
||||||
sal::simulator.clearEvents(this); // remove residual events
|
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