endif
RUNTIME_CXXS_$(1)_$(2) := \
- rt/sync/lock_and_signal.cpp \
rt/rust_builtin.cpp \
rt/rust_upcall.cpp \
rt/miniz.cpp \
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
//! 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")]
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);
}
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`.
}
}
- 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};
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();
}
}
use clone::Clone;
use container::Container;
use iter::{Iterator, range};
-use libc;
use option::{Some, None};
use os;
use path::GenericPath;
/// 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;
}
}
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),
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
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(());
};
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();
}
}
}
}
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
// 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();
} else {
Err(str::raw::from_c_str(last_error))
};
- rust_drop_dlerror_lock();
+ lock.unlock();
ret
}
}
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;
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;
}
}
-#[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();
}
}
}
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
}
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();
}
}
}
}
}
-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;
/* Foreign builtins. */
-#include "sync/lock_and_signal.h"
+#include "rust_globals.h"
#include "vg/valgrind.h"
#include <time.h>
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>
#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
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);
// 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.
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 *
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;
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
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
+++ /dev/null
-// 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:
+++ /dev/null
-// 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 */