| |
| #include "../rust_globals.h" |
| #include "lock_and_signal.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. |
| */ |
| |
| // FIXME (#2683): This is not a portable way of specifying an invalid |
| // pthread_t |
| #define INVALID_THREAD 0 |
| |
| |
| #if defined(__WIN32__) |
| lock_and_signal::lock_and_signal() |
| #if defined(DEBUG_LOCKS) |
| : _holding_thread(INVALID_THREAD) |
| #endif |
| { |
| _event = CreateEvent(NULL, FALSE, FALSE, NULL); |
| |
| // If a CRITICAL_SECTION is not initialized with a spin count, it will |
| // default to 0, even on multi-processor systems. MSDN suggests using |
| // 4000. On single-processor systems, the spin count parameter is ignored |
| // and the critical section's spin count defaults to 0. |
| const DWORD SPIN_COUNT = 4000; |
| CHECKED(!InitializeCriticalSectionAndSpinCount(&_cs, SPIN_COUNT)); |
| |
| // FIXME #2893 Consider checking |
| // GetProcAddress("InitializeCriticalSectionEx") |
| // so Windows >= Vista we can use CRITICAL_SECTION_NO_DEBUG_INFO to avoid |
| // allocating CRITICAL_SECTION debug info that is never released. See: |
| // http://stackoverflow.com/questions/804848/ |
| // critical-sections-leaking-memory-on-vista-win2008#889853 |
| } |
| |
| #else |
| lock_and_signal::lock_and_signal() |
| #if defined(DEBUG_LOCKS) |
| : _holding_thread(INVALID_THREAD) |
| #endif |
| { |
| CHECKED(pthread_cond_init(&_cond, NULL)); |
| CHECKED(pthread_mutex_init(&_mutex, NULL)); |
| } |
| #endif |
| |
| lock_and_signal::~lock_and_signal() { |
| #if defined(__WIN32__) |
| CloseHandle(_event); |
| DeleteCriticalSection(&_cs); |
| #else |
| CHECKED(pthread_cond_destroy(&_cond)); |
| CHECKED(pthread_mutex_destroy(&_mutex)); |
| #endif |
| } |
| |
| void lock_and_signal::lock() { |
| must_not_have_lock(); |
| #if defined(__WIN32__) |
| EnterCriticalSection(&_cs); |
| #if defined(DEBUG_LOCKS) |
| _holding_thread = GetCurrentThreadId(); |
| #endif |
| #else |
| CHECKED(pthread_mutex_lock(&_mutex)); |
| #if defined(DEBUG_LOCKS) |
| _holding_thread = pthread_self(); |
| #endif |
| #endif |
| } |
| |
| void lock_and_signal::unlock() { |
| must_have_lock(); |
| #if defined(DEBUG_LOCKS) |
| _holding_thread = INVALID_THREAD; |
| #endif |
| #if defined(__WIN32__) |
| LeaveCriticalSection(&_cs); |
| #else |
| CHECKED(pthread_mutex_unlock(&_mutex)); |
| #endif |
| } |
| |
| /** |
| * Wait indefinitely until condition is signaled. |
| */ |
| void lock_and_signal::wait() { |
| must_have_lock(); |
| #if defined(DEBUG_LOCKS) |
| _holding_thread = INVALID_THREAD; |
| #endif |
| #if defined(__WIN32__) |
| LeaveCriticalSection(&_cs); |
| WaitForSingleObject(_event, INFINITE); |
| EnterCriticalSection(&_cs); |
| must_not_be_locked(); |
| #if defined(DEBUG_LOCKS) |
| _holding_thread = GetCurrentThreadId(); |
| #endif |
| #else |
| CHECKED(pthread_cond_wait(&_cond, &_mutex)); |
| must_not_be_locked(); |
| #if defined(DEBUG_LOCKS) |
| _holding_thread = pthread_self(); |
| #endif |
| #endif |
| } |
| |
| /** |
| * Signal condition, and resume the waiting thread. |
| */ |
| void lock_and_signal::signal() { |
| #if defined(__WIN32__) |
| SetEvent(_event); |
| #else |
| CHECKED(pthread_cond_signal(&_cond)); |
| #endif |
| } |
| |
| #if defined(DEBUG_LOCKS) |
| bool lock_and_signal::lock_held_by_current_thread() |
| { |
| #if defined(__WIN32__) |
| return _holding_thread == GetCurrentThreadId(); |
| #else |
| return pthread_equal(_holding_thread, pthread_self()); |
| #endif |
| } |
| #endif |
| |
| #if defined(DEBUG_LOCKS) |
| void lock_and_signal::must_have_lock() { |
| assert(lock_held_by_current_thread() && "must have lock"); |
| } |
| void lock_and_signal::must_not_have_lock() { |
| assert(!lock_held_by_current_thread() && "must not have lock"); |
| } |
| void lock_and_signal::must_not_be_locked() { |
| } |
| #else |
| void lock_and_signal::must_have_lock() { } |
| void lock_and_signal::must_not_have_lock() { } |
| void lock_and_signal::must_not_be_locked() { } |
| #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: |