169 lines
4.1 KiB
C++
169 lines
4.1 KiB
C++
|
|
#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:
|