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:
adrian
2012-05-17 15:36:29 +00:00
parent 1e16f72fe2
commit 34fbb932fd
9 changed files with 292 additions and 57 deletions

View File

@ -1,7 +1,3 @@
// Author: Adrian Böckenkamp
// Date: 23.01.2012
#include "SimulatorController.hpp"
#include "SALInst.hpp"
#include "../controller/Event.hpp"
@ -14,7 +10,14 @@ ConcreteSimulatorController simulator;
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)
@ -30,9 +33,6 @@ void SimulatorController::startup()
// Some greetings to the user:
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:
initExperiments();
}
@ -47,11 +47,11 @@ void SimulatorController::onBreakpointEvent(address_t instrPtr)
assert(false &&
"FIXME: SimulatorController::onBreakpointEvent() has not been tested before");
// FIXME: Performanz verbessern
// FIXME: Improve performance
// Loop through all events of type BP*Event:
fi::EventList::iterator it = m_EvList.begin();
while(it != m_EvList.end())
while (it != m_EvList.end())
{
fi::BaseEvent* pev = *it;
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,
bool is_write, address_t instrPtr)
{
// FIXME: Performanz verbessern (falls Iteratorlogik bleibt, wäre
// ein "hasMoreOf(typeid(MemEvents))" denkbar...
// FIXME: Improve performance
fi::MemAccessEvent::accessType_t accesstype =
is_write ? fi::MemAccessEvent::MEM_WRITE

View File

@ -119,8 +119,35 @@ class SimulatorController
* @param opcode the opcode of the conrecete jump instruction
*/
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.
@ -186,7 +213,7 @@ class SimulatorController
*/
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
@ -204,7 +231,8 @@ class SimulatorController
* Add event ev to the event management. This causes the event to be
* active.
* @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);
/**
@ -221,9 +249,11 @@ class SimulatorController
void clearEvents(fi::ExperimentFlow *flow = 0) { m_EvList.remove(flow); }
/**
* 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
*
* FIXME: Maybe this should return immediately if there are not events?
* (additional parameter flag?)
*/
fi::BaseEvent* waitAny();
/**
@ -232,9 +262,21 @@ class SimulatorController
* @param ev the event pointer to be added
* @return the pointer of the occurred event (it is not guaranteed that
* 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);
/**
* 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.
* @return the Experiment-Data from the Job-Server.

View File

@ -1,7 +1,10 @@
#include <sstream>
#include "BochsController.hpp"
#include "BochsMemory.hpp"
#include "BochsRegister.hpp"
#include "../Register.hpp"
#include "../SALInst.hpp"
namespace sal
{
@ -94,8 +97,7 @@ void BochsController::onInstrPtrChanged(address_t instrPtr)
fi::EventList::iterator it = m_EvList.begin();
while(it != m_EvList.end())
{
// FIXME: Performance verbessern (dazu muss entsprechend auch die Speicherung
// in EventList(.cc|.hpp) angepasst bzw. verbessert werden).
// FIXME: Maybe we need to improve the performance of this check.
fi::BPEvent* pEvBreakpt = dynamic_cast<fi::BPEvent*>(*it);
if(pEvBreakpt && (instrPtr == pEvBreakpt->getWatchInstructionPointer() ||
pEvBreakpt->getWatchInstructionPointer() == fi::ANY_ADDR))
@ -184,4 +186,71 @@ void BochsController::fireInterruptDone()
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

View File

@ -18,6 +18,7 @@
#include "../../../bochs/cpu/cpu.h"
#include "../../../bochs/config.h"
#include "../../../bochs/iodev/iodev.h"
#include "../../../bochs/pc_system.h"
using namespace std;
@ -34,31 +35,87 @@ namespace sal
class BochsController : public SimulatorController
{
private:
/**
* stores the current flow for save/restore-operations
*/
fi::ExperimentFlow* m_CurrFlow;
fi::ExperimentFlow* m_CurrFlow; //!< Stores the current flow for save/restore-operations
#ifdef DEBUG
unsigned m_Regularity;
unsigned m_Counter;
std::ostream* m_pDest;
#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:
// Initialize the controller.
BochsController();
~BochsController();
/* ********************************************************************
* Standard Event Handler API (SEH-API):
* Standard Event Handler API:
* ********************************************************************/
/**
* Instruction pointer modification handler. This method is called
* (from the Breakpoints aspect) every time when the Bochs-internal IP
* changes.
* @param instrPtr
* Instruction pointer modification handler. This method is called (from
* the Breakpoints aspect) every time when the Bochs-internal IP changes.
* @param instrPtr the new instruction pointer
*/
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.