// PThreadCondition.cxx #include "dataset_util/PThreadCondition.h" #include "dataset_util/FileStatus.h" #include #include #include #include #include using std::ostream; using std::cerr; using std::endl; using std::setw; //********************************************************************** // Local methods. //********************************************************************** // Debug message. void msg(const PThreadCondition* pcon, int value, char* txt) { if ( FileStatus("debug_PThreadCondition").exists() ) { //bool is_locked = pcon->is_locked(); cerr << "PC: " << setw(10) << pthread_self() << " con=" << setw(10) << pcon // << " lock=" << is_locked << " value=" << setw(2) << value << " " << txt << endl; } } //********************************************************************** // Implementation class. //********************************************************************** class PThreadCondition::Imp { public: pthread_mutex_t* pmtx; bool own_mutex; pthread_cond_t* pcon; int value; pthread_t lock_owner; pthread_mutex_t* pintmtx; }; //********************************************************************** // Static metnods. //********************************************************************** // Return codes. int PThreadCondition::ok() { return 0; } int PThreadCondition::invalid_argument() { return EINVAL; } int PThreadCondition::mutex_not_locked() { return 201; } int PThreadCondition::invalid_mutex_lock_count() { return 202; } int PThreadCondition::timed_out() { return ETIMEDOUT; } //********************************************************************** // Methods. //********************************************************************** // Constructor. // The internal mutex pinmtx protects the owner. PThreadCondition::PThreadCondition() : pimp(new Imp) { pimp->pmtx = new pthread_mutex_t; pthread_mutex_init(pimp->pmtx, 0); pimp->own_mutex = true; pimp->pcon = new pthread_cond_t; int cstat = pthread_cond_init(pimp->pcon, 0); assert( cstat == 0 ); pimp->value = 0; pimp->lock_owner = 0; pimp->pintmtx = new pthread_mutex_t; pthread_mutex_init(pimp->pintmtx, 0); } //********************************************************************** // Destructor. PThreadCondition::~PThreadCondition() { pthread_cond_destroy(pimp->pcon); delete pimp->pcon; if ( pimp->own_mutex ) { delete pimp->pmtx; } delete pimp->pintmtx; } //********************************************************************** // Set value. int PThreadCondition::set(int val) { pimp->value = val; msg(this, pimp->value, "set"); return 0; } //********************************************************************** // Get value. int PThreadCondition::get() const { msg(this, pimp->value, "get"); return pimp->value; } //********************************************************************** // Signal the condition. int PThreadCondition::signal() { msg(this, pimp->value, "signal"); return pthread_cond_signal(pimp->pcon); } //********************************************************************** // Broadcast the condition. int PThreadCondition::broadcast() { msg(this, pimp->value, "broadcast"); return pthread_cond_broadcast(pimp->pcon); } //********************************************************************** // Wait on the condition. int PThreadCondition::wait() { msg(this, pimp->value, "wait begin"); int rstat = pthread_cond_wait(pimp->pcon, pimp->pmtx); msg(this, pimp->value, "wait end"); return rstat; } //********************************************************************** // Wait on the condition with timeout. int PThreadCondition::wait(unsigned int dtim) { msg(this, pimp->value, "timedwait begin"); struct timespec timeout; timeout.tv_sec = time(0) + dtim; timeout.tv_nsec = 0; int rstat = pthread_cond_timedwait(pimp->pcon, pimp->pmtx, &timeout); msg(this, pimp->value, "timedwait end"); return rstat; } //********************************************************************** // Lock the mutex. int PThreadCondition::lock() { int lstat = pthread_mutex_lock(pimp->pmtx); assert( lstat == 0 ); if ( lstat == 0 ) { pthread_mutex_lock(pimp->pintmtx); pimp->lock_owner = pthread_self(); pthread_mutex_unlock(pimp->pintmtx); } return lstat; } //********************************************************************** // Try lock the mutex. int PThreadCondition::trylock() { msg(this, pimp->value, "trylock begin"); int lstat = pthread_mutex_trylock(pimp->pmtx); if ( lstat == 0 ) { pthread_mutex_lock(pimp->pintmtx); pimp->lock_owner = pthread_self(); pthread_mutex_unlock(pimp->pintmtx); } msg(this, pimp->value, "trylock end"); return lstat; } //********************************************************************** // Unlock the mutex. int PThreadCondition::unlock() { msg(this, pimp->value, "unlock"); assert( is_locked() ); pthread_mutex_lock(pimp->pintmtx); int ustat = pthread_mutex_unlock(pimp->pmtx); assert( ustat == 0 ); if ( ustat == 0 ) { pimp->lock_owner = 0; } pthread_mutex_unlock(pimp->pintmtx); return ustat; } //********************************************************************** // Is locked? bool PThreadCondition::is_locked() const { PThreadCondition& con = const_cast(*this); int lstat = con.trylock(); if ( lstat == 0 ) { int ustat = con.unlock(); assert( ustat == 0 ); return false; } assert( lstat == EBUSY ); return true; } //********************************************************************** // Lock owner. pthread_t PThreadCondition::lock_owner() const { pthread_mutex_lock(pimp->pintmtx); pthread_t owner = pimp->lock_owner; pthread_mutex_unlock(pimp->pintmtx); return owner; } //********************************************************************** // Free functions. //********************************************************************** // Output stream. ostream& operator<<(ostream& lhs, const PThreadCondition& rhs) { lhs << "Condition value is " << rhs.get(); if ( rhs.is_locked() ) { lhs << "; mutex is locked by thread " << rhs.lock_owner(); } else { lhs << "; mutex is unlocked"; } return lhs; } //**********************************************************************