Remove the C++ lock_and_signal type

A the same time this purges all runtime support needed for statically
initialized mutexes, moving all users over to the new Mutex type instead.
This commit is contained in:
Alex Crichton 2013-11-14 00:21:43 -08:00
parent 24eb1b445d
commit e8bf078802
13 changed files with 92 additions and 536 deletions

View File

@ -90,7 +90,6 @@ endif
endif
RUNTIME_CXXS_$(1)_$(2) := \
rt/sync/lock_and_signal.cpp \
rt/rust_builtin.cpp \
rt/rust_upcall.cpp \
rt/miniz.cpp \

View File

@ -138,21 +138,19 @@ Accessing environment variables is not generally threadsafe.
Serialize access through a global lock.
*/
fn with_env_lock<T>(f: &fn() -> T) -> T {
use unstable::mutex::{Mutex, MUTEX_INIT};
use unstable::finally::Finally;
static mut lock: Mutex = MUTEX_INIT;
unsafe {
return do (|| {
rust_take_env_lock();
lock.lock();
f()
}).finally {
rust_drop_env_lock();
lock.unlock();
};
}
extern {
fn rust_take_env_lock();
fn rust_drop_env_lock();
}
}
/// Returns a vector of (variable, value) pairs for all the environment

View File

@ -21,32 +21,42 @@
//! FIXME #7756: This has a lot of C glue for lack of globals.
use option::Option;
#[cfg(test)] use option::{Some, None};
#[cfg(test)] use realstd;
#[cfg(test)] use realargs = realstd::rt::args;
/// One-time global initialization.
pub unsafe fn init(argc: int, argv: **u8) {
imp::init(argc, argv)
}
#[cfg(not(test))]
pub unsafe fn init(argc: int, argv: **u8) { imp::init(argc, argv) }
#[cfg(test)]
pub unsafe fn init(argc: int, argv: **u8) { realargs::init(argc, argv) }
/// One-time global cleanup.
pub fn cleanup() {
imp::cleanup()
}
#[cfg(not(test))] pub fn cleanup() { imp::cleanup() }
#[cfg(test)] pub fn cleanup() { realargs::cleanup() }
/// Take the global arguments from global storage.
pub fn take() -> Option<~[~str]> {
imp::take()
#[cfg(not(test))] pub fn take() -> Option<~[~str]> { imp::take() }
#[cfg(test)] pub fn take() -> Option<~[~str]> {
match realargs::take() {
realstd::option::Some(a) => Some(a),
realstd::option::None => None,
}
}
/// Give the global arguments to global storage.
///
/// It is an error if the arguments already exist.
pub fn put(args: ~[~str]) {
imp::put(args)
}
#[cfg(not(test))] pub fn put(args: ~[~str]) { imp::put(args) }
#[cfg(test)] pub fn put(args: ~[~str]) { realargs::put(args) }
/// Make a clone of the global arguments.
pub fn clone() -> Option<~[~str]> {
imp::clone()
#[cfg(not(test))] pub fn clone() -> Option<~[~str]> { imp::clone() }
#[cfg(test)] pub fn clone() -> Option<~[~str]> {
match realargs::clone() {
realstd::option::Some(a) => Some(a),
realstd::option::None => None,
}
}
#[cfg(target_os = "linux")]
@ -58,9 +68,12 @@ mod imp {
use iter::Iterator;
use str;
use unstable::finally::Finally;
use unstable::mutex::{Mutex, MUTEX_INIT};
use util;
use vec;
static mut global_args_ptr: uint = 0;
pub unsafe fn init(argc: int, argv: **u8) {
let args = load_argc_and_argv(argc, argv);
put(args);
@ -94,20 +107,22 @@ mod imp {
}
fn with_lock<T>(f: &fn() -> T) -> T {
static mut lock: Mutex = MUTEX_INIT;
do (|| {
unsafe {
rust_take_global_args_lock();
lock.lock();
f()
}
}).finally {
unsafe {
rust_drop_global_args_lock();
lock.unlock();
}
}
}
fn get_global_ptr() -> *mut Option<~~[~str]> {
unsafe { rust_get_global_args_ptr() }
unsafe { cast::transmute(&global_args_ptr) }
}
// Copied from `os`.
@ -117,12 +132,6 @@ mod imp {
}
}
extern {
fn rust_take_global_args_lock();
fn rust_drop_global_args_lock();
fn rust_get_global_args_ptr() -> *mut Option<~~[~str]>;
}
#[cfg(test)]
mod tests {
use option::{Some, None};

View File

@ -21,17 +21,23 @@ use ptr;
use cell::Cell;
use option::{Option, Some, None};
use unstable::finally::Finally;
use unstable::mutex::{Mutex, MUTEX_INIT};
use tls = rt::thread_local_storage;
static mut RT_TLS_KEY: tls::Key = -1;
/// Initialize the TLS key. Other ops will fail if this isn't executed first.
pub fn init_tls_key() {
static mut lock: Mutex = MUTEX_INIT;
static mut initialized: bool = false;
unsafe {
rust_initialize_rt_tls_key(&mut RT_TLS_KEY);
extern {
fn rust_initialize_rt_tls_key(key: *mut tls::Key);
lock.lock();
if !initialized {
tls::create(&mut RT_TLS_KEY);
initialized = true;
}
lock.unlock();
}
}

View File

@ -14,7 +14,6 @@ use cell::Cell;
use clone::Clone;
use container::Container;
use iter::{Iterator, range};
use libc;
use option::{Some, None};
use os;
use path::GenericPath;
@ -361,11 +360,16 @@ pub fn cleanup_task(mut task: ~Task) {
/// Get a port number, starting at 9600, for use in tests
pub fn next_test_port() -> u16 {
use unstable::mutex::{Mutex, MUTEX_INIT};
static mut lock: Mutex = MUTEX_INIT;
static mut next_offset: u16 = 0;
unsafe {
return rust_dbg_next_port(base_port() as libc::uintptr_t) as u16;
}
extern {
fn rust_dbg_next_port(base: libc::uintptr_t) -> libc::uintptr_t;
let base = base_port();
lock.lock();
let ret = base + next_offset;
next_offset += 1;
lock.unlock();
return ret;
}
}
@ -395,13 +399,13 @@ The bots run multiple builds at the same time, and these builds
all want to use ports. This function figures out which workspace
it is running in and assigns a port range based on it.
*/
fn base_port() -> uint {
fn base_port() -> u16 {
use os;
use str::StrSlice;
use vec::ImmutableVector;
let base = 9600u;
let range = 1000;
let base = 9600u16;
let range = 1000u16;
let bases = [
("32-opt", base + range * 1),

View File

@ -1141,22 +1141,10 @@ fn test_spawn_sched_childs_on_default_sched() {
po.recv();
}
#[cfg(test)]
mod testrt {
use libc;
extern {
pub fn rust_dbg_lock_create() -> *libc::c_void;
pub fn rust_dbg_lock_destroy(lock: *libc::c_void);
pub fn rust_dbg_lock_lock(lock: *libc::c_void);
pub fn rust_dbg_lock_unlock(lock: *libc::c_void);
pub fn rust_dbg_lock_wait(lock: *libc::c_void);
pub fn rust_dbg_lock_signal(lock: *libc::c_void);
}
}
#[test]
fn test_spawn_sched_blocking() {
use unstable::mutex::Mutex;
unsafe {
// Testing that a task in one scheduler can block in foreign code
@ -1165,16 +1153,18 @@ fn test_spawn_sched_blocking() {
let (start_po, start_ch) = stream();
let (fin_po, fin_ch) = stream();
let lock = testrt::rust_dbg_lock_create();
let mut lock = Mutex::new();
let lock2 = Cell::new(lock.clone());
do spawn_sched(SingleThreaded) {
testrt::rust_dbg_lock_lock(lock);
let mut lock = lock2.take();
lock.lock();
start_ch.send(());
// Block the scheduler thread
testrt::rust_dbg_lock_wait(lock);
testrt::rust_dbg_lock_unlock(lock);
lock.wait();
lock.unlock();
fin_ch.send(());
};
@ -1201,11 +1191,11 @@ fn test_spawn_sched_blocking() {
let child_ch = setup_po.recv();
child_ch.send(20);
pingpong(&parent_po, &child_ch);
testrt::rust_dbg_lock_lock(lock);
testrt::rust_dbg_lock_signal(lock);
testrt::rust_dbg_lock_unlock(lock);
lock.lock();
lock.signal();
lock.unlock();
fin_po.recv();
testrt::rust_dbg_lock_destroy(lock);
lock.destroy();
}
}
}

View File

@ -154,6 +154,9 @@ pub mod dl {
}
pub fn check_for_errors_in<T>(f: &fn()->T) -> Result<T, ~str> {
use unstable::mutex::{Mutex, MUTEX_INIT};
static mut lock: Mutex = MUTEX_INIT;
unsafe {
// dlerror isn't thread safe, so we need to lock around this entire
// sequence. `atomically` asserts that we don't do anything that
@ -161,7 +164,7 @@ pub mod dl {
// the scheduler if it happens while the lock is held.
// FIXME #9105 use a Rust mutex instead of C++ mutexes.
do atomically {
rust_take_dlerror_lock();
lock.lock();
let _old_error = dlerror();
let result = f();
@ -172,7 +175,7 @@ pub mod dl {
} else {
Err(str::raw::from_c_str(last_error))
};
rust_drop_dlerror_lock();
lock.unlock();
ret
}
}
@ -192,11 +195,6 @@ pub mod dl {
Local = 0,
}
extern {
fn rust_take_dlerror_lock();
fn rust_drop_dlerror_lock();
}
#[link_name = "dl"]
extern {
fn dlopen(filename: *libc::c_char, flag: libc::c_int) -> *libc::c_void;

View File

@ -11,12 +11,12 @@
use cast;
use cell::Cell;
use comm;
use libc;
use ptr;
use option::{Option,Some,None};
use task;
use unstable::atomics::{AtomicOption,AtomicUint,Acquire,Release,Relaxed,SeqCst};
use unstable::finally::Finally;
use unstable::mutex::Mutex;
use ops::Drop;
use clone::Clone;
use kinds::Send;
@ -319,17 +319,14 @@ pub unsafe fn atomically<U>(f: &fn() -> U) -> U {
}
}
#[allow(non_camel_case_types)] // runtime type
type rust_little_lock = *libc::c_void;
pub struct LittleLock {
priv l: rust_little_lock,
priv l: Mutex,
}
impl Drop for LittleLock {
fn drop(&mut self) {
unsafe {
rust_destroy_little_lock(self.l);
self.l.destroy();
}
}
}
@ -338,29 +335,31 @@ impl LittleLock {
pub fn new() -> LittleLock {
unsafe {
LittleLock {
l: rust_create_little_lock()
l: Mutex::new()
}
}
}
pub unsafe fn lock<T>(&self, f: &fn() -> T) -> T {
let this = cast::transmute_mut(self);
do atomically {
rust_lock_little_lock(self.l);
this.l.lock();
do (|| {
f()
}).finally {
rust_unlock_little_lock(self.l);
this.l.unlock();
}
}
}
pub unsafe fn try_lock<T>(&self, f: &fn() -> T) -> Option<T> {
let this = cast::transmute_mut(self);
do atomically {
if rust_trylock_little_lock(self.l) {
if this.l.trylock() {
Some(do (|| {
f()
}).finally {
rust_unlock_little_lock(self.l);
this.l.unlock();
})
} else {
None
@ -369,18 +368,20 @@ impl LittleLock {
}
pub unsafe fn signal(&self) {
rust_signal_little_lock(self.l);
let this = cast::transmute_mut(self);
this.l.signal();
}
pub unsafe fn lock_and_wait(&self, f: &fn() -> bool) {
let this = cast::transmute_mut(self);
do atomically {
rust_lock_little_lock(self.l);
this.l.lock();
do (|| {
if f() {
rust_wait_little_lock(self.l);
this.l.wait();
}
}).finally {
rust_unlock_little_lock(self.l);
this.l.unlock();
}
}
}
@ -489,16 +490,6 @@ impl<T:Send> Exclusive<T> {
}
}
extern {
fn rust_create_little_lock() -> rust_little_lock;
fn rust_destroy_little_lock(lock: rust_little_lock);
fn rust_trylock_little_lock(lock: rust_little_lock) -> bool;
fn rust_lock_little_lock(lock: rust_little_lock);
fn rust_unlock_little_lock(lock: rust_little_lock);
fn rust_signal_little_lock(lock: rust_little_lock);
fn rust_wait_little_lock(lock: rust_little_lock);
}
#[cfg(test)]
mod tests {
use cell::Cell;

View File

@ -10,7 +10,7 @@
/* Foreign builtins. */
#include "sync/lock_and_signal.h"
#include "rust_globals.h"
#include "vg/valgrind.h"
#include <time.h>
@ -379,41 +379,6 @@ rust_mktime(rust_tm* timeptr) {
return mktime(&t);
}
extern "C" lock_and_signal*
rust_create_little_lock() {
return new lock_and_signal();
}
extern "C" void
rust_destroy_little_lock(lock_and_signal *lock) {
delete lock;
}
extern "C" void
rust_lock_little_lock(lock_and_signal *lock) {
lock->lock();
}
extern "C" bool
rust_trylock_little_lock(lock_and_signal *lock) {
return lock->try_lock();
}
extern "C" void
rust_unlock_little_lock(lock_and_signal *lock) {
lock->unlock();
}
extern "C" void
rust_wait_little_lock(lock_and_signal *lock) {
lock->wait();
}
extern "C" void
rust_signal_little_lock(lock_and_signal *lock) {
lock->signal();
}
#ifndef _WIN32
#include <sys/types.h>
#include <dirent.h>
@ -440,34 +405,6 @@ rust_readdir() {
#endif
#ifndef _WIN32
typedef pthread_key_t tls_key;
#else
typedef DWORD tls_key;
#endif
// Initialize the TLS key used by the new scheduler
extern "C" CDECL void
rust_initialize_rt_tls_key(tls_key *key) {
static lock_and_signal init_lock;
static bool initialized = false;
scoped_lock with(init_lock);
if (!initialized) {
#ifndef _WIN32
assert(!pthread_key_create(key, NULL));
#else
*key = TlsAlloc();
assert(*key != TLS_OUT_OF_INDEXES);
#endif
initialized = true;
}
}
typedef void *(rust_try_fn)(void*, void*);
extern "C" CDECL uintptr_t
@ -538,48 +475,6 @@ rust_get_num_cpus() {
return get_num_cpus();
}
static lock_and_signal global_args_lock;
static uintptr_t global_args_ptr = 0;
extern "C" CDECL void
rust_take_global_args_lock() {
global_args_lock.lock();
}
extern "C" CDECL void
rust_drop_global_args_lock() {
global_args_lock.unlock();
}
extern "C" CDECL uintptr_t*
rust_get_global_args_ptr() {
return &global_args_ptr;
}
static lock_and_signal env_lock;
extern "C" CDECL void
rust_take_env_lock() {
env_lock.lock();
}
extern "C" CDECL void
rust_drop_env_lock() {
env_lock.unlock();
}
static lock_and_signal dlerror_lock;
extern "C" CDECL void
rust_take_dlerror_lock() {
dlerror_lock.lock();
}
extern "C" CDECL void
rust_drop_dlerror_lock() {
dlerror_lock.unlock();
}
extern "C" CDECL unsigned int
rust_valgrind_stack_register(void *start, void *end) {
return VALGRIND_STACK_REGISTER(start, end);

View File

@ -10,7 +10,7 @@
// Helper functions used only in tests
#include "sync/lock_and_signal.h"
#include "rust_globals.h"
// These functions are used in the unit tests for C ABI calls.
@ -34,41 +34,6 @@ rust_dbg_extern_identity_u8(char u) {
return u;
}
extern "C" CDECL lock_and_signal *
rust_dbg_lock_create() {
return new lock_and_signal();
}
extern "C" CDECL void
rust_dbg_lock_destroy(lock_and_signal *lock) {
assert(lock);
delete lock;
}
extern "C" CDECL void
rust_dbg_lock_lock(lock_and_signal *lock) {
assert(lock);
lock->lock();
}
extern "C" CDECL void
rust_dbg_lock_unlock(lock_and_signal *lock) {
assert(lock);
lock->unlock();
}
extern "C" CDECL void
rust_dbg_lock_wait(lock_and_signal *lock) {
assert(lock);
lock->wait();
}
extern "C" CDECL void
rust_dbg_lock_signal(lock_and_signal *lock) {
assert(lock);
lock->signal();
}
typedef void *(*dbg_callback)(void*);
extern "C" CDECL void *
@ -160,17 +125,6 @@ rust_dbg_extern_identity_TwoDoubles(TwoDoubles u) {
return u;
}
// Generates increasing port numbers for network testing
extern "C" CDECL uintptr_t
rust_dbg_next_port(uintptr_t base_port) {
static lock_and_signal dbg_port_lock;
static uintptr_t next_offset = 0;
scoped_lock with(dbg_port_lock);
uintptr_t this_port = base_port + next_offset;
next_offset += 1;
return this_port;
}
extern "C" CDECL intptr_t
rust_get_test_int() {
return 1;

View File

@ -26,21 +26,8 @@ rust_win32_rand_gen
rust_win32_rand_release
upcall_rust_personality
upcall_reset_stack_limit
rust_dbg_lock_create
rust_dbg_lock_destroy
rust_dbg_lock_lock
rust_dbg_lock_unlock
rust_dbg_lock_wait
rust_dbg_lock_signal
rust_dbg_call
rust_dbg_do_nothing
rust_create_little_lock
rust_destroy_little_lock
rust_lock_little_lock
rust_trylock_little_lock
rust_unlock_little_lock
rust_signal_little_lock
rust_wait_little_lock
tdefl_compress_mem_to_heap
tinfl_decompress_mem_to_heap
rust_swap_registers
@ -59,19 +46,12 @@ rust_dbg_extern_return_TwoU32s
rust_dbg_extern_return_TwoU64s
rust_dbg_extern_identity_double
rust_dbg_extern_identity_u8
rust_initialize_rt_tls_key
rust_dbg_next_port
rust_try
rust_begin_unwind
rust_valgrind_stack_register
rust_valgrind_stack_deregister
rust_take_env_lock
rust_drop_env_lock
rust_running_on_valgrind
rust_get_num_cpus
rust_get_global_args_ptr
rust_take_global_args_lock
rust_drop_global_args_lock
rust_get_test_int
rust_pthread_mutex_t_size
rust_pthread_cond_t_size

View File

@ -1,205 +0,0 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#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
}
bool lock_and_signal::try_lock() {
must_not_have_lock();
#if defined(__WIN32__)
if (TryEnterCriticalSection(&_cs)) {
#if defined(DEBUG_LOCKS)
_holding_thread = GetCurrentThreadId();
#endif
return true;
}
#else // non-windows
int trylock = pthread_mutex_trylock(&_mutex);
if (trylock == 0) {
#if defined(DEBUG_LOCKS)
_holding_thread = pthread_self();
#endif
return true;
} else if (trylock == EBUSY) {
// EBUSY means lock was already held by someone else
return false;
}
// abort on all other errors
CHECKED(trylock);
#endif
return false;
}
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:

View File

@ -1,63 +0,0 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#ifndef LOCK_AND_SIGNAL_H
#define LOCK_AND_SIGNAL_H
#include "rust_globals.h"
#ifndef RUST_NDEBUG
#define DEBUG_LOCKS
#endif
class lock_and_signal {
#if defined(__WIN32__)
HANDLE _event;
CRITICAL_SECTION _cs;
#if defined(DEBUG_LOCKS)
DWORD _holding_thread;
#endif
#else
pthread_cond_t _cond;
pthread_mutex_t _mutex;
#if defined(DEBUG_LOCKS)
pthread_t _holding_thread;
#endif
#endif
#if defined(DEBUG_LOCKS)
bool lock_held_by_current_thread();
#endif
void must_not_be_locked();
public:
lock_and_signal();
virtual ~lock_and_signal();
void lock();
bool try_lock();
void unlock();
void wait();
void signal();
void must_have_lock();
void must_not_have_lock();
};
class scoped_lock {
lock_and_signal &lock;
public:
scoped_lock(lock_and_signal &lock);
~scoped_lock();
};
#endif /* LOCK_AND_SIGNAL_H */