diff --git a/src/core/sal/BufferCache.cc b/src/core/sal/BufferCache.cc index 0ef94a85..b732fb0f 100644 --- a/src/core/sal/BufferCache.cc +++ b/src/core/sal/BufferCache.cc @@ -1,16 +1,15 @@ #include #include #include "BufferCache.hpp" -#include "Event.hpp" -#include "EventManager.hpp" +#include "Listener.hpp" +#include "ListenerManager.hpp" namespace fail { template -typename BufferCache::iterator BufferCache::makeActive(EventManager &ev_list, BufferCache::iterator idx) +typename BufferCache::iterator BufferCache::makeActive(ListenerManager &ev_list, BufferCache::iterator idx) { - assert(idx != end() && - "FATAL ERROR: Index larger than cache!"); + assert(idx != end() && "FATAL ERROR: Index larger than cache!"); T ev = *idx; assert(ev && "FATAL ERROR: Object pointer cannot be NULL!"); ev->decreaseCounter(); @@ -20,14 +19,14 @@ typename BufferCache::iterator BufferCache::makeActive(EventManager &ev_li ev->resetCounter(); // Note: This is the one and only situation in which remove() should NOT // store the removed item in the delete-list. - EventManager::iterator it = std::find(ev_list.begin(), ev_list.end(), static_cast(ev)); - ev_list.m_remove(it, true); // remove event from buffer-list + ListenerManager::iterator it = std::find(ev_list.begin(), ev_list.end(), static_cast(ev)); + ev_list.m_remove(it, true); // remove listener from buffer-list ev_list.m_FireList.push_back(ev); return erase(idx); } // Declare here whatever instances of the template you are going to use: -template class BufferCache; -template class BufferCache; +template class BufferCache; +template class BufferCache; } // end-of-namespace: fail diff --git a/src/core/sal/BufferCache.hpp b/src/core/sal/BufferCache.hpp index 17041646..7f8f814c 100644 --- a/src/core/sal/BufferCache.hpp +++ b/src/core/sal/BufferCache.hpp @@ -6,7 +6,7 @@ namespace fail { -class EventManager; +class ListenerManager; /** * \class BufferCache @@ -14,19 +14,19 @@ class EventManager; * \brief A simple dynamic array * * This class is intended to serve as a kind of cache for the - * untyped and therefore quite slow event handling mechanism of Fail*. + * untyped and therefore quite slow listener handling mechanism of Fail*. */ template class BufferCache { public: /** - * The list type inherent to this class. Like bufferlist_t in EventManager.hpp, + * The list type inherent to this class. Like bufferlist_t in ListenerManager.hpp, * but dynamically typed. */ typedef std::list cachelist_t; /** * The iterator of this class used to loop through the list of - * added events. To retrieve an iterator to the first element, call + * added listeners. To retrieve an iterator to the first element, call * begin(). end() returns the iterator, pointing after the last element. * (This behaviour equals the STL iterator in C++.) */ @@ -79,14 +79,14 @@ public: */ inline iterator end() { return m_Buffer.end(); } /** - * Acts as a replacement for EventManager::makeActive, manipulating - * the buffer cache exclusively. EventManager::fireActiveEvents needs - * to be called to fire the active events (see there). - * This method is declared as a friend method in EventManager. - * @param idx the index of the event to trigger + * Acts as a replacement for ListenerManager::makeActive, manipulating + * the buffer cache exclusively. ListenerManager::triggerActiveListeners needs + * to be called to fire the active listeners (see there). + * This method is declared as a friend method in ListenerManager. + * @param idx the index of the listener to trigger * @returns an updated index which can be used to update a loop counter */ - iterator makeActive(EventManager &ev_list, iterator idx); + iterator makeActive(ListenerManager &ev_list, iterator idx); }; } // end-of-namespace: fail diff --git a/src/core/sal/CMakeLists.txt b/src/core/sal/CMakeLists.txt index 5de6337d..185a07c5 100644 --- a/src/core/sal/CMakeLists.txt +++ b/src/core/sal/CMakeLists.txt @@ -1,19 +1,19 @@ if(BUILD_BOCHS) set(SRCS BufferCache.cc - Event.cc - EventManager.cc + Listener.cc + ListenerManager.cc Memory.cc Register.cc SimulatorController.cc bochs/BochsController.cc - bochs/BochsEvents.cc + bochs/BochsListener.cc ) else() set(SRCS BufferCache.cc - Event.cc - EventManager.cc + Listener.cc + ListenerManager.cc Memory.cc Register.cc SimulatorController.cc diff --git a/src/core/sal/EventManager.cc b/src/core/sal/EventManager.cc deleted file mode 100644 index 31f9f115..00000000 --- a/src/core/sal/EventManager.cc +++ /dev/null @@ -1,196 +0,0 @@ -#include - -#include "EventManager.hpp" -#include "SALInst.hpp" - -namespace fail { - -void EventManager::addToCaches(BaseEvent *ev) -{ - BPEvent *bps_ev; - if ((bps_ev = dynamic_cast(ev)) != NULL) - m_Bp_cache.add(bps_ev); - - IOPortEvent *io_ev; - if ((io_ev = dynamic_cast(ev)) != NULL) - m_Io_cache.add(io_ev); -} - -void EventManager::removeFromCaches(BaseEvent *ev) -{ - BPEvent *bpr_ev; - if ((bpr_ev = dynamic_cast(ev)) != NULL) - m_Bp_cache.remove(bpr_ev); - - IOPortEvent *io_ev; - if ((io_ev = dynamic_cast(ev)) != NULL) - m_Io_cache.remove(io_ev); -} - -void EventManager::clearCaches() -{ - m_Bp_cache.clear(); - m_Io_cache.clear(); -} - -void EventManager::add(BaseEvent* ev, ExperimentFlow* pExp) -{ - assert(ev != NULL && "FATAL ERROR: Event (of base type BaseEvent*) cannot be NULL!"); - // a zero counter does not make sense - assert(ev->getCounter() != 0); - ev->setParent(pExp); // event is linked to experiment flow - - addToCaches(ev); - m_BufferList.push_back(ev); -} - -void EventManager::remove(BaseEvent* ev) -{ - // possible cases: - // - ev == 0 -> remove all events - // * clear m_BufferList - // * copy m_FireList to m_DeleteList - if (ev == 0) { - for (bufferlist_t::iterator it = m_BufferList.begin(); it != m_BufferList.end(); it++) - (*it)->onEventDeletion(); - for (firelist_t::iterator it = m_FireList.begin(); it != m_FireList.end(); it++) - (*it)->onEventDeletion(); - clearCaches(); - m_BufferList.clear(); - // all remaining active events must not fire anymore - m_DeleteList.insert(m_DeleteList.end(), m_FireList.begin(), m_FireList.end()); - - // - ev != 0 -> remove single event - // * find/remove ev in m_BufferList - // * if ev in m_FireList, copy to m_DeleteList - } else { - ev->onEventDeletion(); - - removeFromCaches(ev); - m_BufferList.remove(ev); - firelist_t::const_iterator it = - std::find(m_FireList.begin(), m_FireList.end(), ev); - if (it != m_FireList.end()) { - m_DeleteList.push_back(ev); - } - } -} - -EventManager::iterator EventManager::remove(iterator it) -{ - return m_remove(it, false); -} - -EventManager::iterator EventManager::m_remove(iterator it, bool 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. Therefore we only need to call the simulator's - // event handler (onEventDeletion), if m_remove is called with the primary intention - // to *delete* (not "move") an event. - (*it)->onEventDeletion(); - m_DeleteList.push_back(*it); - - // Cached events have their own BufferCache::makeActive() implementation, which - // calls this method and afterwards erase() in the cache class. This is why, when - // called from any kind of makeActive() method, it is unnecessary to call - // BufferCache::remove() from m_remove(). - - // NOTE: in case the semantics of skip_deletelist change, please adapt the following lines - removeFromCaches(*it); - } - - return m_BufferList.erase(it); -} - -void EventManager::remove(ExperimentFlow* flow) -{ - // all events? - if (flow == 0) { - for (bufferlist_t::iterator it = m_BufferList.begin(); - it != m_BufferList.end(); it++) - (*it)->onEventDeletion(); // invoke event handler - clearCaches(); - m_BufferList.clear(); - } else { // remove all events corresponding to a specific experiment ("flow"): - for (bufferlist_t::iterator it = m_BufferList.begin(); - it != m_BufferList.end(); ) { - if ((*it)->getParent() == flow) { - (*it)->onEventDeletion(); - it = m_BufferList.erase(it); - } else { - ++it; - } - } - } - // events that just fired / are about to fire ... - for (firelist_t::const_iterator it = m_FireList.begin(); - it != m_FireList.end(); it++) { - if (std::find(m_DeleteList.begin(), m_DeleteList.end(), *it) - != m_DeleteList.end()) { - continue; // (already in the delete-list? -> skip!) - } - // ... need to be pushed into m_DeleteList, as we're currently - // iterating over m_FireList in fireActiveEvents() and cannot modify it - if (flow == 0 || (*it)->getParent() == flow) { - (*it)->onEventDeletion(); - m_DeleteList.push_back(*it); - } - } -} - -EventManager::~EventManager() -{ - // nothing to do here yet -} - -EventManager::iterator EventManager::makeActive(iterator it) -{ - assert(it != m_BufferList.end() && - "FATAL ERROR: Iterator has already reached the end!"); - BaseEvent* ev = *it; - assert(ev && "FATAL ERROR: Event object pointer cannot be NULL!"); - ev->decreaseCounter(); - if (ev->getCounter() > 0) { - return ++it; - } - ev->resetCounter(); - // Note: This is the one and only situation in which remove() should NOT - // store the removed item in the delete-list. - iterator it_next = m_remove(it, true); // remove event from buffer-list - m_FireList.push_back(ev); - return it_next; -} - -void EventManager::fireActiveEvents() -{ - for (firelist_t::iterator it = m_FireList.begin(); - it != m_FireList.end(); it++) { - if (std::find(m_DeleteList.begin(), m_DeleteList.end(), *it) - == m_DeleteList.end()) { // not found in delete-list? - 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): - m_pFired->onEventTrigger(); - ExperimentFlow* pFlow = m_pFired->getParent(); - assert(pFlow && "FATAL ERROR: The event has no parent experiment (owner)!"); - simulator.m_Flows.toggle(pFlow); - } - } - m_FireList.clear(); - m_DeleteList.clear(); - // Note: Do NOT call any event handlers here! -} - -size_t EventManager::getContextCount() const -{ - std::set uniqueFlows; // count unique ExperimentFlow-ptr - for (bufferlist_t::const_iterator it = m_BufferList.begin(); - it != m_BufferList.end(); it++) - uniqueFlows.insert((*it)->getParent()); - - return uniqueFlows.size(); -} - -} // end-of-namespace: fail diff --git a/src/core/sal/EventManager.hpp b/src/core/sal/EventManager.hpp deleted file mode 100644 index 01ee3695..00000000 --- a/src/core/sal/EventManager.hpp +++ /dev/null @@ -1,222 +0,0 @@ -#ifndef __EVENT_MANAGER_HPP__ - #define __EVENT_MANAGER_HPP__ - -#include -#include -#include -#include - -#include "Event.hpp" -#include "BufferCache.hpp" - -namespace fail { - -class ExperimentFlow; - -/** - * Buffer-list for a specific experiment; acts as a simple storage container - * for events to watch for: - */ -typedef std::list bufferlist_t; -/** - * List of events that match the current simulator event; these events will - * be triggered next (the list is used temporarily). - */ -typedef std::vector firelist_t; -/** - * List of events that have been deleted during a toggled experiment flow while - * triggering the events in the fire-list. This list is used to skip already - * deleted events (therefore it is used temporarily either). - */ -typedef std::vector deletelist_t; - -/** - * Cache classes for the most commonly used types of events, utilising static typing. - * Apart from that, they work like bufferlist_t. - */ -typedef BufferCache bp_cache_t; -typedef bp_cache_t::iterator bp_iter_t; -typedef BufferCache io_cache_t; -typedef io_cache_t::iterator io_iter_t; -/** - * \class EventManager - * - * \brief This class manages the events of the Fail* implementation. - * - * If a event is triggered, the internal data structure will be updated (id est, - * the event will be removed from the so called buffer-list and added to the - * fire-list). Additionally, if an experiment-flow deletes an "active" event - * which is currently stored in the fire-list, the event (to be removed) will - * be added to a -so called- delete-list. This ensures to prevent triggering - * "active" events which have already been deleted by a previous experiment - * flow. (See makeActive() and fireActiveEvent() for implementation specific - * details.) EventManager is part of the SimulatorController and "outsources" - * it's event management. - */ -class EventManager { -private: - // TODO: List separation of "critical types"? Hashing/sorted lists? (-> performance!) - bufferlist_t m_BufferList; //!< the storage for events added by exp. - firelist_t m_FireList; //!< the active events (used temporarily) - deletelist_t m_DeleteList; //!< the deleted events (used temporarily) - BaseEvent* m_pFired; //!< the recently fired Event-object - 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 - friend bp_iter_t bp_cache_t::makeActive(EventManager &ev_list, bp_iter_t idx); - friend io_iter_t io_cache_t::makeActive(EventManager &ev_list, io_iter_t idx); -public: - /** - * The iterator of this class used to loop through the list of - * added events. To retrieve an iterator to the first element, call - * begin(). end() returns the iterator, pointing after the last element. - * (This behaviour equals the STL iterator in C++.) - */ - typedef bufferlist_t::iterator iterator; - - EventManager() : m_pFired(NULL) { } - ~EventManager(); - /** - * Adds the specified event object for the given ExperimentFlow to the - * list of events to be watched for. - * @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 - * which is interested in such events, cannot be \c NULL) - * @return the id of the added event object, that is ev->getId() - */ - void add(BaseEvent* ev, ExperimentFlow* pExp); - /** - * Removes the event based upon the specified \a ev pointer (requires - * to loop through the whole buffer-list). - * @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 - * removed - */ - void remove(BaseEvent* ev); - /** - * Behaves like remove(BaseEvent*) and additionally updates the provided - * iterator. - * @param it the iterator pointing to the Event object to be removed - * @return the updated iterator which will point to the next element - */ - iterator remove(iterator it); -private: - /** - * Internal implementation of remove(iterator it) that allows - * to skip the delete-list. - * @param it the iterator pointing to the Event object to be removed - * @param skip_deletelist \c true to skip the deletion of the Event object - * or \false to behave like \c remove(iterator) - * @return the updated iterator which will point to the next element - */ - iterator m_remove(iterator it, bool skip_deletelist); -public: - /** - * Returns an iterator to the beginning of the internal data structure. - * Don't forget to update the returned iterator when calling one of the - * modifying methods like makeActive() or remove(). Therefore you need - * to call the iterator-based variants of makeActive() and remove(). - * \code - * [X|1|2| ... |n] - * ^ - * \endcode - * @return iterator to the beginning - */ - iterator begin() { return (m_BufferList.begin()); } - /** - * Returns an iterator to the end of the interal data structure. - * Don't forget to update the returned iterator when calling one of the - * modifying methods like makeActive() or remove(). Therefore you need - * to call the iterator-based variants of makeActive() and remove(). - * \code - * [1|2| ... |n]X - * ^ - * \endcode - * @return iterator to the end - */ - iterator end() { return (m_BufferList.end()); } - /** - * Removes all events for the specified experiment. - * @param flow pointer to experiment context (0 = all experiments) - */ - void remove(ExperimentFlow* flow); - /** - * Retrieves the number of experiments which currently have active - * events. This number is trivially equal to the (current) total - * number of ExperimentFlow-objects. - * @return number of experiments having active events - */ - size_t getContextCount() const; - /** - * Retrieves the total number of buffered events. This doesn't include - * the events in the fire- or delete-list. - * @return the total event count (for all flows) - */ - size_t getEventCount() const { return m_BufferList.size(); } - /** - * Retrieves the recently triggered event object. To map this object to - * it's context (id est, the related ExerimentFlow), use - * \c getLastFiredDest(). - * @return a pointer to the recent event or \c NULL if nothing has been - * triggered so far - */ - BaseEvent* getLastFired() { return (m_pFired); } - /** - * Retrieves the ExperimentFlow-object for the given BaseEvent (it's - * \a context). - * @param pEv the event object to be looked up - * @return a pointer to the context of \a pEv or \c NULL if the - * corresponding context could not be found - */ - ExperimentFlow* getExperimentOf(BaseEvent* pEv); - /** - * Moves the events from the (internal) buffer-list to the fire-list. - * To actually fire the events, call fireActiveEvents(). - * Returns an updated iterator which points to the next element. - * @param ev the event to trigger - * @return returns the updated iteration, pointing to the next element - * after makeActive returns, "it" is invalid, so the returned - * iterator should be used to continue the iteration - * - * TODO: Improve naming (instead of "makeActive")? - */ - iterator makeActive(iterator it); - /** - * 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 - * makeActive() for more details. The recently triggered event can be - * retrieved by calling \a getLastFired(). After all events have been - * triggered, the (internal) fire- and delete-list will be cleared. - * - * TODO: Improve naming (instead of "fireActiveEvents")? - */ - void fireActiveEvents(); - /** - * Retrieves the BPEvent buffer cache. - * @returns the buffer cache - */ - inline bp_cache_t &getBPBuffer() { return m_Bp_cache; } - /** - * Retrieves the IOPortEvent buffer cache. - * @returns the buffer cache - */ - inline io_cache_t &getIOBuffer() { return m_Io_cache; } -private: - /** - * Add an event to its appropriate cache. - * @param the event to add - */ - void addToCaches(BaseEvent *ev); - /** - * Remove an event from its cache. - * @param the event to remove - */ - void removeFromCaches(BaseEvent *ev); - /** - * Clear the event caches. - */ - void clearCaches(); -}; - -} // end-of-namespace: fail - -#endif // __EVENT_MANAGER_HPP__ diff --git a/src/core/sal/Event.cc b/src/core/sal/Listener.cc similarity index 68% rename from src/core/sal/Event.cc rename to src/core/sal/Listener.cc index f2011a4d..e3a9a94a 100644 --- a/src/core/sal/Event.cc +++ b/src/core/sal/Listener.cc @@ -1,9 +1,9 @@ -#include "Event.hpp" +#include "Listener.hpp" #include "SALInst.hpp" namespace fail { -bool TroubleEvent::isMatching(unsigned troubleNum) const +bool TroubleListener::isMatching(unsigned troubleNum) const { for (unsigned i = 0; i < m_WatchNumbers.size(); i++) { if (m_WatchNumbers[i] == troubleNum || @@ -13,7 +13,7 @@ bool TroubleEvent::isMatching(unsigned troubleNum) const return false; } -bool TroubleEvent::removeWatchNumber(unsigned troubleNum) +bool TroubleListener::removeWatchNumber(unsigned troubleNum) { for (unsigned i = 0; i < m_WatchNumbers.size(); i++) { if (m_WatchNumbers[i] == troubleNum) { @@ -24,7 +24,7 @@ bool TroubleEvent::removeWatchNumber(unsigned troubleNum) return false; } -bool TroubleEvent::addWatchNumber(unsigned troubleNumber) +bool TroubleListener::addWatchNumber(unsigned troubleNumber) { for (unsigned i = 0; i < m_WatchNumbers.size(); i++) { if (m_WatchNumbers[i] == troubleNumber) @@ -34,7 +34,7 @@ bool TroubleEvent::addWatchNumber(unsigned troubleNumber) return true; } -bool MemAccessEvent::isMatching(address_t addr, accessType_t accesstype) const +bool MemAccessListener::isMatching(address_t addr, accessType_t accesstype) const { if (!(m_WatchType & accesstype)) return false; @@ -44,20 +44,20 @@ bool MemAccessEvent::isMatching(address_t addr, accessType_t accesstype) const return true; } -bool BPEvent::aspaceIsMatching(address_t aspace) const +bool BPListener::aspaceIsMatching(address_t aspace) const { if (m_CR3 == ANY_ADDR || m_CR3 == aspace) return true; return false; } -void BPRangeEvent::setWatchInstructionPointerRange(address_t start, address_t end) +void BPRangeListener::setWatchInstructionPointerRange(address_t start, address_t end) { m_WatchStartAddr = start; m_WatchEndAddr = end; } -bool BPRangeEvent::isMatching(address_t addr, address_t aspace) const +bool BPRangeListener::isMatching(address_t addr, address_t aspace) const { if (!aspaceIsMatching(aspace)) return false; @@ -67,7 +67,7 @@ bool BPRangeEvent::isMatching(address_t addr, address_t aspace) const return true; } -bool BPSingleEvent::isMatching(address_t addr, address_t aspace) const +bool BPSingleListener::isMatching(address_t addr, address_t aspace) const { if (aspaceIsMatching(aspace)) { if (m_WatchInstrPtr == ANY_ADDR || m_WatchInstrPtr == addr) diff --git a/src/core/sal/Event.hpp b/src/core/sal/Listener.hpp similarity index 55% rename from src/core/sal/Event.hpp rename to src/core/sal/Listener.hpp index 64f74bea..f1293ab8 100644 --- a/src/core/sal/Event.hpp +++ b/src/core/sal/Listener.hpp @@ -1,5 +1,5 @@ -#ifndef __EVENT_HPP__ - #define __EVENT_HPP__ +#ifndef __LISTENER_HPP__ + #define __LISTENER_HPP__ #include #include @@ -14,7 +14,7 @@ namespace fail { class ExperimentFlow; -//! address wildcard (e.g. for BPEvent's) +//! address wildcard (e.g. for BPListener's) const address_t ANY_ADDR = static_cast(-1); //! instruction wildcard const unsigned ANY_INSTR = static_cast(-1); @@ -24,58 +24,59 @@ const unsigned ANY_TRAP = static_cast(-1); const unsigned ANY_INTERRUPT = static_cast(-1); /** - * \class BaseEvent - * This is the base class for all event types. + * \class BaseListener + * This is the base class for all listener types. */ -class BaseEvent { +class BaseListener { protected: - time_t m_tStamp; //!< time stamp of event - unsigned int m_OccCounter; //!< event fires when 0 is reached + time_t m_tStamp; //!< time stamp of listener + unsigned int m_OccCounter; //!< listener fires when 0 is reached unsigned int m_OccCounterInit; //!< initial value for m_OccCounter - ExperimentFlow* m_Parent; //!< this event belongs to experiment m_Parent + ExperimentFlow* m_Parent; //!< this listener belongs to experiment m_Parent public: - BaseEvent() : m_OccCounter(1), m_OccCounterInit(1), m_Parent(NULL) + BaseListener() : m_OccCounter(1), m_OccCounterInit(1), m_Parent(NULL) { updateTime(); } - virtual ~BaseEvent() { } + virtual ~BaseListener() { } /** - * 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. + * This method is called when an experiment flow adds a new listener by + * calling \c simulator.addListener() or \c simulator.addListenerAndResume(). + * More specifically, the listener will be added to the listener manager first + * (buffer-list, to be precise) and then this listener 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). + * the addition of the listener \c this, yielding an error in the + * experiment flow (i.e., \c false is returned). */ - virtual bool onEventAddition() { return true; } + virtual bool onAddition() { 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. + * This method is called when an experiment flow removes an listener from + * the listener-management by calling \c removeListener(), \c clearListeners() + * or by deleting a complete flow (\c removeFlow()). More specifically, this + * listener handler will be called *before* the listener is actually deleted. */ - virtual void onEventDeletion() { } + virtual void onDeletion() { } /** - * 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 + * This method is called when an previously added listener is about to be + * triggered by the simulator-backend. More specifically, this listener handler + * will be called *before* the listener is actually triggered, i.e. before the * corresponding coroutine is toggled. */ - virtual void onEventTrigger() { } + virtual void onTrigger() { } + // TODO: Hier noch ne neue Methode oder reicht es, die Semantik von onTrigger umzudef.? /** - * Retrieves the time stamp of this event. The time stamp is set when - * the event gets created, id est the constructor is called. The meaning - * of this value depends on the actual event type. + * Retrieves the time stamp of this listener. The time stamp is set when + * the listener gets created, i.e. the constructor is called. The meaning + * of this value depends on the actual listener type. * @return the time stamp */ std::time_t getTime() const { return (m_tStamp); } /** - * Decreases the event counter by one. When this counter reaches zero, the - * event will be triggered. + * Decreases the listener counter by one. When this counter reaches zero, the + * listener will be triggered. */ void decreaseCounter() { --m_OccCounter; } /** - * Sets the event counter to the specified value (default is one). - * @param val the new counter value + * Sets the listener counter to the specified value. + * @param val the new counter value (default is 1) */ void setCounter(unsigned int val = 1) { m_OccCounter = m_OccCounterInit = val; } /** @@ -84,56 +85,56 @@ public: */ unsigned int getCounter() const { return (m_OccCounter); } /** - * Resets the event counter to its default value, or the last - * value that was set through setCounter(). + * Resets the listener counter to its default value, or the last + * value that was set through \c setCounter(). */ void resetCounter() { m_OccCounter = m_OccCounterInit; } /** - * Sets the time stamp for this event to the current system time. + * Sets the time stamp for this listener to the current system time. */ void updateTime() { time(&m_tStamp); } /** - * Returns the parent experiment of this event (context). - * If the event was created temporarily or wasn't linked to a context, + * Returns the parent experiment of this listener (context). + * If the listener was created temporarily or wasn't linked to a context, * the return value is \c NULL (unknown identity). */ ExperimentFlow* getParent() const { return (m_Parent); } /** - * Sets the parent (context) of this event. The default context + * Sets the parent (context) of this listener. The default context * is \c NULL (unknown identity). */ void setParent(ExperimentFlow* pFlow) { m_Parent = pFlow; } }; // ---------------------------------------------------------------------------- -// Specialized events: +// Specialized listeners: // /** - * \class BEvent - * A Breakpoint event to observe instruction changes within a given address space. + * \class BListener + * A Breakpoint listener to observe instruction changes within a given address space. */ -class BPEvent : virtual public BaseEvent { +class BPListener : virtual public BaseListener { private: address_t m_CR3; address_t m_TriggerInstrPtr; public: /** - * Creates a new breakpoint event. The range information is specific to + * Creates a new breakpoint listener. The range information is specific to * the subclasses. * @param address_space the address space to be oberserved, given as the - * content of a CR3 register. The event will not be triggered unless + * content of a CR3 register. The listener will not be triggered unless * \a ip is part of the given address space. * ANY_ADDR can be used as a placeholder to allow debugging * in a random address space. */ - BPEvent(address_t address_space = ANY_ADDR) + BPListener(address_t address_space = 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 listener. */ address_t getCR3() const { return m_CR3; } /** - * Sets the address space register for this event. + * Sets the address space register for this listener. */ void setCR3(address_t iptr) { m_CR3 = iptr; } /** @@ -145,96 +146,108 @@ public: */ virtual bool isMatching(address_t addr = 0, address_t address_space = ANY_ADDR) const = 0; /** - * Returns the instruction pointer that triggered this event. + * Returns the instruction pointer that triggered this listener. */ address_t getTriggerInstructionPointer() const { return m_TriggerInstrPtr; } /** - * Sets the instruction pointer that triggered this event. Should not + * Sets the instruction pointer that triggered this listener. Should not * be used by experiment code. */ void setTriggerInstructionPointer(address_t iptr) { m_TriggerInstrPtr = iptr; } }; /** - * \class BPSingleEvent - * A Breakpoint event to observe specific instruction pointers. + * \class BPSingleListener + * A Breakpoint listener to observe specific instruction pointers. */ -class BPSingleEvent : virtual public BPEvent { +class BPSingleListener : virtual public BPListener { private: address_t m_WatchInstrPtr; public: - /** - * Creates a new breakpoint event. + /** + * Creates a new breakpoint listener. * @param ip the instruction pointer of the breakpoint. If the control * flow reaches this address and its counter value is zero, the - * event will be triggered. \a eip can be set to the ANY_ADDR - * wildcard to allow arbitrary addresses. + * listener will be triggered. \a eip can be set to the ANY_ADDR + * wildcard to allow arbitrary addresses. Defaults to 0. * @param address_space the address space to be oberserved, given as the - * content of a CR3 register. The event will not be triggered unless - * \a ip is part of the given address space. + * content of a CR3 register. The listener will not be triggered unless + * \a ip is part of the given address space. Defaults to \c ANY_ADDR. * Here, too, ANY_ADDR is a placeholder to allow debugging * in a random address space. */ - BPSingleEvent(address_t ip = 0, address_t address_space = ANY_ADDR) - : BPEvent(address_space), m_WatchInstrPtr(ip) { } + BPSingleListener(address_t ip = 0, address_t address_space = ANY_ADDR) + : BPListener(address_space), m_WatchInstrPtr(ip) { } /** - * Returns the instruction pointer this event waits for. + * Returns the instruction pointer this listener waits for. + * @return the instruction pointer specified in the constructor or by + * calling \c setWatchInstructionPointer() */ address_t getWatchInstructionPointer() const { return m_WatchInstrPtr; } /** - * Sets the instruction pointer this event waits for. + * Sets the instruction pointer this listener waits for. + * @param iptr the new instruction ptr to wait for */ void setWatchInstructionPointer(address_t iptr) { m_WatchInstrPtr = iptr; } /** * Checks whether a given address is matching. + * @param addr address to check + * @param address_space address space information + * @return \c true if address is within the range, \c false otherwise */ bool isMatching(address_t addr, address_t address_space) const; }; /** - * \class BPRangeEvent - * A event type to observe ranges of instruction pointers. + * \class BPRangeListener + * A listener type to observe ranges of instruction pointers. */ -class BPRangeEvent : virtual public BPEvent { +class BPRangeListener : virtual public BPListener { private: address_t m_WatchStartAddr; address_t m_WatchEndAddr; public: /** - * Creates a new breakpoint-range event. The range's ends are both + * Creates a new breakpoint-range listener. The range's ends are both * inclusive, i.e. an address matches if start <= addr <= end. * ANY_ADDR denotes the lower respectively the upper end of the address * space. */ - BPRangeEvent(address_t start = 0, address_t end = 0, address_t address_space = ANY_ADDR) - : BPEvent(address_space), m_WatchStartAddr(start), m_WatchEndAddr(end) + BPRangeListener(address_t start = 0, address_t end = 0, address_t address_space = ANY_ADDR) + : BPListener(address_space), m_WatchStartAddr(start), m_WatchEndAddr(end) { } /** - * Returns the instruction pointer watch range of this event. + * Returns the instruction pointer watch range of this listener. + * @return the listerner's range */ std::pair getWatchInstructionPointerRange() const { return std::make_pair(m_WatchStartAddr, m_WatchEndAddr); } /** * Sets the instruction pointer watch range. Both ends of the range * may be ANY_ADDR (cf. constructor). + * @param start the (inclusive) lower bound, or \c ANY_ADDR + * @param end the (inclusive) upper bound, or \c ANY_ADDR */ - void setWatchInstructionPointerRange(address_t start, - address_t end); + void setWatchInstructionPointerRange(address_t start, address_t end); /** * Checks whether a given address is within the range. + * @param addr address to check + * @param address_space address space information + * @return \c true if address is within the range (represented by + * \c this), \c false otherwise */ bool isMatching(address_t addr, address_t address_space) const; }; /** - * \class MemAccessEvent + * \class MemAccessListener * Observes memory read/write accesses. * FIXME? currently >8-bit accesses only match if their lowest address is being watched * (e.g., a 32-bit write to 0x4 also accesses 0x7, but this cannot be matched) */ -class MemAccessEvent : virtual public BaseEvent { +class MemAccessListener : virtual public BaseListener { public: enum accessType_t { MEM_UNKNOWN = 0x0, @@ -250,7 +263,7 @@ private: * (MEM_READ || MEM_WRITE || MEM_READWRITE). */ accessType_t m_WatchType; - //! Specific guest system address that actually triggered the event. + //! Specific guest system address that actually triggered the listener. address_t m_TriggerAddr; //! Width of the memory access (# bytes). size_t m_TriggerWidth; @@ -259,11 +272,11 @@ private: //! Memory access type at m_TriggerAddr. accessType_t m_AccessType; public: - MemAccessEvent(accessType_t watchtype = MEM_READWRITE) + MemAccessListener(accessType_t watchtype = MEM_READWRITE) : m_WatchAddr(ANY_ADDR), m_WatchType(watchtype), m_TriggerAddr(ANY_ADDR), m_TriggerIP(ANY_ADDR), m_AccessType(MEM_UNKNOWN) { } - MemAccessEvent(address_t addr, + MemAccessListener(address_t addr, accessType_t watchtype = MEM_READWRITE) : m_WatchAddr(addr), m_WatchType(watchtype), m_TriggerAddr(ANY_ADDR), m_TriggerIP(ANY_ADDR), @@ -282,21 +295,21 @@ public: bool isMatching(address_t addr, accessType_t accesstype) const; /** * Returns the specific memory address that actually triggered the - * event. + * listener. */ - address_t getTriggerAddress() const { return (m_TriggerAddr); } + address_t getTriggerAddress() const { return m_TriggerAddr; } /** - * Sets the specific memory address that actually triggered the event. + * Sets the specific memory address that actually triggered the listener. * Should not be used by experiment code. */ void setTriggerAddress(address_t addr) { m_TriggerAddr = addr; } /** * Returns the specific memory address that actually triggered the - * event. + * listener. */ - size_t getTriggerWidth() const { return (m_TriggerWidth); } + size_t getTriggerWidth() const { return m_TriggerWidth; } /** - * Sets the specific memory address that actually triggered the event. + * Sets the specific memory address that actually triggered the listener. * Should not be used by experiment code. */ void setTriggerWidth(size_t width) { m_TriggerWidth = width; } @@ -304,64 +317,62 @@ public: * Returns the address of the instruction causing this memory * access. */ - address_t getTriggerInstructionPointer() const - { return (m_TriggerIP); } + address_t getTriggerInstructionPointer() const { return m_TriggerIP; } /** * Sets the address of the instruction causing this memory * access. Should not be used by experiment code. */ - void setTriggerInstructionPointer(address_t addr) - { m_TriggerIP = addr; } + void setTriggerInstructionPointer(address_t addr) { m_TriggerIP = addr; } /** * Returns type (MEM_READ || MEM_WRITE) of the memory access that - * triggered this event. + * triggered this listener. */ - accessType_t getTriggerAccessType() const { return (m_AccessType); } + accessType_t getTriggerAccessType() const { return m_AccessType; } /** - * Sets type of the memory access that triggered this event. Should + * Sets type of the memory access that triggered this listener. Should * not be used by experiment code. */ void setTriggerAccessType(accessType_t type) { m_AccessType = type; } /** * Returns memory access types (MEM_READ || MEM_WRITE || MEM_READWRITE) - * this event watches. Should not be used by experiment code. + * this listener watches. Should not be used by experiment code. */ - accessType_t getWatchAccessType() const { return (m_WatchType); } + accessType_t getWatchAccessType() const { return m_WatchType; } }; /** - * \class MemReadEvent + * \class MemReadListener * Observes memory read accesses. */ -class MemReadEvent : virtual public MemAccessEvent { +class MemReadListener : virtual public MemAccessListener { public: - MemReadEvent() - : MemAccessEvent(MEM_READ) { } - MemReadEvent(address_t addr) - : MemAccessEvent(addr, MEM_READ) { } + MemReadListener() + : MemAccessListener(MEM_READ) { } + MemReadListener(address_t addr) + : MemAccessListener(addr, MEM_READ) { } }; /** - * \class MemWriteEvent + * \class MemWriteListener * Observes memory write accesses. */ -class MemWriteEvent : virtual public MemAccessEvent { +class MemWriteListener : virtual public MemAccessListener { public: - MemWriteEvent() - : MemAccessEvent(MEM_READ) { } - MemWriteEvent(address_t addr) - : MemAccessEvent(addr, MEM_WRITE) { } + MemWriteListener() + : MemAccessListener(MEM_READ) { } + MemWriteListener(address_t addr) + : MemAccessListener(addr, MEM_WRITE) { } }; /** - * \class TroubleEvent + * \class TroubleListener * Observes interrupt/trap activties. */ -class TroubleEvent : virtual public BaseEvent { +class TroubleListener : virtual public BaseListener { private: /** * Specific guest system interrupt/trap number that actually - * trigger the event. + * trigger the listener. */ int m_TriggerNumber; /** @@ -370,8 +381,8 @@ private: */ std::vector m_WatchNumbers; public: - TroubleEvent() : m_TriggerNumber (-1) { } - TroubleEvent(unsigned troubleNumber) + TroubleListener() : m_TriggerNumber (-1) { } + TroubleListener(unsigned troubleNumber) : m_TriggerNumber(-1) { addWatchNumber(troubleNumber); } /** @@ -393,39 +404,39 @@ public: * Returns the list of observed numbers * @return a copy of the list which contains all observed numbers */ - std::vector getWatchNumbers() { return (m_WatchNumbers); } + std::vector getWatchNumbers() { return m_WatchNumbers; } /** * Checks whether a given interrupt-/trap-number is matching. */ bool isMatching(unsigned troubleNum) const; /** * Sets the specific interrupt-/trap-number that actually triggered - * the event. Should not be used by experiment code. + * the listener. Should not be used by experiment code. */ void setTriggerNumber(unsigned troubleNum) { m_TriggerNumber = troubleNum; } /** * Returns the specific interrupt-/trap-number that actually triggered - * the event. + * the listener. */ - unsigned getTriggerNumber() { return (m_TriggerNumber); } + unsigned getTriggerNumber() { return m_TriggerNumber; } }; /** - * \class InterruptEvent + * \class InterruptListener * Observes interrupts of the guest system. */ -class InterruptEvent : virtual public TroubleEvent { +class InterruptListener : virtual public TroubleListener { private: bool m_IsNMI; //!< non maskable interrupt flag public: - InterruptEvent() : m_IsNMI(false) { } - InterruptEvent(unsigned interrupt) : m_IsNMI(false) + InterruptListener() : m_IsNMI(false) { } + InterruptListener(unsigned interrupt) : m_IsNMI(false) { addWatchNumber(interrupt); } /** * Returns \c true if the interrupt is non maskable, \c false otherwise. */ - bool isNMI() { return (m_IsNMI); } + bool isNMI() { return m_IsNMI; } /** * Sets the interrupt type (non maskable or not). */ @@ -433,29 +444,29 @@ public: }; /** - * \class TrapEvent + * \class TrapListener * Observes traps of the guest system. */ -class TrapEvent : virtual public TroubleEvent { +class TrapListener : virtual public TroubleListener { public: - TrapEvent() { } - TrapEvent(unsigned trap) { addWatchNumber(trap); } + TrapListener() { } + TrapListener(unsigned trap) { addWatchNumber(trap); } }; /** - * \class GuestEvent + * \class GuestListener * Used to receive data from the guest system. */ -class GuestEvent : virtual public BaseEvent { +class GuestListener : virtual public BaseListener { private: char m_Data; unsigned m_Port; public: - GuestEvent() : m_Data(0), m_Port(0) { } + GuestListener() : m_Data(0), m_Port(0) { } /** * Returns the data, transmitted by the guest system. */ - char getData() const { return (m_Data); } + char getData() const { return m_Data; } /** * Sets the data which had been transmitted by the guest system. */ @@ -463,7 +474,7 @@ public: /** * Returns the data length, transmitted by the guest system. */ - unsigned getPort() const { return (m_Port); } + unsigned getPort() const { return m_Port; } /** * Sets the data length which had been transmitted by the guest system. */ @@ -471,52 +482,52 @@ public: }; /** - * \class IOPortEvent + * \class IOPortListener * Observes I/O access on architectures with a separate I/O access mechanism (e.g. IA-32) */ -class IOPortEvent : virtual public BaseEvent { +class IOPortListener : virtual public BaseListener { private: unsigned char m_Data; unsigned m_Port; bool m_Out; public: /** - * Initialises an IOPortEvent + * Initialises an IOPortListener * - * @param port the port the event ist listening on - * @param out Defines the direction of the event. + * @param port the port the listener ist listening on + * @param out Defines the direction of the listener. * \arg \c true Output on the given port is captured. * \arg \c false Input on the given port is captured. */ - IOPortEvent(unsigned port, bool out) : m_Data(0), m_Port(port), m_Out(out) { } + IOPortListener(unsigned port, bool out) : m_Data(0), m_Port(port), m_Out(out) { } /** * Returns the data sent to the specified port */ - unsigned char getData() const { return (m_Data); } + unsigned char getData() const { return m_Data; } /** * Sets the data which had been transmitted. */ void setData(unsigned char data) { m_Data = data; } /** - * Retrieves the port which this event is bound to. + * Retrieves the port which this listener is bound to. */ - unsigned getPort() const { return (m_Port); } + unsigned getPort() const { return m_Port; } /** - * Sets the port which this event is bound to. + * Sets the port which this listener is bound to. */ void setPort(unsigned port) { m_Port = port; } /** * Checks whether a given port number is matching. - * @param p The port number an I/O event occured on + * @param p The port number an I/O listener occured on * @param out True if the communication was outbound, false otherwise */ - bool isMatching(unsigned p, bool out) const { return ( out = isOutEvent() && p == getPort()); } + bool isMatching(unsigned p, bool out) const { return ( out = isOutListener() && p == getPort()); } /** - * Tells you if this event is capturing outbound communication (inbound if false) + * Tells you if this listener is capturing outbound communication (inbound if false) */ - bool isOutEvent() const { return m_Out; } + bool isOutListener() const { return m_Out; } /** - * Change the event direction. + * Change the listener direction. * \arg \c true Output on the given port is captured. * \arg \c false Input on the given port is captured. */ @@ -524,36 +535,36 @@ public: }; /** - * \class JumpEvent - * JumpEvents are used to observe conditional jumps (if...else if...else). + * \class JumpListener + * JumpListeners are used to observe conditional jumps (if...else if...else). */ -class JumpEvent : virtual public BaseEvent { +class JumpListener : virtual public BaseListener { private: unsigned m_Opcode; bool m_FlagTriggered; public: /** - * Constructs a new event object. + * Constructs a new listener object. * @param parent the parent object * @param opcode the opcode of the jump-instruction to be observed * or ANY_INSTR to match all jump-instructions */ - JumpEvent(unsigned opcode = ANY_INSTR) + JumpListener(unsigned opcode = ANY_INSTR) : m_Opcode(opcode), m_FlagTriggered(false) { } /** * Retrieves the opcode of the jump-instruction. */ - unsigned getOpcode() const { return (m_Opcode); } + unsigned getOpcode() const { return m_Opcode; } /** - * Returns \c true, if the event was triggered due to specific register + * Returns \c true, if the listener was triggered due to specific register * content, \c false otherwise. */ - bool isRegisterTriggered() { return (!m_FlagTriggered); } + bool isRegisterTriggered() { return !m_FlagTriggered; } /** - * Returns \c true, of the event was triggered due to specific FLAG + * Returns \c true, of the listener was triggered due to specific FLAG * state, \c false otherwise. This is the common case. */ - bool isFlagTriggered() { return (m_FlagTriggered); } + bool isFlagTriggered() { return m_FlagTriggered; } /** * Sets the requestet jump-instruction opcode. */ @@ -561,36 +572,35 @@ public: /** * Sets the trigger flag. */ - void setFlagTriggered(bool flagTriggered) - { m_FlagTriggered = flagTriggered; } + void setFlagTriggered(bool flagTriggered) { m_FlagTriggered = flagTriggered; } }; /** - * \class GenericTimerEvent - * This event type is used to create timeouts within in an experiment. + * \class GenericTimerListener + * This listener 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 + * from \c GenericTimerListener. \c onListenerAddition should be used to register and + * \c onListenerDeletion to unregister the timer. \c onListenerTrigger 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 GenericTimerEvent : public BaseEvent { +class GenericTimerListener : public BaseListener { protected: unsigned m_Timeout; //!< timeout interval in milliseconds timer_id_t m_Id; //!< internal timer id (sim-specific) bool m_Once; //!< \c true, if the timer should be triggered only once, \c false otherwise public: /** - * Creates a new timer event. This can be used to implement a timeout- + * Creates a new timer listener. This can be used to implement a timeout- * mechanism in the experiment-flow. The timer starts automatically when * added to the simulator backend. * @param timeout the time intervall in milliseconds (ms) - * @see SimulatorController::addEvent + * @see SimulatorController::addListener */ - GenericTimerEvent(unsigned timeout) + GenericTimerListener(unsigned timeout) : m_Timeout(timeout), m_Id(-1) { } - ~GenericTimerEvent() { } + ~GenericTimerListener() { } /** * Retrieves the internal timer id. Maybe useful for debug output. * @return the timer id @@ -610,4 +620,4 @@ public: } // end-of-namespace: fail -#endif // __EVENT_HPP__ +#endif // __LISTENER_HPP__ diff --git a/src/core/sal/ListenerManager.cc b/src/core/sal/ListenerManager.cc new file mode 100644 index 00000000..9607206d --- /dev/null +++ b/src/core/sal/ListenerManager.cc @@ -0,0 +1,191 @@ +#include + +#include "ListenerManager.hpp" +#include "SALInst.hpp" + +namespace fail { + +void ListenerManager::addToCaches(BaseListener *li) +{ + BPListener *bps_li; + if ((bps_li = dynamic_cast(li)) != NULL) + m_Bp_cache.add(bps_li); + + IOPortListener *io_li; + if ((io_li = dynamic_cast(li)) != NULL) + m_Io_cache.add(io_li); +} + +void ListenerManager::removeFromCaches(BaseListener *li) +{ + BPListener *bpr_li; + if ((bpr_li = dynamic_cast(li)) != NULL) + m_Bp_cache.remove(bpr_li); + + IOPortListener *io_li; + if ((io_li = dynamic_cast(li)) != NULL) + m_Io_cache.remove(io_li); +} + +void ListenerManager::clearCaches() +{ + m_Bp_cache.clear(); + m_Io_cache.clear(); +} + +void ListenerManager::add(BaseListener* li, ExperimentFlow* pExp) +{ + assert(li != NULL && "FATAL ERROR: Listener (of base type BaseListener*) cannot be NULL!"); + // a zero counter does not make sense + assert(li->getCounter() != 0); + li->setParent(pExp); // listener is linked to experiment flow + + addToCaches(li); + m_BufferList.push_back(li); +} + +void ListenerManager::remove(BaseListener* li) +{ + // possible cases: + // - li == 0 -> remove all listeners + // * clear m_BufferList + // * copy m_FireList to m_DeleteList + if (li == 0) { + for (bufferlist_t::iterator it = m_BufferList.begin(); it != m_BufferList.end(); it++) + (*it)->onDeletion(); + for (firelist_t::iterator it = m_FireList.begin(); it != m_FireList.end(); it++) + (*it)->onDeletion(); + clearCaches(); + m_BufferList.clear(); + // all remaining active listeners must not fire anymore + m_DeleteList.insert(m_DeleteList.end(), m_FireList.begin(), m_FireList.end()); + + // - li != 0 -> remove single listener + // * find/remove 'li' in 'm_BufferList' + // * if 'li' in 'm_FireList', copy to 'm_DeleteList' + } else { + li->onDeletion(); + + removeFromCaches(li); + m_BufferList.remove(li); + firelist_t::const_iterator it = + std::find(m_FireList.begin(), m_FireList.end(), li); + if (it != m_FireList.end()) { + m_DeleteList.push_back(li); + } + } +} + +ListenerManager::iterator ListenerManager::m_remove(iterator it, bool skip_deletelist) +{ + if (!skip_deletelist) { + // If skip_deletelist = true, m_remove was called from makeActive. Accordingly, we + // are not going to delete an listener, instead we are "moving" a listener object (= *it) + // from the buffer list to the fire-list. Therefore we only need to call the simulator's + // listener handler (onDeletion), if m_remove is called with the primary intention + // to *delete* (not "move") a listener. + (*it)->onDeletion(); + m_DeleteList.push_back(*it); + + // Cached listeners have their own BufferCache::makeActive() implementation, which + // calls this method and afterwards erase() in the cache class. This is why, when + // called from any kind of makeActive() method, it is unnecessary to call + // BufferCache::remove() from m_remove(). + + // NOTE: in case the semantics of skip_deletelist change, please adapt the following lines + removeFromCaches(*it); + } + + return m_BufferList.erase(it); +} + +void ListenerManager::remove(ExperimentFlow* flow) +{ + // all listeners? + if (flow == 0) { + for (bufferlist_t::iterator it = m_BufferList.begin(); + it != m_BufferList.end(); it++) + (*it)->onDeletion(); // invoke listener handler + clearCaches(); + m_BufferList.clear(); + } else { // remove all listeners corresponding to a specific experiment ("flow"): + for (bufferlist_t::iterator it = m_BufferList.begin(); + it != m_BufferList.end(); ) { + if ((*it)->getParent() == flow) { + (*it)->onDeletion(); + it = m_BufferList.erase(it); + } else { + ++it; + } + } + } + // listeners that just fired / are about to fire ... + for (firelist_t::const_iterator it = m_FireList.begin(); + it != m_FireList.end(); it++) { + if (std::find(m_DeleteList.begin(), m_DeleteList.end(), *it) + != m_DeleteList.end()) { + continue; // (already in the delete-list? -> skip!) + } + // ... need to be pushed into m_DeleteList, as we're currently + // iterating over m_FireList in triggerActiveListeners() and cannot modify it + if (flow == 0 || (*it)->getParent() == flow) { + (*it)->onDeletion(); + m_DeleteList.push_back(*it); + } + } +} + +ListenerManager::~ListenerManager() +{ + // nothing to do here yet +} + +ListenerManager::iterator ListenerManager::makeActive(iterator it) +{ + assert(it != m_BufferList.end() && + "FATAL ERROR: Iterator has already reached the end!"); + BaseListener* li = *it; + assert(li && "FATAL ERROR: Listener object pointer cannot be NULL!"); + li->decreaseCounter(); + if (li->getCounter() > 0) { + return ++it; + } + li->resetCounter(); + // Note: This is the one and only situation in which remove() should NOT + // store the removed item in the delete-list. + iterator it_next = m_remove(it, true); // remove listener from buffer-list + m_FireList.push_back(li); + return it_next; +} + +void ListenerManager::triggerActiveListeners() +{ + for (firelist_t::iterator it = m_FireList.begin(); + it != m_FireList.end(); it++) { + if (std::find(m_DeleteList.begin(), m_DeleteList.end(), *it) + == m_DeleteList.end()) { // not found in delete-list? + m_pFired = *it; + // Inform (call) the simulator's (internal) listener handler that we are about + // to trigger an listener (*before* we actually toggle the experiment flow): + m_pFired->onTrigger(); + ExperimentFlow* pFlow = m_pFired->getParent(); + assert(pFlow && "FATAL ERROR: The listener has no parent experiment (owner)!"); + simulator.m_Flows.toggle(pFlow); + } + } + m_FireList.clear(); + m_DeleteList.clear(); + // Note: Do NOT call any listener handlers here! +} + +size_t ListenerManager::getContextCount() const +{ + std::set uniqueFlows; // count unique ExperimentFlow-ptr + for (bufferlist_t::const_iterator it = m_BufferList.begin(); + it != m_BufferList.end(); it++) + uniqueFlows.insert((*it)->getParent()); + + return uniqueFlows.size(); +} + +} // end-of-namespace: fail diff --git a/src/core/sal/ListenerManager.hpp b/src/core/sal/ListenerManager.hpp new file mode 100644 index 00000000..15c1ff0f --- /dev/null +++ b/src/core/sal/ListenerManager.hpp @@ -0,0 +1,219 @@ +#ifndef __LISTENER_MANAGER_HPP__ + #define __LISTENER_MANAGER_HPP__ + +#include +#include +#include +#include + +#include "Listener.hpp" +#include "BufferCache.hpp" + +namespace fail { + +class ExperimentFlow; + +/** + * Buffer-list for a specific experiment; acts as a simple storage container + * for listeners to watch for: + */ +typedef std::list bufferlist_t; +/** + * List of listeners that match the current simulator listener; these listeners will + * be triggered next (the list is used temporarily). + */ +typedef std::vector firelist_t; +/** + * List of listeners that have been deleted during a toggled experiment flow while + * triggering the listeners in the fire-list. This list is used to skip already + * deleted listeners (therefore it is used temporarily either). + */ +typedef std::vector deletelist_t; + +/** + * Cache classes for the most commonly used types of listeners, utilising static typing. + * Apart from that, they work like bufferlist_t. + */ +typedef BufferCache bp_cache_t; +typedef bp_cache_t::iterator bp_iter_t; +typedef BufferCache io_cache_t; +typedef io_cache_t::iterator io_iter_t; +/** + * \class ListenerManager + * + * \brief This class manages the listeners of the Fail* implementation. + * + * If a listener is triggered, the internal data structure will be updated (i.e., + * the listener will be removed from the so called buffer-list and added to the + * fire-list). Additionally, if an experiment-flow deletes an "active" listener + * which is currently stored in the fire-list, the listener (to be removed) will + * be added to a -so called- delete-list. This ensures to prevent triggering + * "active" listeners which have already been deleted by a previous experiment + * flow. (See makeActive() and fireActiveListener() for implementation specific + * details.) ListenerManager is part of the SimulatorController and "outsources" + * it's listener management. + */ +class ListenerManager { +private: + // TODO: List separation of "critical types"? Hashing/sorted lists? (-> performance!) + bufferlist_t m_BufferList; //!< the storage for listeners added by exp. + firelist_t m_FireList; //!< the active listeners (used temporarily) + deletelist_t m_DeleteList; //!< the deleted listeners (used temporarily) + BaseListener* m_pFired; //!< the recently fired Listener-object + bp_cache_t m_Bp_cache; //!< the storage cache for breakpoint listeners + io_cache_t m_Io_cache; //!< the storage cache for port i/o listeners + friend bp_iter_t bp_cache_t::makeActive(ListenerManager &ev_list, bp_iter_t idx); + friend io_iter_t io_cache_t::makeActive(ListenerManager &ev_list, io_iter_t idx); +public: + /** + * The iterator of this class used to loop through the list of added + * listeners. To retrieve an iterator to the first element, call \c begin(). + * \c end() returns the iterator, pointing after the last element. + * (This behaviour equals the STL iterator in C++.) + */ + typedef bufferlist_t::iterator iterator; + + ListenerManager() : m_pFired(NULL) { } + ~ListenerManager(); + /** + * Adds the specified listener object for the given ExperimentFlow to the + * list of listeners to be watched for. + * @param li pointer to the listener object to be added (cannot be \c NULL) + * @param flow the listener context (a pointer to the experiment object + * which is interested in such listeners (cannot be \c NULL) + * @return the id of the added listener object, that is ev->getId() + */ + void add(BaseListener* li, ExperimentFlow* flow); + /** + * Removes the listener based upon the specified \a ev pointer (requires + * to loop through the whole buffer-list). + * @param li the pointer of the listener to be removed; if ev is set to + * \c NULL, all listeners (for \a all experiments) will be + * removed + */ + void remove(BaseListener* li); + /** + * Behaves like remove(BaseListener*) and additionally updates the provided + * iterator. + * @param it the iterator pointing to the Listener object to be removed + * @return the updated iterator which will point to the next element + */ + iterator remove(iterator it); +private: + /** + * Internal implementation of remove(iterator it) that allows + * to skip the delete-list. + * @param it the iterator pointing to the Listener object to be removed + * @param skip_deletelist \c true to skip the deletion of the Listener object + * or \false to behave like \c remove(iterator) + * @return the updated iterator which will point to the next element + */ + iterator m_remove(iterator it, bool skip_deletelist); +public: + /** + * Returns an iterator to the beginning of the internal data structure. + * Don't forget to update the returned iterator when calling one of the + * modifying methods like makeActive() or remove(). Therefore you need + * to call the iterator-based variants of makeActive() and remove(). + * \code + * [X|1|2| ... |n] + * ^ + * \endcode + * @return iterator to the beginning + */ + iterator begin() { return (m_BufferList.begin()); } + /** + * Returns an iterator to the end of the interal data structure. + * Don't forget to update the returned iterator when calling one of the + * modifying methods like makeActive() or remove(). Therefore you need + * to call the iterator-based variants of makeActive() and remove(). + * \code + * [1|2| ... |n]X + * ^ + * \endcode + * @return iterator to the end + */ + iterator end() { return (m_BufferList.end()); } + /** + * Removes all listeners for the specified experiment. + * @param flow pointer to experiment context (0 = all experiments) + */ + void remove(ExperimentFlow* flow); + /** + * Retrieves the number of experiments which currently have active + * listeners. This number is trivially equal to the (current) total + * number of ExperimentFlow-objects. + * @return number of experiments having active listeners + */ + size_t getContextCount() const; + /** + * Retrieves the total number of buffered listeners. This doesn't include + * the listeners in the fire- or delete-list. + * @return the total listener count (for all flows) + */ + size_t getListenerCount() const { return m_BufferList.size(); } + /** + * Retrieves the recently triggered listener object. To map this object to it's + * context (i.e., the related \c ExerimentFlow), use \c getLastFiredDest(). + * @return a pointer to the recent listener or \c NULL if nothing has been + * triggered so far + */ + BaseListener* getLastFired() { return (m_pFired); } + /** + * Retrieves the ExperimentFlow-object for the given BaseListener (it's + * \a context). + * @param li the listener object to be looked up + * @return a pointer to the context of \a pEv or \c NULL if the + * corresponding context could not be found + */ + ExperimentFlow* getExperimentOf(BaseListener* li); + /** + * Moves the listeners from the (internal) buffer-list to the fire-list. + * To actually fire the listeners, call triggerActiveListeners(). + * Returns an updated iterator which points to the next element. + * @param ev the listener to trigger + * @return returns the updated iteration, pointing to the next element + * after makeActive returns, "it" is invalid, so the returned + * iterator should be used to continue the iteration + * + * TODO: Improve naming (instead of "makeActive")? + */ + iterator makeActive(iterator it); + /** + * Triggers the active listeners. Each listener is triggered if it has not + * recently been removed (id est: is not found in the delete-list). See + * makeActive() for more details. The recently triggered listener can be + * retrieved by calling \a getLastFired(). After all listeners have been + * triggered, the (internal) fire- and delete-list will be cleared. + */ + void triggerActiveListeners(); + /** + * Retrieves the BPListener buffer cache. + * @returns the buffer cache + */ + inline bp_cache_t &getBPBuffer() { return m_Bp_cache; } + /** + * Retrieves the IOPortListener buffer cache. + * @returns the buffer cache + */ + inline io_cache_t &getIOBuffer() { return m_Io_cache; } +private: + /** + * Add an listener to its appropriate cache. + * @param li the listener to add + */ + void addToCaches(BaseListener* li); + /** + * Remove an listener from its cache. + * @param li the listener to remove + */ + void removeFromCaches(BaseListener* li); + /** + * Clear the listener caches. + */ + void clearCaches(); +}; + +} // end-of-namespace: fail + +#endif // __LISTENER_MANAGER_HPP__ diff --git a/src/core/sal/Register.hpp b/src/core/sal/Register.hpp index b8af18cb..36126b6a 100644 --- a/src/core/sal/Register.hpp +++ b/src/core/sal/Register.hpp @@ -55,12 +55,12 @@ public: * Returns the (fixed) type of this register. * @return the type of this register */ - RegisterType getType() const { return (m_Type); } + RegisterType getType() const { return m_Type; } /** * Returns the (fixed) width of this register. * @return the width in bits */ - regwidth_t getWidth() const { return (m_Width); } + regwidth_t getWidth() const { return m_Width; } /** * Returns the data referenced by this register. In a concrete * derived class this method has to be defined appropriately. @@ -81,7 +81,7 @@ public: * Retrieves the register name. * @return the textual register description */ - const std::string& getName() const { return (m_Name); } + const std::string& getName() const { return m_Name; } /** * Retrieves the unique index within it's assigned register set. * If the register has not been assigned, \c (size_t)-1 will be @@ -89,18 +89,18 @@ public: * @return the register index or -1 if not assigned * @see isAssigned() */ - size_t getIndex() const { return (m_Index); } + size_t getIndex() const { return m_Index; } /** * Checks whether this register has already been assigned. On * creation the register isn't initially assigned. * @return \c true if assigned, \c false otherwise */ - bool isAssigned() const { return (m_Assigned); } + bool isAssigned() const { return m_Assigned; } /** * Returns the unique id of this register. * @return the unique id */ - unsigned int getId() const { return (m_Id); } + unsigned int getId() const { return m_Id; } }; /** @@ -132,7 +132,7 @@ public: * ^ * \endcode */ - iterator begin() { return (m_Regs.begin()); } + iterator begin() { return m_Regs.begin(); } /** * Returns an iterator to the end of the interal data structure. * \code @@ -140,7 +140,7 @@ public: * ^ * \endcode */ - iterator end() { return (m_Regs.end()); } + iterator end() { return m_Regs.end(); } /** * Constructs a new register set with type \a containerType. * @param containerType the type of registers which should be stored @@ -152,12 +152,12 @@ public: * Returns the type of this set. * @return the type */ - RegisterType getType() const { return (m_Type); } + RegisterType getType() const { return m_Type; } /** * Gets the number of registers of this set. * @return the number of registers */ - size_t count() const { return (m_Regs.size()); } + size_t count() const { return m_Regs.size(); } /** * Retrieves the \a i-th register within this set. * @return a pointer to the \a i-th register; if \a i is invalid, an @@ -169,7 +169,7 @@ public: * @return a pointer to the first register (if existing -- otherwise an * assertion is thrown) */ - virtual Register* first() { return (getRegister(0)); } + virtual Register* first() { return getRegister(0); } }; /** @@ -197,7 +197,7 @@ public: * ^ * \endcode */ - iterator begin() { return (m_Registers.begin()); } + iterator begin() { return m_Registers.begin(); } /** * Returns an iterator to the end of the interal data structure. * \code @@ -205,7 +205,7 @@ public: * ^ * \endcode */ - iterator end() { return (m_Registers.end()); } + iterator end() { return m_Registers.end(); } RegisterManager() { } ~RegisterManager() { clear(); } @@ -218,7 +218,7 @@ public: * Retrieves the number of managed homogeneous register sets. * @return the number of sets */ - virtual size_t subsetCount() const { return (m_Subsets.size()); } + virtual size_t subsetCount() const { return m_Subsets.size(); } /** * Gets the \a i-th register set. * @param i the index of the set to be returned diff --git a/src/core/sal/SimulatorController.cc b/src/core/sal/SimulatorController.cc index 201b8d72..c5a3dee3 100644 --- a/src/core/sal/SimulatorController.cc +++ b/src/core/sal/SimulatorController.cc @@ -6,26 +6,26 @@ namespace fail { // External reference declared in SALInst.hpp ConcreteSimulatorController simulator; -bool SimulatorController::addEvent(BaseEvent* ev) +bool SimulatorController::addListener(BaseListener* li) { - assert(ev != NULL && "FATAL ERROR: Argument (ptr) cannot be NULL!"); - m_EvList.add(ev, m_Flows.getCurrent()); + assert(li != NULL && "FATAL ERROR: Argument (ptr) cannot be NULL!"); + m_LstList.add(li, m_Flows.getCurrent()); // Call the common postprocessing function: - if (!ev->onEventAddition()) { // If the return value signals "false"..., - m_EvList.remove(ev); // ...skip the addition + if (!li->onAddition()) { // If the return value signals "false"..., + m_LstList.remove(li); // ...skip the addition return false; } return true; } -BaseEvent* SimulatorController::waitAny(void) +BaseListener* SimulatorController::resume(void) { - if (!hasEvents()) + if (!hasListeners()) return NULL; m_Flows.resume(); - assert(m_EvList.getLastFired() != NULL && + assert(m_LstList.getLastFired() != NULL && "FATAL ERROR: getLastFired() expected to be non-NULL!"); - return m_EvList.getLastFired(); + return m_LstList.getLastFired(); } void SimulatorController::startup() @@ -43,47 +43,47 @@ void SimulatorController::initExperiments() /* empty. */ } -void SimulatorController::onBreakpointEvent(address_t instrPtr, address_t address_space) +void SimulatorController::onBreakpointListener(address_t instrPtr, address_t address_space) { assert(false && - "FIXME: SimulatorController::onBreakpointEvent() has not been tested before"); + "FIXME: SimulatorController::onBreakpointListener() has not been tested before"); // FIXME: Improve performance! - // Loop through all events of type BP*Event: - EventManager::iterator it = m_EvList.begin(); - while (it != m_EvList.end()) { - BaseEvent* pev = *it; - BPSingleEvent* pbp; BPRangeEvent* pbpr; - if ((pbp = dynamic_cast(pev)) && pbp->isMatching(instrPtr, address_space)) { + // Loop through all events of type BP*Listener: + ListenerManager::iterator it = m_LstList.begin(); + while (it != m_LstList.end()) { + BaseListener* pev = *it; + BPSingleListener* pbp; BPRangeListener* pbpr; + if ((pbp = dynamic_cast(pev)) && pbp->isMatching(instrPtr, address_space)) { pbp->setTriggerInstructionPointer(instrPtr); - it = m_EvList.makeActive(it); + it = m_LstList.makeActive(it); // "it" has already been set to the next element (by calling // makeActive()): continue; // -> skip iterator increment - } else if ((pbpr = dynamic_cast(pev)) && + } else if ((pbpr = dynamic_cast(pev)) && pbpr->isMatching(instrPtr, address_space)) { pbpr->setTriggerInstructionPointer(instrPtr); - it = m_EvList.makeActive(it); + it = m_LstList.makeActive(it); continue; // dito } ++it; } - m_EvList.fireActiveEvents(); + m_LstList.triggerActiveListeners(); } -void SimulatorController::onMemoryAccessEvent(address_t addr, size_t len, +void SimulatorController::onMemoryAccessListener(address_t addr, size_t len, bool is_write, address_t instrPtr) { // FIXME: Improve performance! - MemAccessEvent::accessType_t accesstype = - is_write ? MemAccessEvent::MEM_WRITE - : MemAccessEvent::MEM_READ; + MemAccessListener::accessType_t accesstype = + is_write ? MemAccessListener::MEM_WRITE + : MemAccessListener::MEM_READ; - EventManager::iterator it = m_EvList.begin(); - while (it != m_EvList.end()) { // check for active events - BaseEvent* pev = *it; - MemAccessEvent* ev = dynamic_cast(pev); - // Is this a MemAccessEvent? Correct access type? + ListenerManager::iterator it = m_LstList.begin(); + while (it != m_LstList.end()) { // check for active events + BaseListener* pev = *it; + MemAccessListener* ev = dynamic_cast(pev); + // Is this a MemAccessListener? Correct access type? if (!ev || !ev->isMatching(addr, accesstype)) { ++it; continue; // skip event activation @@ -92,26 +92,26 @@ void SimulatorController::onMemoryAccessEvent(address_t addr, size_t len, ev->setTriggerWidth(len); ev->setTriggerInstructionPointer(instrPtr); ev->setTriggerAccessType(accesstype); - it = m_EvList.makeActive(it); + it = m_LstList.makeActive(it); } - m_EvList.fireActiveEvents(); + m_LstList.triggerActiveListeners(); } -void SimulatorController::onInterruptEvent(unsigned interruptNum, bool nmi) +void SimulatorController::onInterruptListener(unsigned interruptNum, bool nmi) { - EventManager::iterator it = m_EvList.begin(); - while (it != m_EvList.end()) { // check for active events - BaseEvent* pev = *it; - InterruptEvent* pie = dynamic_cast(pev); + ListenerManager::iterator it = m_LstList.begin(); + while (it != m_LstList.end()) { // check for active events + BaseListener* pev = *it; + InterruptListener* pie = dynamic_cast(pev); if (!pie || !pie->isMatching(interruptNum)) { ++it; continue; // skip event activation } pie->setTriggerNumber(interruptNum); pie->setNMI(nmi); - it = m_EvList.makeActive(it); + it = m_LstList.makeActive(it); } - m_EvList.fireActiveEvents(); + m_LstList.triggerActiveListeners(); } bool SimulatorController::isSuppressedInterrupt(unsigned interruptNum) @@ -155,53 +155,53 @@ bool SimulatorController::removeSuppressedInterrupt(unsigned interruptNum) return false; } -void SimulatorController::onTrapEvent(unsigned trapNum) +void SimulatorController::onTrapListener(unsigned trapNum) { - EventManager::iterator it = m_EvList.begin(); - while (it != m_EvList.end()) { // check for active events - BaseEvent* pev = *it; - TrapEvent* pte = dynamic_cast(pev); + ListenerManager::iterator it = m_LstList.begin(); + while (it != m_LstList.end()) { // check for active events + BaseListener* pev = *it; + TrapListener* pte = dynamic_cast(pev); if (!pte || !pte->isMatching(trapNum)) { ++it; continue; // skip event activation } pte->setTriggerNumber(trapNum); - it = m_EvList.makeActive(it); + it = m_LstList.makeActive(it); } - m_EvList.fireActiveEvents(); + m_LstList.triggerActiveListeners(); } -void SimulatorController::onGuestSystemEvent(char data, unsigned port) +void SimulatorController::onGuestSystemListener(char data, unsigned port) { - EventManager::iterator it = m_EvList.begin(); - while (it != m_EvList.end()) { // check for active events - BaseEvent* pev = *it; - GuestEvent* pge = dynamic_cast(pev); + ListenerManager::iterator it = m_LstList.begin(); + while (it != m_LstList.end()) { // check for active events + BaseListener* pev = *it; + GuestListener* pge = dynamic_cast(pev); if (pge != NULL) { pge->setData(data); pge->setPort(port); - it = m_EvList.makeActive(it); + it = m_LstList.makeActive(it); continue; // dito. } ++it; } - m_EvList.fireActiveEvents(); + m_LstList.triggerActiveListeners(); } -void SimulatorController::onJumpEvent(bool flagTriggered, unsigned opcode) +void SimulatorController::onJumpListener(bool flagTriggered, unsigned opcode) { - EventManager::iterator it = m_EvList.begin(); - while (it != m_EvList.end()) { // check for active events - JumpEvent* pje = dynamic_cast(*it); + ListenerManager::iterator it = m_LstList.begin(); + while (it != m_LstList.end()) { // check for active events + JumpListener* pje = dynamic_cast(*it); if (pje != NULL) { pje->setOpcode(opcode); pje->setFlagTriggered(flagTriggered); - it = m_EvList.makeActive(it); + it = m_LstList.makeActive(it); continue; // dito. } ++it; } - m_EvList.fireActiveEvents(); + m_LstList.triggerActiveListeners(); } void SimulatorController::addFlow(ExperimentFlow* flow) @@ -215,15 +215,15 @@ void SimulatorController::addFlow(ExperimentFlow* flow) void SimulatorController::removeFlow(ExperimentFlow* flow) { // remove all remaining events of this flow - clearEvents(flow); + clearListeners(flow); // remove coroutine m_Flows.remove(flow); } -BaseEvent* SimulatorController::addEventAndWait(BaseEvent* ev) +BaseListener* SimulatorController::addListenerAndResume(BaseListener* li) { - addEvent(ev); - return waitAny(); + addListener(li); + return resume(); } void SimulatorController::terminate(int exCode) diff --git a/src/core/sal/SimulatorController.hpp b/src/core/sal/SimulatorController.hpp index a08f633a..5b7e97ba 100644 --- a/src/core/sal/SimulatorController.hpp +++ b/src/core/sal/SimulatorController.hpp @@ -7,9 +7,9 @@ #include #include "efw/CoroutineManager.hpp" -#include "EventManager.hpp" +#include "ListenerManager.hpp" #include "SALConfig.hpp" -#include "Event.hpp" +#include "Listener.hpp" namespace fail { @@ -23,23 +23,22 @@ class MemoryManager; * * \brief The abstract interface for controlling simulators and * accessing experiment data/flows (as part of the "Simulator - * Abstraction Layer". + * Abstraction Layer", SAL for short). * * This class manages (1..N) experiments and provides access to the underlying - * simulator/debugger system. Experiments can enlist arbritrary events - * (Breakpoint, Memory access, Traps, etc.). The SimulatorController then + * simulator/debugger system. Experiments can enlist arbritrary listeners + * (Breakpoint, Memory access, Traps, etc.). The \c SimulatorController then * activates the specific experiment There are further methods to read/write * registers and memory, and control the SUT (save/restore/reset). */ class SimulatorController { protected: - EventManager m_EvList; //!< storage where events are being buffered + ListenerManager m_LstList; //!< storage where listeners are being buffered CoroutineManager m_Flows; //!< managed experiment flows RegisterManager *m_Regs; //!< access to cpu register MemoryManager *m_Mem; //!< access to memory pool - //! list of suppressed interrupts - std::vector m_SuppressedInterrupts; - friend class EventManager; //!< "outsources" the event management + std::vector m_SuppressedInterrupts; //!< list of suppressed interrupts + friend class ListenerManager; //!< "outsources" the listener management public: SimulatorController() : m_Regs(NULL), m_Mem(NULL) { } @@ -60,17 +59,17 @@ public: */ void initExperiments(); /* ******************************************************************** - * Standard Event Handler API + * Standard Listener Handler API * ********************************************************************/ /** - * Breakpoint event handler. This routine needs to be called in the - * simulator specific backend each time a breakpoint event occurs. - * @param instrPtr the instruction pointer of the breakpoint event + * Breakpoint listener handler. This routine needs to be called in the + * simulator specific backend each time a breakpoint listener occurs. + * @param instrPtr the instruction pointer of the breakpoint listener * @param address_space the address space it should occur in */ - void onBreakpointEvent(address_t instrPtr, address_t address_space); + void onBreakpointListener(address_t instrPtr, address_t address_space); /** - * Memory access event handler (read/write). + * Memory access listener handler (read/write). * @param addr the accessed memory address * @param len the length of the accessed memory * @param is_write \c true if memory is written, \c false if read @@ -79,32 +78,31 @@ public: * * FIXME: should instrPtr be part of this interface? */ - void onMemoryAccessEvent(address_t addr, size_t len, - bool is_write, address_t instrPtr); + void onMemoryAccessListener(address_t addr, size_t len, bool is_write, address_t instrPtr); /** - * Interrupt event handler. + * Interrupt listener handler. * @param interruptNum the interrupt-type id * @param nmi nmi-value from guest-system */ - void onInterruptEvent(unsigned interruptNum, bool nmi); + void onInterruptListener(unsigned interruptNum, bool nmi); /** - * Trap event handler. + * Trap listener handler. * @param trapNum the trap-type id */ - void onTrapEvent(unsigned trapNum); + void onTrapListener(unsigned trapNum); /** * Guest system communication handler. * @param data the "message" from the guest system - * @param port the port of the event + * @param port the port of the listener */ - void onGuestSystemEvent(char data, unsigned port); + void onGuestSystemListener(char data, unsigned port); /** * (Conditional) Jump-instruction handler. * @param flagTriggered \c true if the jump was triggered due to a * specific FLAG (zero/carry/sign/overflow/parity flag) * @param opcode the opcode of the conrecete jump instruction */ - void onJumpEvent(bool flagTriggered, unsigned opcode); + void onJumpListener(bool flagTriggered, unsigned opcode); /* ******************************************************************** * Simulator Controller & Access API: * ********************************************************************/ @@ -115,7 +113,7 @@ public: virtual void save(const std::string& path) = 0; /** * Restore simulator state. Implicitly discards all previously - * registered events. + * registered listeners. * @param path Location to previously saved state information */ virtual void restore(const std::string& path) = 0; @@ -144,20 +142,18 @@ public: /** * Remove a Interrupt from the list of suppressed. * @param interruptNum the interrupt-type id - * @return \c true if sucessfully removed, \c false otherwise (not - * found) + * @return \c true if sucessfully removed, \c false otherwise (not found) */ bool removeSuppressedInterrupt(unsigned interruptNum); /** * Returns the (constant) initialized register manager. * @return a reference to the register manager */ - RegisterManager& getRegisterManager() { return (*m_Regs); } - const RegisterManager& getRegisterManager() const { return (*m_Regs); } + RegisterManager& getRegisterManager() { return *m_Regs; } + const RegisterManager& getRegisterManager() const { return *m_Regs; } /** * Sets the register manager. - * @param pReg the new register manager (or a concrete derived class of - * RegisterManager) + * @param pReg the new register manager (or a concrete derived class of \c RegisterManager) */ void setRegisterManager(RegisterManager* pReg) { m_Regs = pReg; } /** @@ -165,74 +161,72 @@ public: * @return a reference to the memory manager */ MemoryManager& getMemoryManager() { return (*m_Mem); } - const MemoryManager& getMemoryManager() const { return (*m_Mem); } + const MemoryManager& getMemoryManager() const { return *m_Mem; } /** * Sets the memory manager. * @param pMem a new concrete memory manager */ void setMemoryManager(MemoryManager* pMem) { m_Mem = pMem; } /* ******************************************************************** - * Experiment-Flow & Event Management API: + * Experiment-Flow & Listener Management API: * ********************************************************************/ /** - * Adds the specified experiment or plugin and creates a coroutine to - * run it in. + * Adds the specified experiment or plugin and creates a coroutine to run it in. * @param flow the experiment flow object to be added */ void addFlow(ExperimentFlow* flow); /** * Removes the specified experiment or plugin and destroys its coroutine - * and all associated events. + * and all associated listeners. * @param flow the experiment flow object to be removed */ void removeFlow(ExperimentFlow* flow); /** - * 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 \c true if the event has been added successfully, \c false otherwise + * Add listener \c li to the listener management. This causes the listener to be active. + * @param li the listener pointer to be added for the current flow + * @return \c true if the listener has been added successfully, \c false otherwise */ - bool addEvent(BaseEvent* ev); + bool addListener(BaseListener* li); /** - * Removes the event with the specified id. - * @param ev the pointer of the event-object to be removed; if \a ev is - * equal to \c NULL all events (for all experiments) will be - * removed + * Removes the listener with the specified pointer \c li. + * @param li the pointer of the listener-object to be removed; if \c li is + * equal to \c NULL, all listeners (for all experiments) will be removed */ - void removeEvent(BaseEvent* ev) { m_EvList.remove(ev); } + void removeListener(BaseListener* li) { m_LstList.remove(li); } /** - * Removes all previously added events for all experiments. To + * Removes all previously added listeners for all experiments. To * restrict this to a specific experiment flow, pass a pointer to it. + * @param flow a ptr to a specific experiment flow whose listeners should + * be removed; if \c flow is \c NULL, all listeners will be removed */ - void clearEvents(ExperimentFlow *flow = 0) { m_EvList.remove(flow); } + void clearListeners(ExperimentFlow *flow = 0) { m_LstList.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. - * @return the previously occurred event, or \c NULL if there are no - * events to wait for + * Switches the control flow to the simulator and waits on any listeners + * which have been added to the listener management. If one of those listeners + * occurs, resume() will return the pointer of that listener. + * @return the previously occurred listener, or \c NULL if there are no + * listeners to wait for */ - BaseEvent* waitAny(); + BaseListener* resume(); /** - * Add event \a ev to the global buffer and wait for it (combines - * \c addEvent() and \c waitAny()). - * @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 + * Add listener \a ev to the global buffer and continues the simulation + * (combines \c addListener() and \c resume()). + * @param li the listener pointer to be added + * @return the pointer of the occurred listener (it is not guaranteed that + * this pointer will be equal to li) */ - BaseEvent* addEventAndWait(BaseEvent* ev); + BaseListener* addListenerAndResume(BaseListener* li); /** - * Checks whether any experiment flow has events in the event-list. - * @return \c true if there are still events, or \c false otherwise + * Checks whether any experiment flow has listeners in the listener-list. + * @return \c true if there are still listeners, or \c false otherwise */ - bool hasEvents() const { return getEventCount() > 0; } + bool hasListeners() const { return getListenerCount() > 0; } /** - * Determines the number of (stored) events in the event-list which have + * Determines the number of (stored) listeners in the listener-list which have * not been triggered so far. - * @return the actual number of events + * @return the actual number of listeners */ - unsigned getEventCount() const { return m_EvList.getEventCount(); } + unsigned getListenerCount() const { return m_LstList.getListenerCount(); } }; } // end-of-namespace: fail diff --git a/src/core/sal/bochs/BochsController.cc b/src/core/sal/bochs/BochsController.cc index cd62a75d..f0405f65 100644 --- a/src/core/sal/bochs/BochsController.cc +++ b/src/core/sal/bochs/BochsController.cc @@ -101,13 +101,13 @@ void BochsController::onInstrPtrChanged(address_t instrPtr, address_t address_sp m_CacheEntry = cache_entry; bool do_fire = false; // Check for active breakpoint-events: - bp_cache_t &buffer_cache = m_EvList.getBPBuffer(); + bp_cache_t &buffer_cache = m_LstList.getBPBuffer(); bp_cache_t::iterator it = buffer_cache.begin(); while (it != buffer_cache.end()) { - BPEvent* pEvBreakpt = *it; + BPListener* pEvBreakpt = *it; if (pEvBreakpt->isMatching(instrPtr, address_space)) { pEvBreakpt->setTriggerInstructionPointer(instrPtr); - it = buffer_cache.makeActive(m_EvList, it); + it = buffer_cache.makeActive(m_LstList, it); do_fire = true; // "it" has already been set to the next element (by calling // makeActive()): @@ -116,28 +116,28 @@ void BochsController::onInstrPtrChanged(address_t instrPtr, address_t address_sp it++; } if (do_fire) - m_EvList.fireActiveEvents(); - // Note: SimulatorController::onBreakpointEvent will not be invoked in this + m_LstList.triggerActiveListeners(); + // Note: SimulatorController::onBreakpointListener will not be invoked in this // implementation. } -void BochsController::onIOPortEvent(unsigned char data, unsigned port, bool out) { +void BochsController::onIOPortListener(unsigned char data, unsigned port, bool out) { // Check for active breakpoint-events: - io_cache_t &buffer_cache = m_EvList.getIOBuffer(); + io_cache_t &buffer_cache = m_LstList.getIOBuffer(); io_cache_t::iterator it = buffer_cache.begin(); while (it != buffer_cache.end()) { - IOPortEvent* pIOPt = (*it); + IOPortListener* pIOPt = (*it); if (pIOPt->isMatching(port, out)) { pIOPt->setData(data); - it = buffer_cache.makeActive(m_EvList, it); + it = buffer_cache.makeActive(m_LstList, it); // "it" has already been set to the next element (by calling // makeActive()): continue; // -> skip iterator increment } it++; } - m_EvList.fireActiveEvents(); - // Note: SimulatorController::onBreakpointEvent will not be invoked in this + m_LstList.triggerActiveListeners(); + // Note: SimulatorController::onBreakpointListener will not be invoked in this // implementation. } @@ -165,7 +165,7 @@ void BochsController::saveDone() void BochsController::restore(const std::string& path) { - clearEvents(); + clearListeners(); restore_bochs_request = true; BX_CPU(0)->async_event |= 1; sr_path = path; @@ -181,7 +181,7 @@ void BochsController::restoreDone() void BochsController::reboot() { - clearEvents(); + clearListeners(); reboot_bochs_request = true; BX_CPU(0)->async_event |= 1; m_CurrFlow = m_Flows.getCurrent(); @@ -213,16 +213,16 @@ void BochsController::onTimerTrigger(void* thisPtr) { // FIXME: The timer logic can be modified to use only one timer in Bochs. // (For now, this suffices.) - TimerEvent* pTmEv = static_cast(thisPtr); - // Check for a matching TimerEvent. (In fact, we are only - // interessted in the iterator pointing at pTmEv.): - EventManager::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, + TimerListener* pli = static_cast(thisPtr); + // Check for a matching TimerListener. (In fact, we are only + // interessted in the iterator pointing at pli.) + ListenerManager::iterator it = std::find(simulator.m_LstList.begin(), + simulator.m_LstList.end(), pli); + // TODO: This has O(|m_LstList|) time complexity. We can further improve this + // by creating a method such that makeActive(pli) works as well, // reducing the time complexity to O(1). - simulator.m_EvList.makeActive(it); - simulator.m_EvList.fireActiveEvents(); + simulator.m_LstList.makeActive(it); + simulator.m_LstList.triggerActiveListeners(); } const std::string& BochsController::getMnemonic() const diff --git a/src/core/sal/bochs/BochsController.hpp b/src/core/sal/bochs/BochsController.hpp index cf70c3a0..81920bd7 100644 --- a/src/core/sal/bochs/BochsController.hpp +++ b/src/core/sal/bochs/BochsController.hpp @@ -8,10 +8,10 @@ #include #include "FailBochsGlobals.hpp" -#include "BochsEvents.hpp" +#include "BochsListener.hpp" #include "../SimulatorController.hpp" -#include "../Event.hpp" +#include "../Listener.hpp" #include "bochs.h" #include "cpu/cpu.h" @@ -40,7 +40,7 @@ public: BochsController(); ~BochsController(); /* ******************************************************************** - * Standard Event Handler API: + * Standard Listener Handler API: * ********************************************************************/ /** * Instruction pointer modification handler. This method is called (from @@ -57,20 +57,20 @@ public: * @param port the port it was transmitted on * @param out true if the I/O traffic has been outbound, false otherwise */ - void onIOPortEvent(unsigned char data, unsigned port, bool out); + void onIOPortListener(unsigned char data, unsigned port, bool out); /** - * Static internal event handler for TimerEvents. This static function is + * Static internal handler for TimerListeners. This static function is * called when a previously registered (Bochs) timer triggers. This function - * searches for the provided TimerEvent object within the EventManager and - * fires such an event by calling \c fireActiveEvents(). - * @param thisPtr a pointer to the TimerEvent-object triggered + * searches for the provided TimerListener object within the ListenerManager and + * fires such an event by calling \c triggerActiveListeners(). + * @param thisPtr a pointer to the TimerListener-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 + * 1777 in bios/rombios.c, function keyboard_init()) if a TimerListener * 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()). + * reproduce this error, try adding a \c TimerListener as the initial step + * in your experiment code and wait for it (\c addListenerAndResume()). */ static void onTimerTrigger(void *thisPtr); /* ******************************************************************** @@ -86,7 +86,7 @@ public: */ void saveDone(); /** - * Restore simulator state. Clears all Events. + * Restore simulator state. Clears all Listeners. * @param path Location to previously saved state information */ void restore(const std::string& path); @@ -95,7 +95,7 @@ public: */ void restoreDone(); /** - * Reboot simulator. Clears all Events. + * Reboot simulator. Clears all Listeners. */ void reboot(); /** diff --git a/src/core/sal/bochs/BochsEvents.cc b/src/core/sal/bochs/BochsListener.cc similarity index 56% rename from src/core/sal/bochs/BochsEvents.cc rename to src/core/sal/bochs/BochsListener.cc index 8ca448de..348921d7 100644 --- a/src/core/sal/bochs/BochsEvents.cc +++ b/src/core/sal/bochs/BochsListener.cc @@ -1,34 +1,34 @@ -#include "BochsEvents.hpp" +#include "BochsListener.hpp" #include "../SALInst.hpp" namespace fail { -bool TimerEvent::onEventAddition() +bool TimerListener::onAddition() { - // Register the timer event in the Bochs simulator: + // Register the timer listener 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() +void TimerListener::onDeletion() { - // Unregister the time event: + // Unregister the time listener: m_unregisterTimer(this); } -timer_id_t TimerEvent::m_registerTimer(TimerEvent* pev) +timer_id_t TimerListener::m_registerTimer(TimerListener* pev) { - assert(pev != NULL && "FATAL ERROR: TimerEvent object ptr cannot be NULL!"); + assert(pev != NULL && "FATAL ERROR: TimerListener object ptr cannot be NULL!"); return static_cast( bx_pc_system.register_timer(pev, BochsController::onTimerTrigger, pev->getTimeout(), false, 1/*start immediately*/, "Fail*: BochsController"/*name*/)); } -bool TimerEvent::m_unregisterTimer(TimerEvent* pev) +bool TimerListener::m_unregisterTimer(TimerListener* pev) { - assert(pev != NULL && "FATAL ERROR: TimerEvent object ptr cannot be NULL!"); + assert(pev != NULL && "FATAL ERROR: TimerListener object ptr cannot be NULL!"); bx_pc_system.deactivate_timer(static_cast(pev->getId())); return bx_pc_system.unregisterTimer(static_cast(pev->getId())); } diff --git a/src/core/sal/bochs/BochsEvents.hpp b/src/core/sal/bochs/BochsListener.hpp similarity index 55% rename from src/core/sal/bochs/BochsEvents.hpp rename to src/core/sal/bochs/BochsListener.hpp index 07f5562c..15943ffd 100644 --- a/src/core/sal/bochs/BochsEvents.hpp +++ b/src/core/sal/bochs/BochsListener.hpp @@ -1,74 +1,76 @@ #ifndef __BOCHS_EVENTS_HPP__ #define __BOCHS_EVENTS_HPP__ -#include "../Event.hpp" +#include "../Listener.hpp" #include "BochsController.hpp" namespace fail { /** - * \class TimerEvent - * Concrete TimerEvent implementation of GenericTimerEvent for the Bochs + * \class TimerListener + * Concrete TimerListener implementation of GenericTimerListener for the Bochs * simulator backend. */ -class TimerEvent : public GenericTimerEvent { +class TimerListener : public GenericTimerListener { private: /** - * Registers a timer in the Bochs simulator. This timer fires \a TimerEvents + * Registers a timer in the Bochs simulator. This timer triggers \a TimerListeners * 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) + * @param pli a pointer to the (experiment flow-) allocated TimerListener object, + * providing all required information to start the timer (e.g. the + * timeout value). + * @return The unique id of the timer recently created. This id is carried + * along with the TimerListener. On errors, -1 is returned (e.g. because + * a timer with the same id is already existing) + * @see TimerListener::getId() */ - static timer_id_t m_registerTimer(TimerEvent* pev); + static timer_id_t m_registerTimer(TimerListener* pli); /** * 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 + * @param pli a pointer to the TimerListener-object to be removed + * @return \c true if the timer with \a pli->getId() has been removed * successfully, \c false otherwise */ - static bool m_unregisterTimer(TimerEvent* pev); + static bool m_unregisterTimer(TimerListener* pli); 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) - * @see SimulatorController::addEvent + * @see SimulatorController::addListener */ - TimerEvent(unsigned timeout) - : GenericTimerEvent(timeout) { } - ~TimerEvent() { onEventDeletion(); } + TimerListener(unsigned timeout) + : GenericTimerListener(timeout) { } + ~TimerListener() { onDeletion(); } /** * This method is called when an experiment flow adds a new event by - * calling \c simulator.addEvent(pev) or \c simulator.addEventAndWait(pev). + * calling \c simulator.addListener() or \c simulator.addListenerAndResume(). * 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). */ - bool onEventAddition(); + bool onAddition(); /** * This method is called when an experiment flow removes an event from - * the event-management by calling \c removeEvent(prev), \c clearEvents() + * the event-management by calling \c removeListener(prev), \c clearListeners() * or by deleting a complete flow (\c removeFlow). More specifically, this * event handler will be called *before* the event is actually deleted. */ - void onEventDeletion(); + void onDeletion(); /** * 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(); } + void onTrigger() { onDeletion(); } + // TODO/FIXME: bei neuer impl. anpassen }; } // end-of-namespace: fail diff --git a/src/core/sal/bochs/BochsRegister.hpp b/src/core/sal/bochs/BochsRegister.hpp index 14ae69ed..5e26749d 100644 --- a/src/core/sal/bochs/BochsRegister.hpp +++ b/src/core/sal/bochs/BochsRegister.hpp @@ -32,7 +32,7 @@ public: * Retrieves the data of the register. * @return the current register data */ - regdata_t getData() { return (*m_pData); } + regdata_t getData() { return *m_pData; } /** * Sets the content of the register. * @param data the new register data to be written @@ -136,44 +136,42 @@ public: * Returns \c true if the corresponding flag is set, or \c false * otherwise. */ - bool getCarryFlag() const { return (BX_CPU(0)->get_CF()); } - bool getParityFlag() const { return (BX_CPU(0)->get_PF()); } - bool getZeroFlag() const { return (BX_CPU(0)->get_ZF()); } - bool getSignFlag() const { return (BX_CPU(0)->get_SF()); } - bool getOverflowFlag() const { return (BX_CPU(0)->get_OF()); } - - bool getTrapFlag() const { return (BX_CPU(0)->get_TF()); } - bool getInterruptFlag() const { return (BX_CPU(0)->get_IF()); } - bool getDirectionFlag() const { return (BX_CPU(0)->get_DF()); } - unsigned getIOPrivilegeLevel() const { return (BX_CPU(0)->get_IOPL()); } - bool getNestedTaskFlag() const { return (BX_CPU(0)->get_NT()); } - bool getResumeFlag() const { return (BX_CPU(0)->get_RF()); } - bool getVMFlag() const { return (BX_CPU(0)->get_VM()); } - bool getAlignmentCheckFlag() const { return (BX_CPU(0)->get_AC()); } - bool getVInterruptFlag() const { return (BX_CPU(0)->get_VIF()); } - bool getVInterruptPendingFlag() const { return (BX_CPU(0)->get_VIP()); } - bool getIdentificationFlag() const { return (BX_CPU(0)->get_ID()); } + bool getCarryFlag() const { return BX_CPU(0)->get_CF(); } + bool getParityFlag() const { return BX_CPU(0)->get_PF(); } + bool getZeroFlag() const { return BX_CPU(0)->get_ZF(); } + bool getSignFlag() const { return BX_CPU(0)->get_SF(); } + bool getOverflowFlag() const { return BX_CPU(0)->get_OF(); } + bool getTrapFlag() const { return BX_CPU(0)->get_TF(); } + bool getInterruptFlag() const { return BX_CPU(0)->get_IF(); } + bool getDirectionFlag() const { return BX_CPU(0)->get_DF(); } + unsigned getIOPrivilegeLevel() const { return BX_CPU(0)->get_IOPL(); } + bool getNestedTaskFlag() const { return BX_CPU(0)->get_NT(); } + bool getResumeFlag() const { return BX_CPU(0)->get_RF(); } + bool getVMFlag() const { return BX_CPU(0)->get_VM(); } + bool getAlignmentCheckFlag() const { return BX_CPU(0)->get_AC(); } + bool getVInterruptFlag() const { return BX_CPU(0)->get_VIF(); } + bool getVInterruptPendingFlag() const { return BX_CPU(0)->get_VIP(); } + bool getIdentificationFlag() const { return BX_CPU(0)->get_ID(); } /** * Sets/resets various status FLAGS. */ - void setCarryFlag(bool bit) { BX_CPU(0)->set_CF(bit); } - void setParityFlag(bool bit) { BX_CPU(0)->set_PF(bit); } - void setZeroFlag(bool bit) { BX_CPU(0)->set_ZF(bit); } - void setSignFlag(bool bit) { BX_CPU(0)->set_SF(bit); } - void setOverflowFlag(bool bit) { BX_CPU(0)->set_OF(bit); } - - void setTrapFlag(bool bit) { BX_CPU(0)->set_TF(bit); } - void setInterruptFlag(bool bit) { BX_CPU(0)->set_IF(bit); } - void setDirectionFlag(bool bit) { BX_CPU(0)->set_DF(bit); } - void setIOPrivilegeLevel(unsigned lvl) { BX_CPU(0)->set_IOPL(lvl); } - void setNestedTaskFlag(bool bit) { BX_CPU(0)->set_NT(bit); } - void setResumeFlag(bool bit) { BX_CPU(0)->set_RF(bit); } - void setVMFlag(bool bit) { BX_CPU(0)->set_VM(bit); } - void setAlignmentCheckFlag(bool bit) { BX_CPU(0)->set_AC(bit); } - void setVInterruptFlag(bool bit) { BX_CPU(0)->set_VIF(bit); } - void setVInterruptPendingFlag(bool bit) { BX_CPU(0)->set_VIP(bit); } - void setIdentificationFlag(bool bit) { BX_CPU(0)->set_ID(bit); } + void setCarryFlag(bool bit) { BX_CPU(0)->set_CF(bit); } + void setParityFlag(bool bit) { BX_CPU(0)->set_PF(bit); } + void setZeroFlag(bool bit) { BX_CPU(0)->set_ZF(bit); } + void setSignFlag(bool bit) { BX_CPU(0)->set_SF(bit); } + void setOverflowFlag(bool bit) { BX_CPU(0)->set_OF(bit); } + void setTrapFlag(bool bit) { BX_CPU(0)->set_TF(bit); } + void setInterruptFlag(bool bit) { BX_CPU(0)->set_IF(bit); } + void setDirectionFlag(bool bit) { BX_CPU(0)->set_DF(bit); } + void setIOPrivilegeLevel(unsigned lvl) { BX_CPU(0)->set_IOPL(lvl); } + void setNestedTaskFlag(bool bit) { BX_CPU(0)->set_NT(bit); } + void setResumeFlag(bool bit) { BX_CPU(0)->set_RF(bit); } + void setVMFlag(bool bit) { BX_CPU(0)->set_VM(bit); } + void setAlignmentCheckFlag(bool bit) { BX_CPU(0)->set_AC(bit); } + void setVInterruptFlag(bool bit) { BX_CPU(0)->set_VIF(bit); } + void setVInterruptPendingFlag(bool bit) { BX_CPU(0)->set_VIP(bit); } + void setIdentificationFlag(bool bit) { BX_CPU(0)->set_ID(bit); } /** * Sets the content of the status register. @@ -184,8 +182,7 @@ public: { #ifdef BX_SUPPORT_X86_64 // We are in 64 bit mode: Just assign the lower 32 bits! - (*m_pData) = ((*m_pData) & 0xFFFFFFFF00000000ULL) | - (data & 0xFFFFFFFFULL); + (*m_pData) = ((*m_pData) & 0xFFFFFFFF00000000ULL) | (data & 0xFFFFFFFFULL); #else *m_pData = data; #endif @@ -204,7 +201,7 @@ public: */ address_t getInstructionPointer() { - return (static_cast(getSetOfType(RT_PC)->first()->getData())); + return static_cast(getSetOfType(RT_PC)->first()->getData()); } /** * Retruns the top address of the stack. @@ -213,9 +210,9 @@ public: address_t getStackPointer() { #if BX_SUPPORT_X86_64 - return (static_cast(getRegister(RID_RSP)->getData())); + return static_cast(getRegister(RID_RSP)->getData()); #else - return (static_cast(getRegister(RID_ESP)->getData())); + return static_cast(getRegister(RID_ESP)->getData()); #endif } /** @@ -226,9 +223,9 @@ public: address_t getBasePointer() { #if BX_SUPPORT_X86_64 - return (static_cast(getRegister(RID_RBP)->getData())); + return static_cast(getRegister(RID_RBP)->getData()); #else - return (static_cast(getRegister(RID_EBP)->getData())); + return static_cast(getRegister(RID_EBP)->getData()); #endif } }; diff --git a/src/core/sal/bochs/Breakpoints.ah b/src/core/sal/bochs/Breakpoints.ah index 9aa683fd..125a703c 100644 --- a/src/core/sal/bochs/Breakpoints.ah +++ b/src/core/sal/bochs/Breakpoints.ah @@ -13,7 +13,7 @@ aspect Breakpoints { pointcut cpuLoop() = "void defineCPULoopJoinPoint(...)"; - advice execution (cpuLoop()) : after () // Event source: "instruction pointer" + advice execution (cpuLoop()) : after () // event source: "instruction pointer" { // Points to the cpu class: "this" if BX_USE_CPU_SMF == 0, // BX_CPU(0) otherwise diff --git a/src/core/sal/bochs/GuestSysCom.ah b/src/core/sal/bochs/GuestSysCom.ah index 747c0ace..6c035ea2 100644 --- a/src/core/sal/bochs/GuestSysCom.ah +++ b/src/core/sal/bochs/GuestSysCom.ah @@ -19,12 +19,12 @@ aspect GuestSysCom { pointcut outInstructions() = "% ...::bx_cpu_c::OUT_DX%(...)"; - advice execution (outInstructions()) : after () // Event source: "guest system" + advice execution (outInstructions()) : after () // Listener source: "guest system" { unsigned rDX = getCPU(tjp->that())->gen_reg[2].word.rx; // port number unsigned rAL = getCPU(tjp->that())->gen_reg[0].word.byte.rl; // data if (rDX == BOCHS_COM_PORT) - fail::simulator.onGuestSystemEvent((char)rAL, rDX); + fail::simulator.onGuestSystemListener((char)rAL, rDX); } }; diff --git a/src/core/sal/bochs/IOPortCom.ah b/src/core/sal/bochs/IOPortCom.ah index c107a0dd..bc47fdcd 100644 --- a/src/core/sal/bochs/IOPortCom.ah +++ b/src/core/sal/bochs/IOPortCom.ah @@ -21,7 +21,7 @@ aspect IOPortCom { { unsigned rDX = getCPU(tjp->that())->gen_reg[2].word.rx; // port number unsigned char rAL = getCPU(tjp->that())->gen_reg[0].word.byte.rl; // data - fail::simulator.onIOPortEvent(rAL, rDX, true); + fail::simulator.onIOPortListener(rAL, rDX, true); } pointcut inInstruction() = "% ...::bx_cpu_c::IN_ALDX(...)"; @@ -30,7 +30,7 @@ aspect IOPortCom { { unsigned rDX = getCPU(tjp->that())->gen_reg[2].word.rx; // port number unsigned char rAL = getCPU(tjp->that())->gen_reg[0].word.byte.rl; // data - fail::simulator.onIOPortEvent(rAL, rDX, false); + fail::simulator.onIOPortListener(rAL, rDX, false); } }; diff --git a/src/core/sal/bochs/Interrupt.ah b/src/core/sal/bochs/Interrupt.ah index e1246dc1..5160e25c 100644 --- a/src/core/sal/bochs/Interrupt.ah +++ b/src/core/sal/bochs/Interrupt.ah @@ -28,9 +28,9 @@ aspect Interrupt { unsigned vector = *(tjp->arg<0>()); unsigned type = *(tjp->arg<1>()); if (type == BX_EXTERNAL_INTERRUPT) - fail::simulator.onInterruptEvent(vector, false); + fail::simulator.onInterruptListener(vector, false); else if (type == BX_NMI) - fail::simulator.onInterruptEvent(vector, true); + fail::simulator.onInterruptListener(vector, true); } }; diff --git a/src/core/sal/bochs/Jump.ah b/src/core/sal/bochs/Jump.ah index 57b2cf97..710e66f0 100644 --- a/src/core/sal/bochs/Jump.ah +++ b/src/core/sal/bochs/Jump.ah @@ -60,7 +60,7 @@ aspect Jump { advice execution (defJumpInstructions()) : around() { bxInstruction_c* pInstr = *(tjp->arg<0>()); // bxInstruction_c-object - fail::simulator.onJumpEvent(true, pInstr->getIaOpcode()); + fail::simulator.onJumpListener(true, pInstr->getIaOpcode()); /* JoinPoint::That* pThis = tjp->that(); if(pThis == NULL) @@ -77,7 +77,7 @@ aspect Jump { // Step-1: Modify one or more of the fxxxFlag according to the error you want to inject // (using pThis->set_XX(new_val)) // Step-2: Call tjp->proceed(); - // Step-3: Eventually, unwind the changes of Step-1 + // Step-3: Listenerually, unwind the changes of Step-1 // // Example: @@ -109,7 +109,7 @@ aspect Jump { advice execution (regJumpInstructions()) : around () { bxInstruction_c* pInstr = *(tjp->arg<0>()); // bxInstruction_c-object - fail::simulator.onJumpEvent(false, pInstr->getIaOpcode()); + fail::simulator.onJumpListener(false, pInstr->getIaOpcode()); /* JoinPoint::That* pThis = tjp->that(); diff --git a/src/core/sal/bochs/MemAccess.ah b/src/core/sal/bochs/MemAccess.ah index f8146c20..cb94dbcc 100644 --- a/src/core/sal/bochs/MemAccess.ah +++ b/src/core/sal/bochs/MemAccess.ah @@ -56,19 +56,19 @@ aspect MemAccess { // Fire a memory-write-event each time the guest system requests // to write data to RAM: // - // Event source: "memory write access" + // Listener source: "memory write access" // #ifdef CONFIG_EVENT_MEMWRITE advice execution (write_methods()) : after () { - fail::simulator.onMemoryAccessEvent( + fail::simulator.onMemoryAccessListener( *(tjp->arg<1>()), sizeof(*(tjp->arg<2>())), true, getCPU(tjp->that())->prev_rip); } advice execution (write_methods_RMW()) : after () { - fail::simulator.onMemoryAccessEvent( + fail::simulator.onMemoryAccessListener( rmw_address, sizeof(*(tjp->arg<0>())), true, getCPU(tjp->that())->prev_rip); } @@ -77,7 +77,7 @@ aspect MemAccess { { std::cerr << "WOOOOOT write_methods_new_stack" << std::endl; // TODO: Log-level? - fail::simulator.onMemoryAccessEvent( + fail::simulator.onMemoryAccessListener( *(tjp->arg<1>()), sizeof(*(tjp->arg<3>())), true, getCPU(tjp->that())->prev_rip); } @@ -86,7 +86,7 @@ aspect MemAccess { { std::cerr << "WOOOOOT write_methods_new_stack_64" << std::endl; // TODO: Log-level? - fail::simulator.onMemoryAccessEvent( + fail::simulator.onMemoryAccessListener( *(tjp->arg<0>()), sizeof(*(tjp->arg<2>())), true, getCPU(tjp->that())->prev_rip); } @@ -98,7 +98,7 @@ aspect MemAccess { // memory (e.g., to read vectors from the interrupt vector // table). /* - fail::simulator.onMemoryAccessEvent( + fail::simulator.onMemoryAccessListener( *(tjp->arg<0>()), sizeof(*(tjp->arg<1>())), true, getCPU(tjp->that())->prev_rip); */ @@ -109,19 +109,19 @@ aspect MemAccess { // Fire a memory-read-event each time the guest system requests // to read data in RAM: // - // Event source: "memory read access" + // Listener source: "memory read access" // #ifdef CONFIG_EVENT_MEMREAD advice execution (read_methods()) : before () { - fail::simulator.onMemoryAccessEvent( + fail::simulator.onMemoryAccessListener( *(tjp->arg<1>()), sizeof(*(tjp->result())), false, getCPU(tjp->that())->prev_rip); } advice execution (read_methods_dqword()) : before () { - fail::simulator.onMemoryAccessEvent( + fail::simulator.onMemoryAccessListener( *(tjp->arg<1>()), 16, false, getCPU(tjp->that())->prev_rip); } @@ -131,7 +131,7 @@ aspect MemAccess { { rmw_address = *(tjp->arg<1>()); #ifdef CONFIG_EVENT_MEMREAD - fail::simulator.onMemoryAccessEvent( + fail::simulator.onMemoryAccessListener( *(tjp->arg<1>()), sizeof(*(tjp->result())), false, getCPU(tjp->that())->prev_rip); #endif @@ -145,7 +145,7 @@ aspect MemAccess { // memory (e.g., to read vectors from the interrupt vector // table). /* - fail::simulator.onMemoryAccessEvent( + fail::simulator.onMemoryAccessListener( *(tjp->arg<0>()), sizeof(*(tjp->result())), false, getCPU(tjp->that())->prev_rip); */ diff --git a/src/core/sal/bochs/Trap.ah b/src/core/sal/bochs/Trap.ah index dcfe489e..3797f929 100644 --- a/src/core/sal/bochs/Trap.ah +++ b/src/core/sal/bochs/Trap.ah @@ -15,9 +15,9 @@ aspect Trap { advice execution (exception_method()) : before () { - fail::simulator.onTrapEvent(*(tjp->arg<0>())); + fail::simulator.onTrapListener(*(tjp->arg<0>())); // TODO: There are some different types of exceptions at cpu.h (line 265-281) - // Which kind of a trap are these types? + // Which kind of traps are these types? } }; diff --git a/src/core/sal/ovp/OVPController.cc b/src/core/sal/ovp/OVPController.cc index 454aeda6..9df2a051 100644 --- a/src/core/sal/ovp/OVPController.cc +++ b/src/core/sal/ovp/OVPController.cc @@ -84,12 +84,12 @@ void OVPController::onInstrPtrChanged(address_t instrPtr) // cerr << "instrPtr: 0x" << hex << instrPtr << " SP: 0x" << hex << m_Regs->getStackPointer() \ // << " R0: 0x" << hex << r0 << " ST: 0x" << hex << st << endl; - // Check for active breakpoint-events: - EventManager::iterator it = m_EvList.begin(); + // Check for active breakpoint-Listeners: + ListenerManager::iterator it = m_EvList.begin(); while (it != m_EvList.end()) { // FIXME: Performance verbessern (dazu muss entsprechend auch die Speicherung - // in EventManager(.cc|.hpp) angepasst bzw. verbessert werden). - BPSingleEvent* pEvBreakpt = dynamic_cast(*it); + // in ListenerManager(.cc|.hpp) angepasst bzw. verbessert werden). + BPSingleListener* pEvBreakpt = dynamic_cast(*it); if (pEvBreakpt && (instrPtr == pEvBreakpt->getWatchInstructionPointer() || pEvBreakpt->getWatchInstructionPointer() == ANY_ADDR)) { pEvBreakpt->setTriggerInstructionPointer(instrPtr); @@ -98,7 +98,7 @@ void OVPController::onInstrPtrChanged(address_t instrPtr) // makeActive()): continue; // -> skip iterator increment } - BPRangeEvent* pEvRange = dynamic_cast(*it); + BPRangeListener* pEvRange = dynamic_cast(*it); if (pEvRange && pEvRange->isMatching(instrPtr)) { pEvBreakpt->setTriggerInstructionPointer(instrPtr); it = m_EvList.makeActive(it); @@ -106,7 +106,7 @@ void OVPController::onInstrPtrChanged(address_t instrPtr) } it++; } - m_EvList.fireActiveEvents(); + m_EvList.fireActiveListeners(); } void OVPController::save(const string& path) diff --git a/src/core/sal/ovp/OVPController.hpp b/src/core/sal/ovp/OVPController.hpp index 1f489c39..6be63705 100644 --- a/src/core/sal/ovp/OVPController.hpp +++ b/src/core/sal/ovp/OVPController.hpp @@ -7,7 +7,7 @@ #include #include "../SimulatorController.hpp" -#include "../Event.hpp" +#include "../Listener.hpp" #include "../Register.hpp" #include "ovp/OVPPlatform.hpp"