#include "../globals.h" /* * A "lock-and-signal" pair. These are necessarily coupled on pthreads * systems, and artificially coupled (by this file) on win32. Put * together here to minimize ifdefs elsewhere; you must use them as * if you're using a pthreads cvar+mutex pair. */ #include "lock_and_signal.h" #if defined(__WIN32__) lock_and_signal::lock_and_signal() : alive(true) { // FIXME: In order to match the behavior of pthread_cond_broadcast on // Windows, we create manual reset events. This however breaks the // behavior of pthread_cond_signal, fixing this is quite involved: // refer to: http://www.cs.wustl.edu/~schmidt/win32-cv-1.html _event = CreateEvent(NULL, TRUE, FALSE, NULL); InitializeCriticalSection(&_cs); } #else lock_and_signal::lock_and_signal() : _locked(false), alive(true) { CHECKED(pthread_cond_init(&_cond, NULL)); CHECKED(pthread_mutex_init(&_mutex, NULL)); } #endif lock_and_signal::~lock_and_signal() { #if defined(__WIN32__) CloseHandle(_event); #else CHECKED(pthread_cond_destroy(&_cond)); CHECKED(pthread_mutex_destroy(&_mutex)); #endif alive = false; } void lock_and_signal::lock() { #if defined(__WIN32__) EnterCriticalSection(&_cs); _holding_thread = GetCurrentThreadId(); #else CHECKED(pthread_mutex_lock(&_mutex)); _holding_thread = pthread_self(); #endif _locked = true; } void lock_and_signal::unlock() { _locked = false; #if defined(__WIN32__) LeaveCriticalSection(&_cs); #else CHECKED(pthread_mutex_unlock(&_mutex)); #endif } /** * Wait indefinitely until condition is signaled. */ void lock_and_signal::wait() { timed_wait(0); } bool lock_and_signal::timed_wait(size_t timeout_in_ms) { _locked = false; bool rv = true; #if defined(__WIN32__) LeaveCriticalSection(&_cs); DWORD timeout = timeout_in_ms == 0 ? INFINITE : timeout_in_ms; rv = WaitForSingleObject(_event, timeout) != WAIT_TIMEOUT; EnterCriticalSection(&_cs); _holding_thread = GetCurrentThreadId(); #else if (timeout_in_ms == 0) { CHECKED(pthread_cond_wait(&_cond, &_mutex)); } else { timeval time_val; gettimeofday(&time_val, NULL); timespec time_spec; time_spec.tv_sec = time_val.tv_sec + 0; time_spec.tv_nsec = time_val.tv_usec * 1000 + timeout_in_ms * 1000000; if(time_spec.tv_nsec >= 1000000000) { time_spec.tv_sec++; time_spec.tv_nsec -= 1000000000; } int cond_wait_status = pthread_cond_timedwait(&_cond, &_mutex, &time_spec); switch(cond_wait_status) { case 0: // successfully grabbed the lock. break; case ETIMEDOUT: // Oops, we timed out. rv = false; break; default: // Error CHECKED(cond_wait_status); } } _holding_thread = pthread_self(); #endif _locked = true; return rv; } /** * Signal condition, and resume the waiting thread. */ void lock_and_signal::signal() { #if defined(__WIN32__) SetEvent(_event); #else CHECKED(pthread_cond_signal(&_cond)); #endif } /** * Signal condition, and resume all waiting threads. */ void lock_and_signal::signal_all() { #if defined(__WIN32__) SetEvent(_event); #else CHECKED(pthread_cond_broadcast(&_cond)); #endif } bool lock_and_signal::lock_held_by_current_thread() { #if defined(__WIN32__) return _locked && _holding_thread == GetCurrentThreadId(); #else return _locked && _holding_thread == pthread_self(); #endif } scoped_lock::scoped_lock(lock_and_signal &lock) : lock(lock) { lock.lock(); } scoped_lock::~scoped_lock() { lock.unlock(); } // // Local Variables: // mode: C++ // fill-column: 78; // indent-tabs-mode: nil // c-basic-offset: 4 // buffer-file-coding-system: utf-8-unix // compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'"; // End: