PageRenderTime 34ms CodeModel.GetById 1ms app.highlight 26ms RepoModel.GetById 1ms app.codeStats 0ms

/src/rt/sync/lock_and_signal.cpp

http://github.com/jruderman/rust
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: