/src/rt/sync/lock_and_signal.cpp
C++ | 169 lines | 118 code | 18 blank | 33 comment | 3 complexity | 81de49abf2f34bec62d3b3ee9c6a0f1e MD5 | raw file
1 2#include "../rust_globals.h" 3#include "lock_and_signal.h" 4 5/* 6 * A "lock-and-signal" pair. These are necessarily coupled on pthreads 7 * systems, and artificially coupled (by this file) on win32. Put 8 * together here to minimize ifdefs elsewhere; you must use them as 9 * if you're using a pthreads cvar+mutex pair. 10 */ 11 12// FIXME (#2683): This is not a portable way of specifying an invalid 13// pthread_t 14#define INVALID_THREAD 0 15 16 17#if defined(__WIN32__) 18lock_and_signal::lock_and_signal() 19#if defined(DEBUG_LOCKS) 20 : _holding_thread(INVALID_THREAD) 21#endif 22{ 23 _event = CreateEvent(NULL, FALSE, FALSE, NULL); 24 25 // If a CRITICAL_SECTION is not initialized with a spin count, it will 26 // default to 0, even on multi-processor systems. MSDN suggests using 27 // 4000. On single-processor systems, the spin count parameter is ignored 28 // and the critical section's spin count defaults to 0. 29 const DWORD SPIN_COUNT = 4000; 30 CHECKED(!InitializeCriticalSectionAndSpinCount(&_cs, SPIN_COUNT)); 31 32 // FIXME #2893 Consider checking 33 // GetProcAddress("InitializeCriticalSectionEx") 34 // so Windows >= Vista we can use CRITICAL_SECTION_NO_DEBUG_INFO to avoid 35 // allocating CRITICAL_SECTION debug info that is never released. See: 36 // http://stackoverflow.com/questions/804848/ 37 // critical-sections-leaking-memory-on-vista-win2008#889853 38} 39 40#else 41lock_and_signal::lock_and_signal() 42#if defined(DEBUG_LOCKS) 43 : _holding_thread(INVALID_THREAD) 44#endif 45{ 46 CHECKED(pthread_cond_init(&_cond, NULL)); 47 CHECKED(pthread_mutex_init(&_mutex, NULL)); 48} 49#endif 50 51lock_and_signal::~lock_and_signal() { 52#if defined(__WIN32__) 53 CloseHandle(_event); 54 DeleteCriticalSection(&_cs); 55#else 56 CHECKED(pthread_cond_destroy(&_cond)); 57 CHECKED(pthread_mutex_destroy(&_mutex)); 58#endif 59} 60 61void lock_and_signal::lock() { 62 must_not_have_lock(); 63#if defined(__WIN32__) 64 EnterCriticalSection(&_cs); 65#if defined(DEBUG_LOCKS) 66 _holding_thread = GetCurrentThreadId(); 67#endif 68#else 69 CHECKED(pthread_mutex_lock(&_mutex)); 70#if defined(DEBUG_LOCKS) 71 _holding_thread = pthread_self(); 72#endif 73#endif 74} 75 76void lock_and_signal::unlock() { 77 must_have_lock(); 78#if defined(DEBUG_LOCKS) 79 _holding_thread = INVALID_THREAD; 80#endif 81#if defined(__WIN32__) 82 LeaveCriticalSection(&_cs); 83#else 84 CHECKED(pthread_mutex_unlock(&_mutex)); 85#endif 86} 87 88/** 89 * Wait indefinitely until condition is signaled. 90 */ 91void lock_and_signal::wait() { 92 must_have_lock(); 93#if defined(DEBUG_LOCKS) 94 _holding_thread = INVALID_THREAD; 95#endif 96#if defined(__WIN32__) 97 LeaveCriticalSection(&_cs); 98 WaitForSingleObject(_event, INFINITE); 99 EnterCriticalSection(&_cs); 100 must_not_be_locked(); 101#if defined(DEBUG_LOCKS) 102 _holding_thread = GetCurrentThreadId(); 103#endif 104#else 105 CHECKED(pthread_cond_wait(&_cond, &_mutex)); 106 must_not_be_locked(); 107#if defined(DEBUG_LOCKS) 108 _holding_thread = pthread_self(); 109#endif 110#endif 111} 112 113/** 114 * Signal condition, and resume the waiting thread. 115 */ 116void lock_and_signal::signal() { 117#if defined(__WIN32__) 118 SetEvent(_event); 119#else 120 CHECKED(pthread_cond_signal(&_cond)); 121#endif 122} 123 124#if defined(DEBUG_LOCKS) 125bool lock_and_signal::lock_held_by_current_thread() 126{ 127#if defined(__WIN32__) 128 return _holding_thread == GetCurrentThreadId(); 129#else 130 return pthread_equal(_holding_thread, pthread_self()); 131#endif 132} 133#endif 134 135#if defined(DEBUG_LOCKS) 136void lock_and_signal::must_have_lock() { 137 assert(lock_held_by_current_thread() && "must have lock"); 138} 139void lock_and_signal::must_not_have_lock() { 140 assert(!lock_held_by_current_thread() && "must not have lock"); 141} 142void lock_and_signal::must_not_be_locked() { 143} 144#else 145void lock_and_signal::must_have_lock() { } 146void lock_and_signal::must_not_have_lock() { } 147void lock_and_signal::must_not_be_locked() { } 148#endif 149 150scoped_lock::scoped_lock(lock_and_signal &lock) 151 : lock(lock) 152{ 153 lock.lock(); 154} 155 156scoped_lock::~scoped_lock() 157{ 158 lock.unlock(); 159} 160 161// 162// Local Variables: 163// mode: C++ 164// fill-column: 78; 165// indent-tabs-mode: nil 166// c-basic-offset: 4 167// buffer-file-coding-system: utf-8-unix 168// compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'"; 169// End: