// // OpenThread library, Copyright (C) 2002 - 2003 The Open Thread Group // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // // PThreadCondition.c++ - C++ Condition class built on top of posix threads. // ~~~~~~~~~~~~~~~~~~~~ // #if defined(_MSC_VER) || defined(__MINGW32__) # include #else # include #endif #include #include #include "PThreadConditionPrivateData.h" #include "PThreadMutexPrivateData.h" using namespace OpenThreads; #if defined(_MSC_VER) || defined(__MINGW32__) int gettimeofday(struct timeval* tp, void* tzp) { LARGE_INTEGER t; if(QueryPerformanceCounter(&t)) { /* hardware supports a performance counter */ static int been_here = 0; static LARGE_INTEGER f; if( !been_here ) { been_here = 1; QueryPerformanceFrequency(&f); } tp->tv_sec = t.QuadPart/f.QuadPart; tp->tv_usec = ((float)t.QuadPart/f.QuadPart*1000*1000) - (tp->tv_sec*1000*1000); } else { /* hardware doesn't support a performance counter, so get the time in a more traditional way. */ DWORD t; t = timeGetTime(); tp->tv_sec = t / 1000; tp->tv_usec = t % 1000; } /* 0 indicates that the call succeeded. */ return 0; } #endif //---------------------------------------------------------------------------- // This cancel cleanup handler is necessary to ensure that the barrier's // mutex gets unlocked on cancel. Otherwise deadlocks could occur with // later joins. // void condition_cleanup_handler(void *arg) { pthread_mutex_t *mutex = static_cast(arg); pthread_mutex_unlock(mutex); } //---------------------------------------------------------------------------- // // Decription: Constructor // // Use: public. // Condition::Condition() { PThreadConditionPrivateData *pd = new PThreadConditionPrivateData(); int status = pthread_cond_init( &pd->condition, NULL ); assert(status == 0); _prvData = static_cast(pd); } //---------------------------------------------------------------------------- // // Decription: Destructor // // Use: public. // Condition::~Condition() { PThreadConditionPrivateData *pd = static_cast(_prvData); int status = pthread_cond_destroy( &pd->condition ); assert(status == 0); delete pd; } //---------------------------------------------------------------------------- // // Decription: wait on a condition // // Use: public. // int Condition::wait(Mutex *mutex) { PThreadConditionPrivateData *pd = static_cast(_prvData); PThreadMutexPrivateData *mpd = static_cast(mutex->_prvData); int status; pthread_cleanup_push(condition_cleanup_handler, &mpd->mutex); status = pthread_cond_wait( &pd->condition, &mpd->mutex ); pthread_cleanup_pop(0); return status; } //---------------------------------------------------------------------------- // // Decription: wait on a condition, for a specified period of time // // Use: public. // int Condition::wait(Mutex *mutex, unsigned long int ms) { PThreadConditionPrivateData *pd = static_cast(_prvData); PThreadMutexPrivateData *mpd = static_cast(mutex->_prvData); struct ::timeval now; ::gettimeofday( &now, 0 ); // Wait time is now + ms milliseconds unsigned int sec = ms / 1000; unsigned int nsec = (ms % 1000) * 1000; struct timespec abstime; abstime.tv_sec = now.tv_sec + sec; abstime.tv_nsec = now.tv_usec*1000 + nsec; int status; pthread_cleanup_push(condition_cleanup_handler, &mpd->mutex); status = pthread_cond_timedwait( &pd->condition, &mpd->mutex, &abstime ); pthread_cleanup_pop(0); return status; } //---------------------------------------------------------------------------- // // Decription: signal a thread to wake up. // // Use: public. // int Condition::signal() { PThreadConditionPrivateData *pd = static_cast(_prvData); return pthread_cond_signal( &pd->condition ); } //---------------------------------------------------------------------------- // // Decription: signal many threads to wake up. // // Use: public. // int Condition::broadcast() { PThreadConditionPrivateData *pd = static_cast(_prvData); return pthread_cond_broadcast( &pd->condition ); }