Pre-/postprocessing is done within the event objects (Bochs-specific event added), ++coding-style.
git-svn-id: https://www4.informatik.uni-erlangen.de/i4svn/danceos/trunk/devel/fail@1366 8c4709b5-6ec9-48aa-a5cd-a96041d1645a
This commit is contained in:
@ -26,9 +26,6 @@ public:
|
|||||||
{
|
{
|
||||||
run();
|
run();
|
||||||
simulator.clearEvents(this); // remove residual events
|
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.
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -7,6 +7,7 @@ if(BUILD_BOCHS)
|
|||||||
Register.cc
|
Register.cc
|
||||||
SimulatorController.cc
|
SimulatorController.cc
|
||||||
bochs/BochsController.cc
|
bochs/BochsController.cc
|
||||||
|
bochs/BochsEvents.cc
|
||||||
)
|
)
|
||||||
else()
|
else()
|
||||||
set(SRCS
|
set(SRCS
|
||||||
|
|||||||
@ -7,9 +7,8 @@ EventId BaseEvent::m_Counter = 0;
|
|||||||
|
|
||||||
bool TroubleEvent::isMatching(unsigned troubleNum) const
|
bool TroubleEvent::isMatching(unsigned troubleNum) const
|
||||||
{
|
{
|
||||||
for(unsigned i = 0; i < m_WatchNumbers.size(); i++)
|
for (unsigned i = 0; i < m_WatchNumbers.size(); i++) {
|
||||||
{
|
if (m_WatchNumbers[i] == troubleNum ||
|
||||||
if(m_WatchNumbers[i] == troubleNum ||
|
|
||||||
m_WatchNumbers[i] == ANY_TRAP)
|
m_WatchNumbers[i] == ANY_TRAP)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -18,10 +17,8 @@ bool TroubleEvent::isMatching(unsigned troubleNum) const
|
|||||||
|
|
||||||
bool TroubleEvent::removeWatchNumber(unsigned troubleNum)
|
bool TroubleEvent::removeWatchNumber(unsigned troubleNum)
|
||||||
{
|
{
|
||||||
for(unsigned i = 0; i < m_WatchNumbers.size(); i++)
|
for (unsigned i = 0; i < m_WatchNumbers.size(); i++) {
|
||||||
{
|
if (m_WatchNumbers[i] == troubleNum) {
|
||||||
if(m_WatchNumbers[i] == troubleNum)
|
|
||||||
{
|
|
||||||
m_WatchNumbers.erase(m_WatchNumbers.begin()+i);
|
m_WatchNumbers.erase(m_WatchNumbers.begin()+i);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -31,10 +28,8 @@ bool TroubleEvent::removeWatchNumber(unsigned troubleNum)
|
|||||||
|
|
||||||
bool TroubleEvent::addWatchNumber(unsigned troubleNumber)
|
bool TroubleEvent::addWatchNumber(unsigned troubleNumber)
|
||||||
{
|
{
|
||||||
for(unsigned i = 0; i < m_WatchNumbers.size(); i++)
|
for (unsigned i = 0; i < m_WatchNumbers.size(); i++) {
|
||||||
{
|
if (m_WatchNumbers[i] == troubleNumber)
|
||||||
|
|
||||||
if(m_WatchNumbers[i] == troubleNumber)
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
m_WatchNumbers.push_back(troubleNumber);
|
m_WatchNumbers.push_back(troubleNumber);
|
||||||
@ -43,12 +38,12 @@ bool TroubleEvent::addWatchNumber(unsigned troubleNumber)
|
|||||||
|
|
||||||
bool MemAccessEvent::isMatching(address_t addr, accessType_t accesstype) const
|
bool MemAccessEvent::isMatching(address_t addr, accessType_t accesstype) const
|
||||||
{
|
{
|
||||||
if(!(m_WatchType & accesstype))
|
if (!(m_WatchType & accesstype))
|
||||||
return (false);
|
return false;
|
||||||
else if(m_WatchAddr != addr &&
|
else if (m_WatchAddr != addr &&
|
||||||
m_WatchAddr != ANY_ADDR)
|
m_WatchAddr != ANY_ADDR)
|
||||||
return (false);
|
return false;
|
||||||
return (true);
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BPEvent::aspaceIsMatching(address_t aspace) const
|
bool BPEvent::aspaceIsMatching(address_t aspace) const
|
||||||
@ -77,9 +72,8 @@ bool BPRangeEvent::isMatching(address_t addr, address_t aspace) const
|
|||||||
bool BPSingleEvent::isMatching(address_t addr, address_t aspace) const
|
bool BPSingleEvent::isMatching(address_t addr, address_t aspace) const
|
||||||
{
|
{
|
||||||
if (aspaceIsMatching(aspace)) {
|
if (aspaceIsMatching(aspace)) {
|
||||||
if (m_WatchInstrPtr == ANY_ADDR || m_WatchInstrPtr == addr) {
|
if (m_WatchInstrPtr == ANY_ADDR || m_WatchInstrPtr == addr)
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,9 +17,9 @@ class ExperimentFlow;
|
|||||||
typedef unsigned long EventId; //!< type of event ids
|
typedef unsigned long EventId; //!< type of event ids
|
||||||
|
|
||||||
//! invalid event id (used as a return indicator)
|
//! invalid event id (used as a return indicator)
|
||||||
const EventId INVALID_EVENT = (EventId)-1;
|
const EventId INVALID_EVENT = static_cast<EventId>(-1);
|
||||||
//! address wildcard (e.g. for BPEvent's)
|
//! address wildcard (e.g. for BPEvent's)
|
||||||
const address_t ANY_ADDR = static_cast<address_t>(-1);
|
const address_t ANY_ADDR = static_cast<address_t>(-1);
|
||||||
//! instruction wildcard
|
//! instruction wildcard
|
||||||
const unsigned ANY_INSTR = static_cast<unsigned>(-1);
|
const unsigned ANY_INSTR = static_cast<unsigned>(-1);
|
||||||
//! trap wildcard
|
//! trap wildcard
|
||||||
@ -45,6 +45,30 @@ public:
|
|||||||
BaseEvent() : m_Id(++m_Counter), m_OccCounter(1), m_OccCounterInit(1), m_Parent(NULL)
|
BaseEvent() : m_Id(++m_Counter), m_OccCounter(1), m_OccCounterInit(1), m_Parent(NULL)
|
||||||
{ updateTime(); }
|
{ updateTime(); }
|
||||||
virtual ~BaseEvent() { }
|
virtual ~BaseEvent() { }
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
* @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. \c INVALID_EVENT is returned).
|
||||||
|
*/
|
||||||
|
virtual bool onEventAddition() { 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.
|
||||||
|
*/
|
||||||
|
virtual void onEventDeletion() { }
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
virtual void onEventTrigger() { }
|
||||||
/**
|
/**
|
||||||
* Retrieves the unique event id for this event.
|
* Retrieves the unique event id for this event.
|
||||||
* @return the unique id
|
* @return the unique id
|
||||||
@ -116,8 +140,7 @@ public:
|
|||||||
* in a random address space.
|
* in a random address space.
|
||||||
*/
|
*/
|
||||||
BPEvent(address_t address_space = ANY_ADDR)
|
BPEvent(address_t address_space = ANY_ADDR)
|
||||||
: m_CR3(address_space), m_TriggerInstrPtr(ANY_ADDR)
|
: m_CR3(address_space), m_TriggerInstrPtr(ANY_ADDR) { }
|
||||||
{}
|
|
||||||
/**
|
/**
|
||||||
* Returns the address space register of this event.
|
* Returns the address space register of this event.
|
||||||
*/
|
*/
|
||||||
@ -539,7 +562,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
unsigned getOpcode() const { return (m_Opcode); }
|
unsigned getOpcode() const { return (m_Opcode); }
|
||||||
/**
|
/**
|
||||||
* Returns \c true, of the event was triggered due to specific register
|
* Returns \c true, if the event was triggered due to specific register
|
||||||
* content, \c false otherwise.
|
* content, \c false otherwise.
|
||||||
*/
|
*/
|
||||||
bool isRegisterTriggered() { return (!m_FlagTriggered); }
|
bool isRegisterTriggered() { return (!m_FlagTriggered); }
|
||||||
@ -560,26 +583,31 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \class TimerEvent
|
* \class GenericTimerEvent
|
||||||
* This event type is used to create timeouts/timers within in an experiment.
|
* This event type is used to create timeouts within in an experiment.
|
||||||
|
*
|
||||||
|
* Depending on your simulator backend, a concrete class needs to be derived
|
||||||
|
* from \c GenericTimerEvent. \c onEventAddition should be used to register and
|
||||||
|
* \c onEventDeletion to unregister the timer. \c onEventTrigger can be used to
|
||||||
|
* re-register the timer if a repetitive timer is requested and the back-
|
||||||
|
* end doesn't support such timer types natively.
|
||||||
*/
|
*/
|
||||||
class TimerEvent : public BaseEvent {
|
class GenericTimerEvent : public BaseEvent {
|
||||||
private:
|
protected:
|
||||||
unsigned m_Timeout; //!< timeout interval in milliseconds
|
unsigned m_Timeout; //!< timeout interval in milliseconds
|
||||||
timer_id_t m_Id; //!< internal timer id (sim-specific)
|
timer_id_t m_Id; //!< internal timer id (sim-specific)
|
||||||
bool m_Once; //!< true, if the timer should be triggered only once
|
bool m_Once; //!< \c true, if the timer should be triggered only once, \c false otherwise
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Creates a new timer event. This can be used to implement a timeout-
|
* Creates a new timer event. This can be used to implement a timeout-
|
||||||
* mechanism in the experiment-flow. The timer starts automatically when
|
* mechanism in the experiment-flow. The timer starts automatically when
|
||||||
* added to the simulator backend (@see SimulatorController::addEvent)
|
* added to the simulator backend.
|
||||||
* @param timeout the time intervall in milliseconds (ms)
|
* @param timeout the time intervall in milliseconds (ms)
|
||||||
* @param once \c true, if the TimerEvent should be triggered once,
|
* @see SimulatorController::addEvent
|
||||||
* \c false if it should occur regularly
|
|
||||||
*/
|
*/
|
||||||
TimerEvent(unsigned timeout, bool once)
|
GenericTimerEvent(unsigned timeout)
|
||||||
: m_Timeout(timeout), m_Id(-1), m_Once(once) { }
|
: m_Timeout(timeout), m_Id(-1) { }
|
||||||
~TimerEvent() { }
|
~GenericTimerEvent() { }
|
||||||
/**
|
/**
|
||||||
* Retrieves the internal timer id. Maybe useful for debug output.
|
* Retrieves the internal timer id. Maybe useful for debug output.
|
||||||
* @return the timer id
|
* @return the timer id
|
||||||
@ -595,11 +623,6 @@ public:
|
|||||||
* @return the timout in milliseconds
|
* @return the timout in milliseconds
|
||||||
*/
|
*/
|
||||||
unsigned getTimeout() const { return m_Timeout; }
|
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: fail
|
} // end-of-namespace: fail
|
||||||
|
|||||||
@ -8,26 +8,27 @@ namespace fail {
|
|||||||
void EventList::addToCaches(BaseEvent *ev)
|
void EventList::addToCaches(BaseEvent *ev)
|
||||||
{
|
{
|
||||||
BPEvent *bps_ev;
|
BPEvent *bps_ev;
|
||||||
if((bps_ev = dynamic_cast<BPEvent*>(ev)) != NULL)
|
if ((bps_ev = dynamic_cast<BPEvent*>(ev)) != NULL)
|
||||||
m_Bp_cache.add(bps_ev);
|
m_Bp_cache.add(bps_ev);
|
||||||
|
|
||||||
IOPortEvent *io_ev;
|
IOPortEvent *io_ev;
|
||||||
if((io_ev = dynamic_cast<IOPortEvent*>(ev)) != NULL)
|
if ((io_ev = dynamic_cast<IOPortEvent*>(ev)) != NULL)
|
||||||
m_Io_cache.add(io_ev);
|
m_Io_cache.add(io_ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventList::removeFromCaches(BaseEvent *ev)
|
void EventList::removeFromCaches(BaseEvent *ev)
|
||||||
{
|
{
|
||||||
BPEvent *bpr_ev;
|
BPEvent *bpr_ev;
|
||||||
if((bpr_ev = dynamic_cast<BPEvent*>(ev)) != NULL)
|
if ((bpr_ev = dynamic_cast<BPEvent*>(ev)) != NULL)
|
||||||
m_Bp_cache.remove(bpr_ev);
|
m_Bp_cache.remove(bpr_ev);
|
||||||
|
|
||||||
IOPortEvent *io_ev;
|
IOPortEvent *io_ev;
|
||||||
if((io_ev = dynamic_cast<IOPortEvent*>(ev)) != NULL)
|
if ((io_ev = dynamic_cast<IOPortEvent*>(ev)) != NULL)
|
||||||
m_Io_cache.remove(io_ev);
|
m_Io_cache.remove(io_ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventList::clearCaches() {
|
void EventList::clearCaches()
|
||||||
|
{
|
||||||
m_Bp_cache.clear();
|
m_Bp_cache.clear();
|
||||||
m_Io_cache.clear();
|
m_Io_cache.clear();
|
||||||
}
|
}
|
||||||
@ -41,7 +42,7 @@ EventId EventList::add(BaseEvent* ev, ExperimentFlow* pExp)
|
|||||||
|
|
||||||
addToCaches(ev);
|
addToCaches(ev);
|
||||||
m_BufferList.push_back(ev);
|
m_BufferList.push_back(ev);
|
||||||
return (ev->getId());
|
return ev->getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventList::remove(BaseEvent* ev)
|
void EventList::remove(BaseEvent* ev)
|
||||||
@ -52,9 +53,9 @@ void EventList::remove(BaseEvent* ev)
|
|||||||
// * 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++)
|
for (bufferlist_t::iterator it = m_BufferList.begin(); it != m_BufferList.end(); it++)
|
||||||
simulator.onEventDeletion(*it);
|
(*it)->onEventDeletion();
|
||||||
for (firelist_t::iterator it = m_FireList.begin(); it != m_FireList.end(); it++)
|
for (firelist_t::iterator it = m_FireList.begin(); it != m_FireList.end(); it++)
|
||||||
simulator.onEventDeletion(*it);
|
(*it)->onEventDeletion();
|
||||||
clearCaches();
|
clearCaches();
|
||||||
m_BufferList.clear();
|
m_BufferList.clear();
|
||||||
// all remaining active events must not fire anymore
|
// all remaining active events must not fire anymore
|
||||||
@ -64,7 +65,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 {
|
||||||
simulator.onEventDeletion(ev);
|
ev->onEventDeletion();
|
||||||
|
|
||||||
removeFromCaches(ev);
|
removeFromCaches(ev);
|
||||||
m_BufferList.remove(ev);
|
m_BufferList.remove(ev);
|
||||||
@ -78,7 +79,7 @@ void EventList::remove(BaseEvent* ev)
|
|||||||
|
|
||||||
EventList::iterator EventList::remove(iterator it)
|
EventList::iterator EventList::remove(iterator it)
|
||||||
{
|
{
|
||||||
return (m_remove(it, false));
|
return m_remove(it, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
EventList::iterator EventList::m_remove(iterator it, bool skip_deletelist)
|
EventList::iterator EventList::m_remove(iterator it, bool skip_deletelist)
|
||||||
@ -87,9 +88,9 @@ EventList::iterator EventList::m_remove(iterator it, bool skip_deletelist)
|
|||||||
// If skip_deletelist = true, m_remove was called from makeActive. Accordingly, we
|
// 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)
|
// are not going to delete an event, instead we are "moving" an event object (= *it)
|
||||||
// from the buffer list to the fire-list. Therefore we only need to call the simulator's
|
// from the buffer list to the fire-list. Therefore we only need to call the simulator's
|
||||||
// event handler (m_onEventDeletion), if m_remove is called with the primary intention
|
// event handler (onEventDeletion), if m_remove is called with the primary intention
|
||||||
// to *delete* (not "move") an event.
|
// to *delete* (not "move") an event.
|
||||||
simulator.onEventDeletion(*it);
|
(*it)->onEventDeletion();
|
||||||
m_DeleteList.push_back(*it);
|
m_DeleteList.push_back(*it);
|
||||||
|
|
||||||
// Cached events have their own BufferCache<T>::makeActive() implementation, which
|
// Cached events have their own BufferCache<T>::makeActive() implementation, which
|
||||||
@ -98,35 +99,26 @@ EventList::iterator EventList::m_remove(iterator it, bool skip_deletelist)
|
|||||||
// BufferCache<T>::remove() from m_remove().
|
// BufferCache<T>::remove() from m_remove().
|
||||||
|
|
||||||
// NOTE: in case the semantics of skip_deletelist change, please adapt the following lines
|
// NOTE: in case the semantics of skip_deletelist change, please adapt the following lines
|
||||||
removeFromCaches((*it));
|
removeFromCaches(*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
|
|
||||||
// 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();
|
for (bufferlist_t::iterator it = m_BufferList.begin();
|
||||||
it != m_BufferList.end(); it++)
|
it != m_BufferList.end(); it++)
|
||||||
simulator.onEventDeletion(*it); // invoke event handler
|
(*it)->onEventDeletion(); // invoke event handler
|
||||||
clearCaches();
|
clearCaches();
|
||||||
m_BufferList.clear();
|
m_BufferList.clear();
|
||||||
} else { // remove all events corresponding to a specific experiment ("flow"):
|
} 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) {
|
||||||
simulator.onEventDeletion(*it);
|
(*it)->onEventDeletion();
|
||||||
it = m_BufferList.erase(it);
|
it = m_BufferList.erase(it);
|
||||||
} else {
|
} else {
|
||||||
++it;
|
++it;
|
||||||
@ -143,7 +135,7 @@ void EventList::remove(ExperimentFlow* flow)
|
|||||||
// ... 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) {
|
||||||
simulator.onEventDeletion(*it);
|
(*it)->onEventDeletion();
|
||||||
m_DeleteList.push_back(*it);
|
m_DeleteList.push_back(*it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -157,11 +149,11 @@ EventList::~EventList()
|
|||||||
BaseEvent* EventList::getEventFromId(EventId id)
|
BaseEvent* EventList::getEventFromId(EventId id)
|
||||||
{
|
{
|
||||||
// Loop through all events:
|
// Loop through all events:
|
||||||
for(bufferlist_t::iterator it = m_BufferList.begin();
|
for (bufferlist_t::iterator it = m_BufferList.begin();
|
||||||
it != m_BufferList.end(); it++)
|
it != m_BufferList.end(); it++)
|
||||||
if((*it)->getId() == id)
|
if ((*it)->getId() == id)
|
||||||
return (*it);
|
return *it;
|
||||||
return (NULL); // Nothing found.
|
return NULL; // Nothing found.
|
||||||
}
|
}
|
||||||
|
|
||||||
EventList::iterator EventList::makeActive(iterator it)
|
EventList::iterator EventList::makeActive(iterator it)
|
||||||
@ -179,7 +171,7 @@ EventList::iterator EventList::makeActive(iterator it)
|
|||||||
// store the removed item in the delete-list.
|
// store the removed item in the delete-list.
|
||||||
iterator it_next = m_remove(it, true); // remove event from buffer-list
|
iterator it_next = m_remove(it, true); // remove event from buffer-list
|
||||||
m_FireList.push_back(ev);
|
m_FireList.push_back(ev);
|
||||||
return (it_next);
|
return it_next;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventList::fireActiveEvents()
|
void EventList::fireActiveEvents()
|
||||||
@ -191,7 +183,7 @@ void EventList::fireActiveEvents()
|
|||||||
m_pFired = *it;
|
m_pFired = *it;
|
||||||
// Inform (call) the simulator's (internal) event handler that we are about
|
// Inform (call) the simulator's (internal) event handler that we are about
|
||||||
// to trigger an event (*before* we actually toggle the experiment flow):
|
// to trigger an event (*before* we actually toggle the experiment flow):
|
||||||
simulator.onEventTrigger(m_pFired);
|
m_pFired->onEventTrigger();
|
||||||
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)!");
|
||||||
simulator.m_Flows.toggle(pFlow);
|
simulator.m_Flows.toggle(pFlow);
|
||||||
@ -205,8 +197,8 @@ void EventList::fireActiveEvents()
|
|||||||
size_t EventList::getContextCount() const
|
size_t EventList::getContextCount() const
|
||||||
{
|
{
|
||||||
std::set<ExperimentFlow*> uniqueFlows; // count unique ExperimentFlow-ptr
|
std::set<ExperimentFlow*> uniqueFlows; // count unique ExperimentFlow-ptr
|
||||||
for(bufferlist_t::const_iterator it = m_BufferList.begin();
|
for (bufferlist_t::const_iterator it = m_BufferList.begin();
|
||||||
it != m_BufferList.end(); it++)
|
it != m_BufferList.end(); it++)
|
||||||
uniqueFlows.insert((*it)->getParent());
|
uniqueFlows.insert((*it)->getParent());
|
||||||
|
|
||||||
return uniqueFlows.size();
|
return uniqueFlows.size();
|
||||||
|
|||||||
@ -53,170 +53,169 @@ typedef io_cache_t::iterator io_iter_t;
|
|||||||
* details.) EventList is part of the SimulatorController and "outsources"
|
* details.) EventList is part of the SimulatorController and "outsources"
|
||||||
* it's event management.
|
* it's event management.
|
||||||
*/
|
*/
|
||||||
class EventList
|
class EventList {
|
||||||
{
|
private:
|
||||||
private:
|
// TODO: List separation of "critical types"? Hashing/sorted lists? (-> performance!)
|
||||||
// TODO: List separation of "critical types"? Hashing/sorted lists? (-> performance!)
|
bufferlist_t m_BufferList; //!< the storage for events added by exp.
|
||||||
bufferlist_t m_BufferList; //!< the storage for events added by exp.
|
firelist_t m_FireList; //!< the active events (used temporarily)
|
||||||
firelist_t m_FireList; //!< the active events (used temporarily)
|
deletelist_t m_DeleteList; //!< the deleted events (used temporarily)
|
||||||
deletelist_t m_DeleteList; //!< the deleted events (used temporarily)
|
BaseEvent* m_pFired; //!< the recently fired Event-object
|
||||||
BaseEvent* m_pFired; //!< the recently fired Event-object
|
bp_cache_t m_Bp_cache; //!< the storage cache for breakpoint events
|
||||||
bp_cache_t m_Bp_cache; //!< the storage cache for breakpoint events
|
io_cache_t m_Io_cache; //!< the storage cache for port i/o events
|
||||||
io_cache_t m_Io_cache; //!< the storage cache for port i/o events
|
friend bp_iter_t bp_cache_t::makeActive(EventList &ev_list, bp_iter_t idx);
|
||||||
friend bp_iter_t bp_cache_t::makeActive(EventList &ev_list, bp_iter_t idx);
|
friend io_iter_t io_cache_t::makeActive(EventList &ev_list, io_iter_t idx);
|
||||||
friend io_iter_t io_cache_t::makeActive(EventList &ev_list, io_iter_t idx);
|
public:
|
||||||
public:
|
/**
|
||||||
/**
|
* The iterator of this class used to loop through the list of
|
||||||
* The iterator of this class used to loop through the list of
|
* added events. To retrieve an iterator to the first element, call
|
||||||
* added events. To retrieve an iterator to the first element, call
|
* begin(). end() returns the iterator, pointing after the last element.
|
||||||
* begin(). end() returns the iterator, pointing after the last element.
|
* (This behaviour equals the STL iterator in C++.)
|
||||||
* (This behaviour equals the STL iterator in C++.)
|
*/
|
||||||
*/
|
typedef bufferlist_t::iterator iterator;
|
||||||
typedef bufferlist_t::iterator iterator;
|
|
||||||
|
|
||||||
EventList() : m_pFired(NULL) { }
|
EventList() : m_pFired(NULL) { }
|
||||||
~EventList();
|
~EventList();
|
||||||
/**
|
/**
|
||||||
* Adds the specified event object for the given ExperimentFlow to the
|
* Adds the specified event object for the given ExperimentFlow to the
|
||||||
* list of events to be watched for.
|
* list of events to be watched for.
|
||||||
* @param ev pointer to the event object to be added (cannot be \c NULL)
|
* @param ev pointer to the event object to be added (cannot be \c NULL)
|
||||||
* @param pExp the event context (a pointer to the experiment object
|
* @param pExp the event context (a pointer to the experiment object
|
||||||
* which is interested in such events, cannot be \c NULL)
|
* which is interested in such events, cannot be \c NULL)
|
||||||
* @return the id of the added event object, that is ev->getId()
|
* @return the id of the added event object, that is ev->getId()
|
||||||
*/
|
*/
|
||||||
EventId add(BaseEvent* ev, ExperimentFlow* pExp);
|
EventId add(BaseEvent* ev, ExperimentFlow* pExp);
|
||||||
/**
|
/**
|
||||||
* Removes the event based upon the specified \a ev pointer (requires
|
* Removes the event based upon the specified \a ev pointer (requires
|
||||||
* to loop through the whole buffer-list).
|
* to loop through the whole buffer-list).
|
||||||
* @param ev the pointer of the event to be removed; if ev is set to
|
* @param ev the pointer of the event to be removed; if ev is set to
|
||||||
* \c NULL, all events (for \a all experiments) will be
|
* \c NULL, all events (for \a all experiments) will be
|
||||||
* removed
|
* removed
|
||||||
*/
|
*/
|
||||||
void remove(BaseEvent* ev);
|
void remove(BaseEvent* ev);
|
||||||
/**
|
/**
|
||||||
* Behaves like remove(BaseEvent) and additionally updates the provided
|
* Behaves like remove(BaseEvent) and additionally updates the provided
|
||||||
* iteration.
|
* iteration.
|
||||||
* @return the updated iterator which will point to the next element
|
* @return the updated iterator which will point to the next element
|
||||||
*/
|
*/
|
||||||
iterator remove(iterator it);
|
iterator remove(iterator it);
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* Internal implementation of remove(iterator it) that allows
|
* Internal implementation of remove(iterator it) that allows
|
||||||
* to skip the delete-list.
|
* to skip the delete-list.
|
||||||
* @return the updated iterator which will point to the next element
|
* @return the updated iterator which will point to the next element
|
||||||
*/
|
*/
|
||||||
iterator m_remove(iterator it, bool skip_deletelist);
|
iterator m_remove(iterator it, bool skip_deletelist);
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Returns an iterator to the beginning of the internal data structure.
|
* Returns an iterator to the beginning of the internal data structure.
|
||||||
* Don't forget to update the returned iterator when calling one of the
|
* Don't forget to update the returned iterator when calling one of the
|
||||||
* modifying methods like makeActive() or remove(). Therefore you need
|
* modifying methods like makeActive() or remove(). Therefore you need
|
||||||
* to call the iterator-based variants of makeActive() and remove().
|
* to call the iterator-based variants of makeActive() and remove().
|
||||||
* \code
|
* \code
|
||||||
* [X|1|2| ... |n]
|
* [X|1|2| ... |n]
|
||||||
* ^
|
* ^
|
||||||
* \endcode
|
* \endcode
|
||||||
*/
|
*/
|
||||||
iterator begin() { return (m_BufferList.begin()); }
|
iterator begin() { return (m_BufferList.begin()); }
|
||||||
/**
|
/**
|
||||||
* Returns an iterator to the end of the interal data structure.
|
* Returns an iterator to the end of the interal data structure.
|
||||||
* Don't forget to update the returned iterator when calling one of the
|
* Don't forget to update the returned iterator when calling one of the
|
||||||
* modifying methods like makeActive() or remove(). Therefore you need
|
* modifying methods like makeActive() or remove(). Therefore you need
|
||||||
* to call the iterator-based variants of makeActive() and remove().
|
* to call the iterator-based variants of makeActive() and remove().
|
||||||
* \code
|
* \code
|
||||||
* [1|2| ... |n]X
|
* [1|2| ... |n]X
|
||||||
* ^
|
* ^
|
||||||
* \endcode
|
* \endcode
|
||||||
*/
|
*/
|
||||||
iterator end() { return (m_BufferList.end()); }
|
iterator end() { return (m_BufferList.end()); }
|
||||||
/**
|
/**
|
||||||
* Retrieves the event object for the given \a id. The internal data
|
* Retrieves the event object for the given \a id. The internal data
|
||||||
* remains unchanged.
|
* remains unchanged.
|
||||||
* @param id of event to be retrieved.
|
* @param id of event to be retrieved.
|
||||||
* @return pointer to event or \c NULL of \a id could not be found
|
* @return pointer to event or \c NULL of \a id could not be found
|
||||||
*/
|
*/
|
||||||
BaseEvent* getEventFromId(EventId id);
|
BaseEvent* getEventFromId(EventId id);
|
||||||
/**
|
/**
|
||||||
* Removes all events for the specified experiment.
|
* Removes all events for the specified experiment.
|
||||||
* @param flow pointer to experiment context (0 = all experiments)
|
* @param flow pointer to experiment context (0 = all experiments)
|
||||||
*/
|
*/
|
||||||
void remove(ExperimentFlow* flow);
|
void remove(ExperimentFlow* flow);
|
||||||
/**
|
/**
|
||||||
* Retrieves the number of experiments which currently have active
|
* Retrieves the number of experiments which currently have active
|
||||||
* events. This number is trivially equal to the (current) total
|
* events. This number is trivially equal to the (current) total
|
||||||
* number of ExperimentFlow-objects.
|
* number of ExperimentFlow-objects.
|
||||||
* @return number of experiments having active events
|
* @return number of experiments having active events
|
||||||
*/
|
*/
|
||||||
size_t getContextCount() const;
|
size_t getContextCount() const;
|
||||||
/**
|
/**
|
||||||
* Retrieves the total number of buffered events. This doesn't include
|
* Retrieves the total number of buffered events. This doesn't include
|
||||||
* the events in the fire- or delete-list.
|
* 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
|
||||||
* \c getLastFiredDest().
|
* \c getLastFiredDest().
|
||||||
* @return a pointer to the recent event or \c NULL if nothing has been
|
* @return a pointer to the recent event or \c NULL if nothing has been
|
||||||
* triggered so far
|
* triggered so far
|
||||||
*/
|
*/
|
||||||
BaseEvent* getLastFired() { return (m_pFired); }
|
BaseEvent* getLastFired() { return (m_pFired); }
|
||||||
/**
|
/**
|
||||||
* Retrieves the ExperimentFlow-object for the given BaseEvent (it's
|
* Retrieves the ExperimentFlow-object for the given BaseEvent (it's
|
||||||
* \a context).
|
* \a context).
|
||||||
* @param pEv the event object to be looked up
|
* @param pEv the event object to be looked up
|
||||||
* @return a pointer to the context of \a pEv or \c NULL if the
|
* @return a pointer to the context of \a pEv or \c NULL if the
|
||||||
* corresponding context could not be found
|
* corresponding context could not be found
|
||||||
*/
|
*/
|
||||||
ExperimentFlow* getExperimentOf(BaseEvent* pEv);
|
ExperimentFlow* getExperimentOf(BaseEvent* pEv);
|
||||||
/**
|
/**
|
||||||
* Moves the events from the (internal) buffer-list to the fire-list.
|
* Moves the events from the (internal) buffer-list to the fire-list.
|
||||||
* To actually fire the events, call fireActiveEvents().
|
* To actually fire the events, call fireActiveEvents().
|
||||||
* Returns an updated iterator which points to the next element.
|
* Returns an updated iterator which points to the next element.
|
||||||
* @param ev the event to trigger
|
* @param ev the event to trigger
|
||||||
* @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: Improve naming (instead of "makeActive")?
|
* TODO: Improve naming (instead of "makeActive")?
|
||||||
*/
|
*/
|
||||||
iterator makeActive(iterator it);
|
iterator makeActive(iterator it);
|
||||||
/**
|
/**
|
||||||
* Triggers the active events. Each event is triggered if it has not
|
* Triggers the active events. Each event is triggered if it has not
|
||||||
* recently been removed (id est: is not found in the delete-list). See
|
* recently been removed (id est: is not found in the delete-list). See
|
||||||
* 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: Improve naming (instead of "fireActiveEvents")?
|
* TODO: Improve naming (instead of "fireActiveEvents")?
|
||||||
*/
|
*/
|
||||||
void fireActiveEvents();
|
void fireActiveEvents();
|
||||||
/**
|
/**
|
||||||
* Retrieves the BPEvent buffer cache.
|
* Retrieves the BPEvent buffer cache.
|
||||||
* @returns the buffer cache
|
* @returns the buffer cache
|
||||||
*/
|
*/
|
||||||
inline bp_cache_t &getBPBuffer() { return m_Bp_cache; }
|
inline bp_cache_t &getBPBuffer() { return m_Bp_cache; }
|
||||||
/**
|
/**
|
||||||
* Retrieves the IOPortEvent buffer cache.
|
* Retrieves the IOPortEvent buffer cache.
|
||||||
* @returns the buffer cache
|
* @returns the buffer cache
|
||||||
*/
|
*/
|
||||||
inline io_cache_t &getIOBuffer() { return m_Io_cache; }
|
inline io_cache_t &getIOBuffer() { return m_Io_cache; }
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* Add an event to its appropriate cache.
|
* Add an event to its appropriate cache.
|
||||||
* @param the event to add
|
* @param the event to add
|
||||||
*/
|
*/
|
||||||
void addToCaches(BaseEvent *ev);
|
void addToCaches(BaseEvent *ev);
|
||||||
/**
|
/**
|
||||||
* Remove an event from its cache.
|
* Remove an event from its cache.
|
||||||
* @param the event to remove
|
* @param the event to remove
|
||||||
*/
|
*/
|
||||||
void removeFromCaches(BaseEvent *ev);
|
void removeFromCaches(BaseEvent *ev);
|
||||||
/**
|
/**
|
||||||
* Clear the event caches.
|
* Clear the event caches.
|
||||||
*/
|
*/
|
||||||
void clearCaches();
|
void clearCaches();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end-of-namespace: fail
|
} // end-of-namespace: fail
|
||||||
|
|||||||
@ -11,7 +11,7 @@ EventId SimulatorController::addEvent(BaseEvent* ev)
|
|||||||
assert(ev != NULL && "FATAL ERROR: Argument (ptr) cannot be NULL!");
|
assert(ev != NULL && "FATAL ERROR: Argument (ptr) cannot be NULL!");
|
||||||
EventId ret = m_EvList.add(ev, m_Flows.getCurrent());
|
EventId ret = m_EvList.add(ev, m_Flows.getCurrent());
|
||||||
// Call the common postprocessing function:
|
// Call the common postprocessing function:
|
||||||
if (!onEventAddition(ev)) { // If the return value signals "false"...,
|
if (!ev->onEventAddition()) { // If the return value signals "false"...,
|
||||||
m_EvList.remove(ev); // ...skip the addition
|
m_EvList.remove(ev); // ...skip the addition
|
||||||
ret = INVALID_EVENT;
|
ret = INVALID_EVENT;
|
||||||
}
|
}
|
||||||
@ -20,10 +20,12 @@ EventId SimulatorController::addEvent(BaseEvent* ev)
|
|||||||
|
|
||||||
BaseEvent* SimulatorController::waitAny(void)
|
BaseEvent* SimulatorController::waitAny(void)
|
||||||
{
|
{
|
||||||
|
if (!hasEvents())
|
||||||
|
return NULL;
|
||||||
m_Flows.resume();
|
m_Flows.resume();
|
||||||
assert(m_EvList.getLastFired() != NULL &&
|
assert(m_EvList.getLastFired() != NULL &&
|
||||||
"FATAL ERROR: getLastFired() expected to be non-NULL!");
|
"FATAL ERROR: getLastFired() expected to be non-NULL!");
|
||||||
return (m_EvList.getLastFired());
|
return m_EvList.getLastFired();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimulatorController::startup()
|
void SimulatorController::startup()
|
||||||
@ -45,26 +47,21 @@ void SimulatorController::onBreakpointEvent(address_t instrPtr, address_t addres
|
|||||||
{
|
{
|
||||||
assert(false &&
|
assert(false &&
|
||||||
"FIXME: SimulatorController::onBreakpointEvent() has not been tested before");
|
"FIXME: SimulatorController::onBreakpointEvent() has not been tested before");
|
||||||
|
// FIXME: Improve performance!
|
||||||
// FIXME: Improve performance
|
|
||||||
|
|
||||||
// Loop through all events of type BP*Event:
|
// Loop through all events of type BP*Event:
|
||||||
EventList::iterator it = m_EvList.begin();
|
EventList::iterator it = m_EvList.begin();
|
||||||
while (it != m_EvList.end())
|
while (it != m_EvList.end()) {
|
||||||
{
|
|
||||||
BaseEvent* pev = *it;
|
BaseEvent* pev = *it;
|
||||||
BPSingleEvent* pbp; BPRangeEvent* pbpr;
|
BPSingleEvent* pbp; BPRangeEvent* pbpr;
|
||||||
if((pbp = dynamic_cast<BPSingleEvent*>(pev)) && pbp->isMatching(instrPtr, address_space))
|
if ((pbp = dynamic_cast<BPSingleEvent*>(pev)) && pbp->isMatching(instrPtr, address_space)) {
|
||||||
{
|
pbp->setTriggerInstructionPointer(instrPtr);
|
||||||
pbp->setTriggerInstructionPointer(instrPtr);
|
|
||||||
it = m_EvList.makeActive(it);
|
it = m_EvList.makeActive(it);
|
||||||
// "it" has already been set to the next element (by calling
|
// "it" has already been set to the next element (by calling
|
||||||
// makeActive()):
|
// makeActive()):
|
||||||
continue; // -> skip iterator increment
|
continue; // -> skip iterator increment
|
||||||
}
|
} else if ((pbpr = dynamic_cast<BPRangeEvent*>(pev)) &&
|
||||||
else if((pbpr = dynamic_cast<BPRangeEvent*>(pev)) &&
|
pbpr->isMatching(instrPtr, address_space)) {
|
||||||
pbpr->isMatching(instrPtr, address_space))
|
|
||||||
{
|
|
||||||
pbpr->setTriggerInstructionPointer(instrPtr);
|
pbpr->setTriggerInstructionPointer(instrPtr);
|
||||||
it = m_EvList.makeActive(it);
|
it = m_EvList.makeActive(it);
|
||||||
continue; // dito
|
continue; // dito
|
||||||
@ -77,20 +74,17 @@ void SimulatorController::onBreakpointEvent(address_t instrPtr, address_t addres
|
|||||||
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: Improve performance
|
// FIXME: Improve performance!
|
||||||
|
|
||||||
MemAccessEvent::accessType_t accesstype =
|
MemAccessEvent::accessType_t accesstype =
|
||||||
is_write ? MemAccessEvent::MEM_WRITE
|
is_write ? MemAccessEvent::MEM_WRITE
|
||||||
: MemAccessEvent::MEM_READ;
|
: MemAccessEvent::MEM_READ;
|
||||||
|
|
||||||
EventList::iterator it = m_EvList.begin();
|
EventList::iterator it = m_EvList.begin();
|
||||||
while(it != m_EvList.end()) // check for active events
|
while (it != m_EvList.end()) { // check for active events
|
||||||
{
|
|
||||||
BaseEvent* pev = *it;
|
BaseEvent* pev = *it;
|
||||||
MemAccessEvent* ev = dynamic_cast<MemAccessEvent*>(pev);
|
MemAccessEvent* ev = dynamic_cast<MemAccessEvent*>(pev);
|
||||||
// Is this a MemAccessEvent? Correct access type?
|
// Is this a MemAccessEvent? Correct access type?
|
||||||
if(!ev || !ev->isMatching(addr, accesstype))
|
if (!ev || !ev->isMatching(addr, accesstype)) {
|
||||||
{
|
|
||||||
++it;
|
++it;
|
||||||
continue; // skip event activation
|
continue; // skip event activation
|
||||||
}
|
}
|
||||||
@ -106,12 +100,10 @@ void SimulatorController::onMemoryAccessEvent(address_t addr, size_t len,
|
|||||||
void SimulatorController::onInterruptEvent(unsigned interruptNum, bool nmi)
|
void SimulatorController::onInterruptEvent(unsigned interruptNum, bool nmi)
|
||||||
{
|
{
|
||||||
EventList::iterator it = m_EvList.begin();
|
EventList::iterator it = m_EvList.begin();
|
||||||
while(it != m_EvList.end()) // check for active events
|
while (it != m_EvList.end()) { // check for active events
|
||||||
{
|
|
||||||
BaseEvent* pev = *it;
|
BaseEvent* pev = *it;
|
||||||
InterruptEvent* pie = dynamic_cast<InterruptEvent*>(pev);
|
InterruptEvent* pie = dynamic_cast<InterruptEvent*>(pev);
|
||||||
if(!pie || !pie->isMatching(interruptNum))
|
if (!pie || !pie->isMatching(interruptNum)) {
|
||||||
{
|
|
||||||
++it;
|
++it;
|
||||||
continue; // skip event activation
|
continue; // skip event activation
|
||||||
}
|
}
|
||||||
@ -124,55 +116,52 @@ void SimulatorController::onInterruptEvent(unsigned interruptNum, bool nmi)
|
|||||||
|
|
||||||
bool SimulatorController::isSuppressedInterrupt(unsigned interruptNum)
|
bool SimulatorController::isSuppressedInterrupt(unsigned interruptNum)
|
||||||
{
|
{
|
||||||
for(size_t i = 0; i < m_SuppressedInterrupts.size(); i++)
|
for (size_t i = 0; i < m_SuppressedInterrupts.size(); i++)
|
||||||
if((m_SuppressedInterrupts[i] == interruptNum ||
|
if ((m_SuppressedInterrupts[i] == interruptNum ||
|
||||||
m_SuppressedInterrupts[i] == ANY_INTERRUPT) && interruptNum != (unsigned) interrupt_to_fire+32 ){
|
m_SuppressedInterrupts[i] == ANY_INTERRUPT) &&
|
||||||
if((int)interruptNum == interrupt_to_fire+32){
|
interruptNum != (unsigned)interrupt_to_fire + 32) {
|
||||||
|
if ((int)interruptNum == interrupt_to_fire + 32) {
|
||||||
interrupt_to_fire = -1;
|
interrupt_to_fire = -1;
|
||||||
return(true);
|
return true;
|
||||||
}
|
}
|
||||||
return (true);
|
return true;
|
||||||
}
|
}
|
||||||
return (false);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SimulatorController::addSuppressedInterrupt(unsigned interruptNum)
|
bool SimulatorController::addSuppressedInterrupt(unsigned interruptNum)
|
||||||
{
|
{
|
||||||
// Check if already existing:
|
// Check if already existing:
|
||||||
if(isSuppressedInterrupt(interruptNum+32))
|
if (isSuppressedInterrupt(interruptNum+32))
|
||||||
return (false); // already added: nothing to do here
|
return false; // already added: nothing to do here
|
||||||
|
|
||||||
if(interruptNum == ANY_INTERRUPT){
|
if (interruptNum == ANY_INTERRUPT) {
|
||||||
m_SuppressedInterrupts.push_back(interruptNum);
|
m_SuppressedInterrupts.push_back(interruptNum);
|
||||||
return (true);
|
return true;
|
||||||
}else{
|
} else {
|
||||||
m_SuppressedInterrupts.push_back(interruptNum+32);
|
m_SuppressedInterrupts.push_back(interruptNum+32);
|
||||||
return (true);
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SimulatorController::removeSuppressedInterrupt(unsigned interruptNum)
|
bool SimulatorController::removeSuppressedInterrupt(unsigned interruptNum)
|
||||||
{
|
{
|
||||||
for(size_t i = 0; i < m_SuppressedInterrupts.size(); i++)
|
for (size_t i = 0; i < m_SuppressedInterrupts.size(); i++) {
|
||||||
{
|
if (m_SuppressedInterrupts[i] == interruptNum+32 ||
|
||||||
if(m_SuppressedInterrupts[i] == interruptNum+32 || m_SuppressedInterrupts[i] == ANY_INTERRUPT)
|
m_SuppressedInterrupts[i] == ANY_INTERRUPT)
|
||||||
{
|
|
||||||
m_SuppressedInterrupts.erase(m_SuppressedInterrupts.begin() + i);
|
m_SuppressedInterrupts.erase(m_SuppressedInterrupts.begin() + i);
|
||||||
return (true);
|
return true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return (false);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimulatorController::onTrapEvent(unsigned trapNum)
|
void SimulatorController::onTrapEvent(unsigned trapNum)
|
||||||
{
|
{
|
||||||
EventList::iterator it = m_EvList.begin();
|
EventList::iterator it = m_EvList.begin();
|
||||||
while(it != m_EvList.end()) // check for active events
|
while(it != m_EvList.end()) { // check for active events
|
||||||
{
|
|
||||||
BaseEvent* pev = *it;
|
BaseEvent* pev = *it;
|
||||||
TrapEvent* pte = dynamic_cast<TrapEvent*>(pev);
|
TrapEvent* pte = dynamic_cast<TrapEvent*>(pev);
|
||||||
if(!pte || !pte->isMatching(trapNum))
|
if (!pte || !pte->isMatching(trapNum)) {
|
||||||
{
|
|
||||||
++it;
|
++it;
|
||||||
continue; // skip event activation
|
continue; // skip event activation
|
||||||
}
|
}
|
||||||
@ -185,12 +174,10 @@ void SimulatorController::onTrapEvent(unsigned trapNum)
|
|||||||
void SimulatorController::onGuestSystemEvent(char data, unsigned port)
|
void SimulatorController::onGuestSystemEvent(char data, unsigned port)
|
||||||
{
|
{
|
||||||
EventList::iterator it = m_EvList.begin();
|
EventList::iterator it = m_EvList.begin();
|
||||||
while(it != m_EvList.end()) // check for active events
|
while (it != m_EvList.end()) { // check for active events
|
||||||
{
|
|
||||||
BaseEvent* pev = *it;
|
BaseEvent* pev = *it;
|
||||||
GuestEvent* pge = dynamic_cast<GuestEvent*>(pev);
|
GuestEvent* pge = dynamic_cast<GuestEvent*>(pev);
|
||||||
if(pge != NULL)
|
if (pge != NULL) {
|
||||||
{
|
|
||||||
pge->setData(data);
|
pge->setData(data);
|
||||||
pge->setPort(port);
|
pge->setPort(port);
|
||||||
it = m_EvList.makeActive(it);
|
it = m_EvList.makeActive(it);
|
||||||
@ -204,11 +191,9 @@ void SimulatorController::onGuestSystemEvent(char data, unsigned port)
|
|||||||
void SimulatorController::onJumpEvent(bool flagTriggered, unsigned opcode)
|
void SimulatorController::onJumpEvent(bool flagTriggered, unsigned opcode)
|
||||||
{
|
{
|
||||||
EventList::iterator it = m_EvList.begin();
|
EventList::iterator it = m_EvList.begin();
|
||||||
while(it != m_EvList.end()) // check for active events
|
while (it != m_EvList.end()) { // check for active events
|
||||||
{
|
|
||||||
JumpEvent* pje = dynamic_cast<JumpEvent*>(*it);
|
JumpEvent* pje = dynamic_cast<JumpEvent*>(*it);
|
||||||
if(pje != NULL)
|
if (pje != NULL) {
|
||||||
{
|
|
||||||
pje->setOpcode(opcode);
|
pje->setOpcode(opcode);
|
||||||
pje->setFlagTriggered(flagTriggered);
|
pje->setFlagTriggered(flagTriggered);
|
||||||
it = m_EvList.makeActive(it);
|
it = m_EvList.makeActive(it);
|
||||||
@ -238,7 +223,7 @@ void SimulatorController::removeFlow(ExperimentFlow* flow)
|
|||||||
BaseEvent* SimulatorController::addEventAndWait(BaseEvent* ev)
|
BaseEvent* SimulatorController::addEventAndWait(BaseEvent* ev)
|
||||||
{
|
{
|
||||||
addEvent(ev);
|
addEvent(ev);
|
||||||
return (waitAny());
|
return waitAny();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimulatorController::terminate(int exCode)
|
void SimulatorController::terminate(int exCode)
|
||||||
|
|||||||
@ -105,33 +105,6 @@ public:
|
|||||||
* @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(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(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(BaseEvent* pev) { }
|
|
||||||
/* ********************************************************************
|
/* ********************************************************************
|
||||||
* Simulator Controller & Access API:
|
* Simulator Controller & Access API:
|
||||||
* ********************************************************************/
|
* ********************************************************************/
|
||||||
@ -236,10 +209,8 @@ public:
|
|||||||
/**
|
/**
|
||||||
* 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 event.
|
* one of those events occour, waitAny() will return the id of that event.
|
||||||
* @return the previously occurred event
|
* @return the previously occurred event, or \c NULL if there are no
|
||||||
*
|
* events to wait for
|
||||||
* FIXME: Maybe this should return immediately if there are not events?
|
|
||||||
* (additional parameter flag?)
|
|
||||||
*/
|
*/
|
||||||
BaseEvent* waitAny();
|
BaseEvent* waitAny();
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -209,7 +209,7 @@ void BochsController::fireInterruptDone()
|
|||||||
m_Flows.toggle(m_CurrFlow);
|
m_Flows.toggle(m_CurrFlow);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BochsController::m_onTimerTrigger(void* thisPtr)
|
void BochsController::onTimerTrigger(void* thisPtr)
|
||||||
{
|
{
|
||||||
// FIXME: The timer logic can be modified to use only one timer in Bochs.
|
// FIXME: The timer logic can be modified to use only one timer in Bochs.
|
||||||
// (For now, this suffices.)
|
// (For now, this suffices.)
|
||||||
@ -225,57 +225,6 @@ void BochsController::m_onTimerTrigger(void* thisPtr)
|
|||||||
simulator.m_EvList.fireActiveEvents();
|
simulator.m_EvList.fireActiveEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
timer_id_t BochsController::m_registerTimer(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(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(BaseEvent* pev)
|
|
||||||
{
|
|
||||||
TimerEvent* tmev;
|
|
||||||
// Register the timer event in the Bochs simulator:
|
|
||||||
if ((tmev = dynamic_cast<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(BaseEvent* pev)
|
|
||||||
{
|
|
||||||
TimerEvent* tmev;
|
|
||||||
// Unregister the time event:
|
|
||||||
if ((tmev = dynamic_cast<TimerEvent*>(pev)) != NULL) {
|
|
||||||
m_unregisterTimer(tmev);
|
|
||||||
}
|
|
||||||
// Note: Maybe more stuff to do here for other event types.
|
|
||||||
}
|
|
||||||
|
|
||||||
void BochsController::onEventTrigger(BaseEvent* pev)
|
|
||||||
{
|
|
||||||
TimerEvent* tmev;
|
|
||||||
// Unregister the time event, if once-flag is true:
|
|
||||||
if ((tmev = dynamic_cast<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.
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string& BochsController::getMnemonic() const
|
const std::string& BochsController::getMnemonic() const
|
||||||
{
|
{
|
||||||
static std::string str;
|
static std::string str;
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "FailBochsGlobals.hpp"
|
#include "FailBochsGlobals.hpp"
|
||||||
|
#include "BochsEvents.hpp"
|
||||||
|
|
||||||
#include "../SimulatorController.hpp"
|
#include "../SimulatorController.hpp"
|
||||||
#include "../Event.hpp"
|
#include "../Event.hpp"
|
||||||
@ -34,40 +35,6 @@ private:
|
|||||||
unsigned m_Counter; //! current instr-ptr counter
|
unsigned m_Counter; //! current instr-ptr counter
|
||||||
std::ostream* m_pDest; //! debug output object (defaults to \c std::cout)
|
std::ostream* m_pDest; //! debug output object (defaults to \c std::cout)
|
||||||
#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(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(TimerEvent* pev);
|
|
||||||
public:
|
public:
|
||||||
// Initialize the controller.
|
// Initialize the controller.
|
||||||
BochsController();
|
BochsController();
|
||||||
@ -81,7 +48,8 @@ public:
|
|||||||
* @param instrPtr the new instruction pointer
|
* @param instrPtr the new instruction pointer
|
||||||
* @param address_space the address space the CPU is currently in
|
* @param address_space the address space the CPU is currently in
|
||||||
*/
|
*/
|
||||||
void onInstrPtrChanged(address_t instrPtr, address_t address_space, BX_CPU_C *context, bxICacheEntry_c *cache_entry);
|
void onInstrPtrChanged(address_t instrPtr, address_t address_space, BX_CPU_C *context,
|
||||||
|
bxICacheEntry_c *cache_entry);
|
||||||
/**
|
/**
|
||||||
* I/O port communication handler. This method is called (from
|
* I/O port communication handler. This method is called (from
|
||||||
* the IOPortCom aspect) every time when Bochs performs a port I/O operation.
|
* the IOPortCom aspect) every time when Bochs performs a port I/O operation.
|
||||||
@ -91,31 +59,20 @@ public:
|
|||||||
*/
|
*/
|
||||||
void onIOPortEvent(unsigned char data, unsigned port, bool out);
|
void onIOPortEvent(unsigned char data, unsigned port, bool out);
|
||||||
/**
|
/**
|
||||||
* This method is called when an experiment flow adds a new event by
|
* Static internal event handler for TimerEvents. This static function is
|
||||||
* calling \c simulator.addEvent(pev) or \c simulator.addEventAndWait(pev).
|
* called when a previously registered (Bochs) timer triggers. This function
|
||||||
* More specifically, the event will be added to the event-list first
|
* searches for the provided TimerEvent object within the EventList and
|
||||||
* (buffer-list, to be precise) and then this event handler is called.
|
* fires such an event by calling \c fireActiveEvents().
|
||||||
* @param pev the event which has been added
|
* @param thisPtr a pointer to the TimerEvent-object triggered
|
||||||
* @return You should return \c true to continue and \c false to prevent
|
*
|
||||||
* the addition of the event \a pev.
|
* 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 \c TimerEvent as the initial step
|
||||||
|
* in your experiment code and wait for it (\c addEventAndWait()).
|
||||||
*/
|
*/
|
||||||
bool onEventAddition(BaseEvent* pev);
|
static void onTimerTrigger(void *thisPtr);
|
||||||
/**
|
|
||||||
* 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(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(BaseEvent* pev);
|
|
||||||
/* ********************************************************************
|
/* ********************************************************************
|
||||||
* Simulator Controller & Access API:
|
* Simulator Controller & Access API:
|
||||||
* ********************************************************************/
|
* ********************************************************************/
|
||||||
|
|||||||
36
src/core/sal/bochs/BochsEvents.cc
Normal file
36
src/core/sal/bochs/BochsEvents.cc
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#include "BochsEvents.hpp"
|
||||||
|
#include "../SALInst.hpp"
|
||||||
|
|
||||||
|
namespace fail {
|
||||||
|
|
||||||
|
bool TimerEvent::onEventAddition()
|
||||||
|
{
|
||||||
|
// Register the timer event in the Bochs simulator:
|
||||||
|
setId(m_registerTimer(this));
|
||||||
|
if(getId() == -1)
|
||||||
|
return false; // unable to register the timer (error in Bochs' function call)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TimerEvent::onEventDeletion()
|
||||||
|
{
|
||||||
|
// Unregister the time event:
|
||||||
|
m_unregisterTimer(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
timer_id_t TimerEvent::m_registerTimer(TimerEvent* pev)
|
||||||
|
{
|
||||||
|
assert(pev != NULL && "FATAL ERROR: TimerEvent object ptr cannot be NULL!");
|
||||||
|
return static_cast<timer_id_t>(
|
||||||
|
bx_pc_system.register_timer(pev, BochsController::onTimerTrigger, pev->getTimeout(),
|
||||||
|
false, 1/*start immediately*/, "Fail*: BochsController"/*name*/));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TimerEvent::m_unregisterTimer(TimerEvent* pev)
|
||||||
|
{
|
||||||
|
assert(pev != NULL && "FATAL ERROR: TimerEvent object ptr cannot be NULL!");
|
||||||
|
bx_pc_system.deactivate_timer(static_cast<unsigned>(pev->getId()));
|
||||||
|
return bx_pc_system.unregisterTimer(static_cast<unsigned>(pev->getId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end-of-namespace: fail
|
||||||
78
src/core/sal/bochs/BochsEvents.hpp
Normal file
78
src/core/sal/bochs/BochsEvents.hpp
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
#ifndef __BOCHS_EVENTS_HPP__
|
||||||
|
#define __BOCHS_EVENTS_HPP__
|
||||||
|
|
||||||
|
#include "../Event.hpp"
|
||||||
|
|
||||||
|
#include "BochsController.hpp"
|
||||||
|
|
||||||
|
namespace fail {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \class TimerEvent
|
||||||
|
* Concrete TimerEvent implementation of GenericTimerEvent for the Bochs
|
||||||
|
* simulator backend.
|
||||||
|
*/
|
||||||
|
class TimerEvent : public GenericTimerEvent {
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* 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 errors, -1 is returned
|
||||||
|
* (e.g. because a timer with the same id is already existing)
|
||||||
|
*/
|
||||||
|
static timer_id_t m_registerTimer(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
|
||||||
|
*/
|
||||||
|
static bool m_unregisterTimer(TimerEvent* pev);
|
||||||
|
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 FailBochs.
|
||||||
|
* @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
|
||||||
|
* @see SimulatorController::addEvent
|
||||||
|
*/
|
||||||
|
TimerEvent(unsigned timeout)
|
||||||
|
: GenericTimerEvent(timeout) { }
|
||||||
|
~TimerEvent() { onEventDeletion(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
* @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();
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
virtual void onEventDeletion();
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
void onEventTrigger() { onEventDeletion(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end-of-namespace: fail
|
||||||
|
|
||||||
|
#endif // __BOCHS_EVENTS_HPP__
|
||||||
Reference in New Issue
Block a user