mirror of
https://github.com/rust-lang/rust.git
synced 2026-05-28 20:16:58 +03:00
f76e6c39f6
This simplifies the check for thread ownership by removing the _locked flag and just comparing against the thread ID of the last thread to take the lock. If the running thread took the lock _holding_thread will be equal to pthread_self(); if _holding_thread is some other value then the running thread does not have the lock. Setting a pthread_t to 0 like this is not portable but should work on every platform we are likely to care about for the near future.
168 lines
4.0 KiB
C++
168 lines
4.0 KiB
C++
#include <assert.h>
|
|
#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"
|
|
|
|
// FIXME: 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()
|
|
: _holding_thread(INVALID_THREAD)
|
|
{
|
|
// 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()
|
|
: _holding_thread(INVALID_THREAD)
|
|
{
|
|
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
|
|
}
|
|
|
|
void lock_and_signal::lock() {
|
|
#if defined(__WIN32__)
|
|
EnterCriticalSection(&_cs);
|
|
_holding_thread = GetCurrentThreadId();
|
|
#else
|
|
CHECKED(pthread_mutex_lock(&_mutex));
|
|
_holding_thread = pthread_self();
|
|
#endif
|
|
}
|
|
|
|
void lock_and_signal::unlock() {
|
|
_holding_thread = INVALID_THREAD;
|
|
#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) {
|
|
assert(lock_held_by_current_thread());
|
|
_holding_thread = INVALID_THREAD;
|
|
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
|
|
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 _holding_thread == GetCurrentThreadId();
|
|
#else
|
|
return pthread_equal(_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:
|