#include #include #include "monitor.H" namespace util { Monitor::Token::Token(Monitor *Mon) : #ifndef NDEBUG mon(Mon), mythread(pthread_self()) #else mon(Mon) #endif { } Monitor::Token::~Token() { mon->unlock(this); } bool Monitor::Token::wait(const struct timespec *abstime) { if (abstime) { return mon->wait(this, abstime); } else { mon->wait(this); return true; } } void Monitor::Token::notify() { mon->notify(this); } void Monitor::Token::notifyAll() { mon->notifyAll(this); } //////////////////////////////////////////////////////////////////////////// Monitor::Monitor() { pthread_mutexattr_t mattr; pthread_mutexattr_init(&mattr); //need it to recurse to one extra level pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init(&mutex, &mattr); pthread_cond_init(&cond, 0); #ifndef NDEBUG owned = false; owner = -1; #endif } bool Monitor::destroyMonitor(Monitor *&mon) { bool okay = (!mon)||mon->lockdepth.empty(); if (okay) { delete mon; mon = 0; } return okay; } Monitor::~Monitor() { pthread_mutex_destroy(&mutex); pthread_cond_destroy(&cond); } Monitor::token Monitor::getToken() { Token *ret = new Token(this); lock(ret); return token(ret); } void Monitor::lock(Token *tok) { assert(tok->rightThread()); //lock protects internal and external critical sections pthread_mutex_lock(&mutex); if (lockdepth.count(tok->mythread)) { assert(owned); assert(owner==tok->mythread); assert(lockdepth[tok->mythread]>0); ++(lockdepth[tok->mythread]); pthread_mutex_unlock(&mutex); //take care of recursion } else { assert(!owned); #ifndef NDEBUG owned = true; owner = tok->mythread; #endif lockdepth[tok->mythread] = 1; } } void Monitor::unlock(Token *tok) { assert(tok->rightThread()); assert(owned); assert(owner==tok->mythread); DepthMap::iterator found = lockdepth.find(tok->mythread); assert(found!=lockdepth.end()); --(found->second); if ((found->second)<=0) { assert((found->second)==0); //should never, EVER go negative #ifndef NDEBUG owned = false; #endif lockdepth.erase(found); pthread_mutex_unlock(&mutex); } } bool Monitor::wait(Token *tok, const struct timespec *abstime) { assert(tok->rightThread()); assert(owned); assert(owner==tok->mythread); #ifndef NDEBUG owned = false; #endif bool ret = (pthread_cond_timedwait(&cond, &mutex, abstime) != ETIMEDOUT); assert(!owned); #ifndef NDEBUG owned = true; owner = tok->mythread; #endif return ret; } void Monitor::wait(Token *tok) { assert(tok->rightThread()); assert(owned); assert(owner==tok->mythread); #ifndef NDEBUG owned = false; #endif pthread_cond_wait(&cond, &mutex); assert(!owned); #ifndef NDEBUG owned = true; owner = tok->mythread; #endif } void Monitor::notify(Token *tok) { assert(tok->rightThread()); assert(owned); assert(owner==tok->mythread); pthread_cond_signal(&cond); } void Monitor::notifyAll(Token *tok) { assert(tok->rightThread()); assert(owned); assert(owner==tok->mythread); pthread_cond_broadcast(&cond); } }