Files
fail/core/controller/Signal.hpp
hsc b70b6fb43a another directory rename: failstar -> fail
"failstar" sounds like a name for a cruise liner from the 80s.  As "*" isn't a
desirable part of directory names, just name the whole thing "fail/", the core
parts being stored in "fail/core/".

Additionally fixing two build system dependency issues:
 - missing jobserver -> protomessages dependency
 - broken bochs -> fail dependency (add_custom_target DEPENDS only allows plain
   file dependencies ... cmake for the win)


git-svn-id: https://www4.informatik.uni-erlangen.de/i4svn/danceos/trunk/devel/fail@956 8c4709b5-6ec9-48aa-a5cd-a96041d1645a
2012-03-08 19:43:02 +00:00

137 lines
3.5 KiB
C++

#ifndef __SIGNAL_HPP__
#define __SIGNAL_HPP__
// Author: Adrian Böckenkamp
// Date: 15.06.2011
#include <cassert>
#include <memory>
#include <iostream>
#ifndef __puma
#include <boost/thread.hpp>
#include <boost/interprocess/sync/named_semaphore.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/mutex.hpp>
#endif
namespace fi
{
#ifndef __puma
typedef boost::mutex Mutex; // lock/unlock
typedef boost::mutex::scoped_lock ScopeLock; // use RAII with lock/unlock mechanism
typedef boost::condition_variable ConditionVariable; // wait/notify_one
#else
typedef int Mutex;
typedef int ScopeLock;
typedef int ConditionVariable;
#endif
// Simulate a "private" semaphore using boost-mechanisms:
class Semaphore
{
private:
Mutex m_Mutex;
ConditionVariable m_CondVar;
unsigned long m_Value;
public:
// Create a semaphore object based on a mutex and a condition variable
// and initialize it to value "init".
Semaphore(unsigned long init = 0) : m_Value(init) { }
void post()
{
ScopeLock lock(m_Mutex);
++m_Value; // increase semaphore value:
#ifndef __puma
m_CondVar.notify_one(); // wake up other thread, currently waiting on condition var.
#endif
}
void wait()
{
ScopeLock lock(m_Mutex);
#ifndef __puma
while(!m_Value) // "wait-if-zero"
m_CondVar.wait(lock);
#endif
--m_Value; // decrease semaphore value
}
};
class Signal
{
private:
static Mutex m_InstanceMutex; // used to sync calls to getInst()
static std::auto_ptr<Signal> m_This; // the one and only instance
Semaphore m_semBochs;
Semaphore m_semContr;
Semaphore m_semSimCtrl;
bool m_Locked; // prevent misuse of thread-sync
// Singleton class (forbid creation, copying and assignment):
Signal()
: m_semBochs(0), m_semContr(0),
m_semSimCtrl(0), m_Locked(false) { }
Signal(Signal const& s)
: m_semBochs(), m_semContr(),
m_semSimCtrl(), m_Locked(false) { } // never called.
Signal& operator=(Signal const&) { return *this; } // dito.
~Signal() { }
friend class std::auto_ptr<Signal>;
public:
static Signal& getInst()
{
ScopeLock lock(m_InstanceMutex); // lock/unlock handled by RAII principle
if(!m_This.get())
m_This.reset(new Signal());
return (*m_This);
}
// Called from Experiment-Controller class ("beyond Bochs"):
void lockExperiment()
{
assert(!m_Locked &&
"[Signal::lockExperiment]: lockExperiment called twice without calling unlockExperiment() in between.");
m_Locked = true;
m_semContr.wait(); // suspend experiment process
}
// Called from Experiment-Controller class ("beyond Bochs"):
void unlockExperiment()
{
assert(m_Locked &&
"[Signal::unlockExperiment]: unlockExperiment called twice without calling lockExperiment() in between.");
m_Locked = false;
m_semBochs.post(); // resume experiment (continue bochs simulation)
}
// Called from Advice-Code ("within Bochs") to trigger event occurrence:
void signalEvent()
{
m_semContr.post(); // Signal event (to Experiment-Controller)
m_semBochs.wait(); // Wait upon handling to finish
}
// Called from Experiment-Controller to allow simulation start:
void startSimulation()
{
m_semSimCtrl.post();
}
// Called from Bochs, directly after thread creation for Experiment-Controller:
// (This ensures that Bochs waits until the experiment has been set up in the
// Experiment-Controller.)
void waitForStartup()
{
m_semSimCtrl.wait();
}
};
} // end-of-namespace: fi
#endif /* __SIGNAL_HPP__ */