BURTON Mark
Builds for 1 pipeline passed in 6 minutes 33 seconds

use a mutex to ensure start-up is determanistic

(also cleanup the thread code a little for readibility)
... ... @@ -82,8 +82,9 @@ public:
private:
std::list<source_entry> sources;
pthread_cond_t cnd;
pthread_mutex_t cnd_mutex;
cond_mutex start_mutex;
std::list<source_entry>::iterator start_source;
cond_mutex cnd_mutex;
sc_core::sc_time backWindow;
sc_core::sc_time frontWindow;
sc_core::sc_time backSourceWindow;
... ... @@ -92,30 +93,32 @@ private:
async_event checkWindowEvent;
bool have_d_mutex;
fifo_mutex d_mutex;
public:
void unlock() {
pthread_mutex_lock(&cnd_mutex);
cnd_mutex.lock();
active++;
// we should not need to notify checkWindowEvent here.
pthread_cond_broadcast(&cnd); // kick sources
pthread_mutex_unlock(&cnd_mutex);
cnd_mutex.broadcast(); // kick sources
cnd_mutex.unlock();
}
// called at the end of a transaction (from SystemC).
void lock() {
pthread_mutex_lock(&cnd_mutex);
cnd_mutex.lock();
active--;
// must notify checkWindowEvent here to give SystemC something to do
checkWindowEvent.notify();
pthread_mutex_unlock(&cnd_mutex);
cnd_mutex.unlock();
}
SC_CTOR(centralSyncPolicy)
: deterministic("deterministic",false)
, sc_behind_mode("sc_behind",false)
, sources()
, start_mutex()
, start_source(sources.begin())
, cnd_mutex()
, backWindow(SC_ZERO_TIME), frontWindow(SC_ZERO_TIME), sc_is_back_window(false)
, active(0)
, d_mutex()
... ... @@ -127,9 +130,6 @@ public:
sensitive << checkWindowEvent;
dont_initialize();
pthread_mutex_init(&cnd_mutex, NULL);
pthread_cond_init(&cnd, NULL);
have_d_mutex=false;
/* deterministic value here will always be the default value (lua file not parsed yet) */
}
... ... @@ -148,6 +148,8 @@ public:
*/
checkWindowEvent.notify(tlm_utils::tlm_quantumkeeper::get_global_quantum());
// COUT << " quantum " << tlm_utils::tlm_quantumkeeper::get_global_quantum() << "\n";
start_source=sources.begin();
start_mutex.broadcast();
}
~centralSyncPolicy() {
... ... @@ -161,33 +163,32 @@ public:
* Take the lock before you exit, will force others out of the critical region
* (preventing segfault on exit)
*/
pthread_mutex_lock(&cnd_mutex);
cnd_mutex.lock();
}
void initWindow(sc_core::sc_time t, source_entry *source, bool decoupled)
{
pthread_mutex_lock(&cnd_mutex);
cnd_mutex.lock();
source->end_time = t;
update_window();
source->decoupled=decoupled;
pthread_mutex_unlock(&cnd_mutex);
cnd_mutex.unlock();
}
void setWindow(sc_core::sc_time t, source_entry *source)
{
pthread_mutex_lock(&cnd_mutex);
cnd_mutex.lock();
source->end_time = t;
update_window();
if (source->decoupled) {
pthread_mutex_unlock(&cnd_mutex);
cnd_mutex.unlock();
return; // do not attempt to sync this source.
}
if (deterministic) {
if (t > (backWindow + source->quantum)) {
if (source->locked) {
// COUT << "Qemu "<<source->name<<" out\n";
source->locked = false;
d_mutex.unlock();
}
... ... @@ -196,32 +197,25 @@ public:
/* wait if we're ahead the backWindow plus a quantum */
while (t > (backWindow + source->quantum)) {
// COUT << "ahead wait sc_time:"<<sc_time_stamp()<< " our time:"<<t<< " backWindow:"<<backWindow<<" bwin+q "<<(backWindow + source->quantum)<<"\n";
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
ts.tv_sec += 5; // Wait 1 second
int p = pthread_cond_timedwait(&cnd, &cnd_mutex, &ts);
int p = cnd_mutex.timedwait();
if ( p != 0 ) {
SC_REPORT_ERROR("greenthreads", "Deadlock timeout reached");
break;
}
}
pthread_mutex_unlock(&cnd_mutex);
cnd_mutex.unlock();
if (deterministic) {
if (!source->locked) {
// COUT << "Qemu "<<source->name<<" knocking\n";
d_mutex.lock();
source->locked=true;
// COUT << "Qemu "<<source->name<<" in\n";
}
}
}
// MUST be called from SystemC thread.
source_entry *registerSource(const char* name, syncSource *source, uint64_t quantum) {
pthread_mutex_lock(&cnd_mutex);
cnd_mutex.lock();
sources.push_back(source_entry());
source_entry *entry = &(sources.back());
entry->source = source;
... ... @@ -229,10 +223,23 @@ public:
entry->quantum = sc_time(quantum, SC_NS);
entry->locked=false;
entry->name = name;
pthread_mutex_unlock(&cnd_mutex);
cnd_mutex.unlock();
return entry;
}
/* ensure that the start of simulation is deterministic
*/
void startRunning(source_entry *source)
{
start_mutex.lock();
while(&(*start_source) != source) {
start_mutex.timedwait();
}
start_source++;
start_mutex.unlock();
start_mutex.broadcast_l();
}
/*
* we are called when the window changes, or we call ourself
* Or - critically - we get interupted by a txn, and then the txn
... ... @@ -243,13 +250,12 @@ public:
void checkWindow()
{
// We may have been woken up to do somethign on behalf of a Qemu.
// COUT << "\n check window at "<<sc_time_stamp()<<"\n\n";
if (have_d_mutex) {
d_mutex.unlock();
have_d_mutex=false;
}
pthread_mutex_lock(&cnd_mutex);
cnd_mutex.lock();
if (sc_is_back_window) {
update_window();
}
... ... @@ -264,23 +270,18 @@ public:
have_d_mutex=true;
}
} else {
// COUT << "\n notify in at "<<sc_front_window<<"\n\n";
checkWindowEvent.notify(sc_front_window - sc_time_stamp());
}
} else {
/* Ensure there are no pending token requests. */
// COUT << "systemc locking sc time "<<sc_time_stamp()<<" sc_front_window "<<sc_front_window<<"\n";
if (active==0) {
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
ts.tv_sec += 5;
int p = pthread_cond_timedwait(&cnd, &cnd_mutex, &ts);
int p = cnd_mutex.timedwait();
if ( p != 0 ) {
SC_REPORT_ERROR("greenthreads", "Deadlock timeout reached");
}
}
}
pthread_mutex_unlock(&cnd_mutex);
cnd_mutex.unlock();
}
protected:
... ... @@ -322,7 +323,7 @@ protected:
/* If the windows changed, wake-up pending threads */
if (changed) {
checkWindowEvent.notify();
pthread_cond_broadcast(&cnd); // kick sources
cnd_mutex.broadcast(); // kick sources
}
}
};
... ... @@ -331,11 +332,12 @@ class syncSource {
source_entry *handle;
pthread_t sc_thread;
const char* name;
bool running=false;
public:
/*
* This class MUST be instanciated from SystemC (and in the SystemC thread)
*/
syncSource(const char* _name, uint64_t quantum, bool _decoupled = false):name(_name) {
syncSource(const char* _name, uint64_t quantum, bool _decoupled = false):name(_name) {
sc_thread = pthread_self();
handle = centralSyncPolicy::share.registerSource(name, this, quantum);
centralSyncPolicy::share.initWindow(SC_ZERO_TIME, handle, _decoupled);
... ... @@ -345,6 +347,10 @@ public:
if (pthread_equal(pthread_self(), sc_thread)) {
return;
}
if (!running) {
centralSyncPolicy::share.startRunning(handle);
running=true;
}
// COUT << "Sync "<<name<<" At sc_time:"<<sc_time_stamp()<< " sync time:"<<t<<"\n";
centralSyncPolicy::share.setWindow(t, handle);
}
... ...
... ... @@ -73,6 +73,43 @@ public:
};
/** Convenience timed cond implementation */
class cond_mutex {
pthread_cond_t cnd;
pthread_mutex_t mutex;
bool locked;
public:
cond_mutex() {
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cnd, NULL);
}
void lock()
{
pthread_mutex_lock(&mutex);
}
void unlock()
{
pthread_mutex_unlock(&mutex);
}
int timedwait()
{
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
ts.tv_sec += 5;
return pthread_cond_timedwait(&cnd, &mutex, &ts);
}
void broadcast()
{
pthread_cond_broadcast(&cnd);
}
void broadcast_l()
{
lock();
broadcast();
unlock();
}
};
/** Convenience fifo mutex (diterministic) */
class fifo_mutex {
pthread_cond_t cnd;
pthread_mutex_t mutex;
... ...