auto merge of #10479 : alexcrichton/rust/native-mutex.rs, r=cmr
This adds a new `std::unstable::mutex` module which contains bindings to the platform-provided mutexes. This module is pretty much entirely unsafe to use, but is critical for the runtime and dropping our C++ dependency. The actual implementation is to do a compare-and-swap on an initially uninitialized pointer. Pthreads does allow for static initialization, so this wouldn't be necessary if we had all the proper headers and whatnot, but windows it looks like will always require some sort of compare-and-swap operation. For now, I didn't want to have to define all the pthreads headers, so I continue to just malloc the pthreads lock/cvar. After this, there's only one remaining C++ component of rust, and that's unwinding.
This commit is contained in:
commit
f5f5d5aac7
48
mk/clean.mk
48
mk/clean.mk
@ -12,13 +12,19 @@
|
||||
# Cleanup
|
||||
######################################################################
|
||||
|
||||
CLEAN_STAGE_RULES = \
|
||||
$(foreach stage, $(STAGES), \
|
||||
$(foreach host, $(CFG_HOST), \
|
||||
CLEAN_STAGE_RULES := \
|
||||
$(foreach stage, $(STAGES), \
|
||||
$(foreach host, $(CFG_HOST), \
|
||||
clean$(stage)_H_$(host) \
|
||||
$(foreach target, $(CFG_TARGET), \
|
||||
$(foreach target, $(CFG_TARGET), \
|
||||
clean$(stage)_T_$(target)_H_$(host))))
|
||||
|
||||
CLEAN_STAGE_RULES := $(CLEAN_STAGE_RULES) \
|
||||
$(foreach host, $(CFG_HOST), clean-generic-H-$(host))
|
||||
|
||||
CLEAN_STAGE_RULES := $(CLEAN_STAGE_RULES) \
|
||||
$(foreach host, $(CFG_TARGET), clean-generic-T-$(host))
|
||||
|
||||
CLEAN_LLVM_RULES = \
|
||||
$(foreach target, $(CFG_HOST), \
|
||||
clean-llvm$(target))
|
||||
@ -33,19 +39,6 @@ clean: clean-misc $(CLEAN_STAGE_RULES)
|
||||
|
||||
clean-misc:
|
||||
@$(call E, cleaning)
|
||||
$(Q)find $(CFG_BUILD)/rustllvm \
|
||||
$(CFG_BUILD)/rt \
|
||||
$(CFG_BUILD)/test \
|
||||
-name '*.[odasS]' -o \
|
||||
-name '*.so' -o \
|
||||
-name '*.dylib' -o \
|
||||
-name '*.dll' -o \
|
||||
-name '*.def' -o \
|
||||
-name '*.bc' \
|
||||
| xargs rm -f
|
||||
$(Q)find $(CFG_BUILD)\
|
||||
-name '*.dSYM' \
|
||||
| xargs rm -Rf
|
||||
$(Q)rm -f $(RUNTIME_OBJS) $(RUNTIME_DEF)
|
||||
$(Q)rm -f $(RUSTLLVM_LIB_OBJS) $(RUSTLLVM_OBJS_OBJS) $(RUSTLLVM_DEF)
|
||||
$(Q)rm -Rf $(DOCS)
|
||||
@ -60,6 +53,27 @@ clean-misc:
|
||||
$(Q)rm -Rf $(foreach sub, index styles files search javascript, \
|
||||
$(wildcard doc/*/$(sub)))
|
||||
|
||||
define CLEAN_GENERIC
|
||||
|
||||
clean-generic-$(2)-$(1):
|
||||
$(Q)find $(1)/rustllvm \
|
||||
$(1)/rt \
|
||||
$(1)/test \
|
||||
-name '*.[odasS]' -o \
|
||||
-name '*.so' -o \
|
||||
-name '*.dylib' -o \
|
||||
-name '*.dll' -o \
|
||||
-name '*.def' -o \
|
||||
-name '*.bc' \
|
||||
| xargs rm -f
|
||||
$(Q)find $(1)\
|
||||
-name '*.dSYM' \
|
||||
| xargs rm -Rf
|
||||
endef
|
||||
|
||||
$(foreach host, $(CFG_HOST), $(eval $(call CLEAN_GENERIC,$(host),H)))
|
||||
$(foreach targ, $(CFG_TARGET), $(eval $(call CLEAN_GENERIC,$(targ),T)))
|
||||
|
||||
define CLEAN_HOST_STAGE_N
|
||||
|
||||
clean$(1)_H_$(2):
|
||||
|
@ -206,7 +206,7 @@ CFG_LIB_GLOB_arm-apple-darwin = lib$(1)-*.dylib
|
||||
CFG_LIB_DSYM_GLOB_arm-apple-darwin = lib$(1)-*.dylib.dSYM
|
||||
CFG_GCCISH_CFLAGS_arm-apple-darwin := -Wall -Werror -g -fPIC $(CFG_IOS_FLAGS)
|
||||
CFG_GCCISH_CXXFLAGS_arm-apple-darwin := -fno-rtti $(CFG_IOS_FLAGS)
|
||||
CFG_GCCISH_LINK_FLAGS_arm-apple-darwin := -dynamiclib -lpthread -framework CoreServices -Wl,-no_compact_unwind
|
||||
CFG_GCCISH_LINK_FLAGS_arm-apple-darwin := -dynamiclib -lpthread -framework CoreServices -Wl,-no_compact_unwind
|
||||
CFG_GCCISH_DEF_FLAG_arm-apple-darwin := -Wl,-exported_symbols_list,
|
||||
CFG_GCCISH_PRE_LIB_FLAGS_arm-apple-darwin :=
|
||||
CFG_GCCISH_POST_LIB_FLAGS_arm-apple-darwin :=
|
||||
@ -506,7 +506,7 @@ define CFG_MAKE_TOOLCHAIN
|
||||
-c -o $$(1) $$(2)
|
||||
CFG_LINK_C_$(1) = $$(CC_$(1)) \
|
||||
$$(CFG_GCCISH_LINK_FLAGS) -o $$(1) \
|
||||
$$(CFG_GCCISH_LINK_FLAGS_$(1))) \
|
||||
$$(CFG_GCCISH_LINK_FLAGS_$(1)) \
|
||||
$$(CFG_GCCISH_DEF_FLAG_$(1))$$(3) $$(2) \
|
||||
$$(call CFG_INSTALL_NAME_$(1),$$(4))
|
||||
CFG_COMPILE_CXX_$(1) = $$(CXX_$(1)) \
|
||||
|
28
mk/rt.mk
28
mk/rt.mk
@ -90,14 +90,18 @@ endif
|
||||
endif
|
||||
|
||||
RUNTIME_CXXS_$(1)_$(2) := \
|
||||
rt/sync/lock_and_signal.cpp \
|
||||
rt/rust_builtin.cpp \
|
||||
rt/rust_upcall.cpp \
|
||||
rt/miniz.cpp \
|
||||
rt/rust_android_dummy.cpp \
|
||||
rt/rust_test_helpers.cpp
|
||||
rt/rust_cxx_glue.cpp
|
||||
|
||||
RUNTIME_CS_$(1)_$(2) :=
|
||||
RUNTIME_CS_$(1)_$(2) := \
|
||||
rt/rust_builtin.c \
|
||||
rt/rust_upcall.c \
|
||||
rt/miniz.c \
|
||||
rt/rust_android_dummy.c \
|
||||
rt/rust_test_helpers.c
|
||||
|
||||
# stage0 remove this after the next snapshot
|
||||
%.cpp:
|
||||
@touch tmp/foo.o
|
||||
|
||||
RUNTIME_S_$(1)_$(2) := rt/arch/$$(HOST_$(1))/_context.S \
|
||||
rt/arch/$$(HOST_$(1))/record_sp.S
|
||||
@ -115,7 +119,7 @@ ALL_OBJ_FILES += $$(RUNTIME_OBJS_$(1)_$(2))
|
||||
MORESTACK_OBJS_$(1)_$(2) := $$(RT_BUILD_DIR_$(1)_$(2))/arch/$$(HOST_$(1))/morestack.o
|
||||
ALL_OBJ_FILES += $$(MORESTACK_OBJS_$(1)_$(2))
|
||||
|
||||
$$(RT_BUILD_DIR_$(1)_$(2))/%.o: rt/%.cpp $$(MKFILE_DEPS)
|
||||
$$(RT_BUILD_DIR_$(1)_$(2))/rust_cxx_glue.o: rt/rust_cxx_glue.cpp $$(MKFILE_DEPS)
|
||||
@$$(call E, compile: $$@)
|
||||
$$(Q)$$(call CFG_COMPILE_CXX_$(1), $$@, $$(RUNTIME_INCS_$(1)_$(2)) \
|
||||
$$(SNAP_DEFINES) $$(RUNTIME_CXXFLAGS_$(1)_$(2))) $$<
|
||||
@ -242,13 +246,13 @@ endif
|
||||
UV_SUPPORT_NAME_$(1) := $$(call CFG_STATIC_LIB_NAME_$(1),uv_support)
|
||||
UV_SUPPORT_DIR_$(1) := $$(RT_OUTPUT_DIR_$(1))/uv_support
|
||||
UV_SUPPORT_LIB_$(1) := $$(UV_SUPPORT_DIR_$(1))/$$(UV_SUPPORT_NAME_$(1))
|
||||
UV_SUPPORT_CS_$(1) := rt/rust_uv.cpp
|
||||
UV_SUPPORT_OBJS_$(1) := $$(UV_SUPPORT_CS_$(1):rt/%.cpp=$$(UV_SUPPORT_DIR_$(1))/%.o)
|
||||
UV_SUPPORT_CS_$(1) := rt/rust_uv.c
|
||||
UV_SUPPORT_OBJS_$(1) := $$(UV_SUPPORT_CS_$(1):rt/%.c=$$(UV_SUPPORT_DIR_$(1))/%.o)
|
||||
|
||||
$$(UV_SUPPORT_DIR_$(1))/%.o: rt/%.cpp
|
||||
$$(UV_SUPPORT_DIR_$(1))/%.o: rt/%.c
|
||||
@$$(call E, compile: $$@)
|
||||
@mkdir -p $$(@D)
|
||||
$$(Q)$$(call CFG_COMPILE_CXX_$(1), $$@, \
|
||||
$$(Q)$$(call CFG_COMPILE_C_$(1), $$@, \
|
||||
-I $$(S)src/libuv/include \
|
||||
$$(RUNTIME_CFLAGS_$(1))) $$<
|
||||
|
||||
|
@ -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
|
||||
|
@ -21,46 +21,60 @@
|
||||
//! 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")]
|
||||
#[cfg(target_os = "android")]
|
||||
#[cfg(target_os = "freebsd")]
|
||||
mod imp {
|
||||
use cast;
|
||||
use libc;
|
||||
use option::{Option, Some, None};
|
||||
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 +108,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 +133,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};
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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),
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -24,6 +24,7 @@ pub mod simd;
|
||||
#[cfg(not(test))]
|
||||
pub mod lang;
|
||||
pub mod sync;
|
||||
pub mod mutex;
|
||||
pub mod atomics;
|
||||
pub mod raw;
|
||||
|
||||
|
336
src/libstd/unstable/mutex.rs
Normal file
336
src/libstd/unstable/mutex.rs
Normal file
@ -0,0 +1,336 @@
|
||||
// Copyright 2013 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.
|
||||
|
||||
//! A native mutex and condition variable type
|
||||
//!
|
||||
//! This module contains bindings to the platform's native mutex/condition
|
||||
//! variable primitives. It provides a single type, `Mutex`, which can be
|
||||
//! statically initialized via the `MUTEX_INIT` value. This object serves as both a
|
||||
//! mutex and a condition variable simultaneously.
|
||||
//!
|
||||
//! The lock is lazily initialized, but it can only be unsafely destroyed. A
|
||||
//! statically initialized lock doesn't necessarily have a time at which it can
|
||||
//! get deallocated. For this reason, there is no `Drop` implementation of the
|
||||
//! mutex, but rather the `destroy()` method must be invoked manually if
|
||||
//! destruction of the mutex is desired.
|
||||
//!
|
||||
//! It is not recommended to use this type for idiomatic rust use. This type is
|
||||
//! appropriate where no other options are available, but other rust concurrency
|
||||
//! primitives should be used before this type.
|
||||
//!
|
||||
//! # Example
|
||||
//!
|
||||
//! use std::unstable::mutex::{Mutex, MUTEX_INIT};
|
||||
//!
|
||||
//! // Use a statically initialized mutex
|
||||
//! static mut lock: Mutex = MUTEX_INIT;
|
||||
//!
|
||||
//! unsafe {
|
||||
//! lock.lock();
|
||||
//! lock.unlock();
|
||||
//! }
|
||||
//!
|
||||
//! // Use a normally initialied mutex
|
||||
//! let mut lock = Mutex::new();
|
||||
//! unsafe {
|
||||
//! lock.lock();
|
||||
//! lock.unlock();
|
||||
//! lock.destroy();
|
||||
//! }
|
||||
|
||||
#[allow(non_camel_case_types)];
|
||||
|
||||
use libc::c_void;
|
||||
use unstable::atomics;
|
||||
|
||||
pub struct Mutex {
|
||||
// pointers for the lock/cond handles, atomically updated
|
||||
priv lock: atomics::AtomicUint,
|
||||
priv cond: atomics::AtomicUint,
|
||||
}
|
||||
|
||||
pub static MUTEX_INIT: Mutex = Mutex {
|
||||
lock: atomics::INIT_ATOMIC_UINT,
|
||||
cond: atomics::INIT_ATOMIC_UINT,
|
||||
};
|
||||
|
||||
impl Mutex {
|
||||
/// Creates a new mutex, with the lock/condition variable pre-initialized
|
||||
pub unsafe fn new() -> Mutex {
|
||||
Mutex {
|
||||
lock: atomics::AtomicUint::new(imp::init_lock() as uint),
|
||||
cond: atomics::AtomicUint::new(imp::init_cond() as uint),
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new copy of this mutex. This is an unsafe operation because
|
||||
/// there is no reference counting performed on this type.
|
||||
///
|
||||
/// This function may only be called on mutexes which have had both the
|
||||
/// internal condition variable and lock initialized. This means that the
|
||||
/// mutex must have been created via `new`, or usage of it has already
|
||||
/// initialized the internal handles.
|
||||
///
|
||||
/// This is a dangerous function to call as both this mutex and the returned
|
||||
/// mutex will share the same handles to the underlying mutex/condition
|
||||
/// variable. Care must be taken to ensure that deallocation happens
|
||||
/// accordingly.
|
||||
pub unsafe fn clone(&self) -> Mutex {
|
||||
let lock = self.lock.load(atomics::Relaxed);
|
||||
let cond = self.cond.load(atomics::Relaxed);
|
||||
assert!(lock != 0);
|
||||
assert!(cond != 0);
|
||||
Mutex {
|
||||
lock: atomics::AtomicUint::new(lock),
|
||||
cond: atomics::AtomicUint::new(cond),
|
||||
}
|
||||
}
|
||||
|
||||
/// Acquires this lock. This assumes that the current thread does not
|
||||
/// already hold the lock.
|
||||
pub unsafe fn lock(&mut self) { imp::lock(self.getlock()) }
|
||||
|
||||
/// Attempts to acquire the lock. The value returned is whether the lock was
|
||||
/// acquired or not
|
||||
pub unsafe fn trylock(&mut self) -> bool { imp::trylock(self.getlock()) }
|
||||
|
||||
/// Unlocks the lock. This assumes that the current thread already holds the
|
||||
/// lock.
|
||||
pub unsafe fn unlock(&mut self) { imp::unlock(self.getlock()) }
|
||||
|
||||
/// Block on the internal condition variable.
|
||||
///
|
||||
/// This function assumes that the lock is already held
|
||||
pub unsafe fn wait(&mut self) { imp::wait(self.getcond(), self.getlock()) }
|
||||
|
||||
/// Signals a thread in `wait` to wake up
|
||||
pub unsafe fn signal(&mut self) { imp::signal(self.getcond()) }
|
||||
|
||||
/// This function is especially unsafe because there are no guarantees made
|
||||
/// that no other thread is currently holding the lock or waiting on the
|
||||
/// condition variable contained inside.
|
||||
pub unsafe fn destroy(&mut self) {
|
||||
imp::free_lock(self.lock.swap(0, atomics::Relaxed));
|
||||
imp::free_cond(self.cond.swap(0, atomics::Relaxed));
|
||||
}
|
||||
|
||||
unsafe fn getlock(&mut self) -> *c_void {
|
||||
match self.lock.load(atomics::Relaxed) {
|
||||
0 => {}
|
||||
n => return n as *c_void
|
||||
}
|
||||
let lock = imp::init_lock();
|
||||
match self.lock.compare_and_swap(0, lock, atomics::SeqCst) {
|
||||
0 => return lock as *c_void,
|
||||
_ => {}
|
||||
}
|
||||
imp::free_lock(lock);
|
||||
return self.lock.load(atomics::Relaxed) as *c_void;
|
||||
}
|
||||
|
||||
unsafe fn getcond(&mut self) -> *c_void {
|
||||
match self.cond.load(atomics::Relaxed) {
|
||||
0 => {}
|
||||
n => return n as *c_void
|
||||
}
|
||||
let cond = imp::init_cond();
|
||||
match self.cond.compare_and_swap(0, cond, atomics::SeqCst) {
|
||||
0 => return cond as *c_void,
|
||||
_ => {}
|
||||
}
|
||||
imp::free_cond(cond);
|
||||
return self.cond.load(atomics::Relaxed) as *c_void;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
mod imp {
|
||||
use libc::c_void;
|
||||
use libc;
|
||||
use ptr;
|
||||
|
||||
type pthread_mutex_t = libc::c_void;
|
||||
type pthread_mutexattr_t = libc::c_void;
|
||||
type pthread_cond_t = libc::c_void;
|
||||
type pthread_condattr_t = libc::c_void;
|
||||
|
||||
pub unsafe fn init_lock() -> uint {
|
||||
let block = libc::malloc(rust_pthread_mutex_t_size() as libc::size_t);
|
||||
assert!(!block.is_null());
|
||||
let n = pthread_mutex_init(block, ptr::null());
|
||||
assert_eq!(n, 0);
|
||||
return block as uint;
|
||||
}
|
||||
|
||||
pub unsafe fn init_cond() -> uint {
|
||||
let block = libc::malloc(rust_pthread_cond_t_size() as libc::size_t);
|
||||
assert!(!block.is_null());
|
||||
let n = pthread_cond_init(block, ptr::null());
|
||||
assert_eq!(n, 0);
|
||||
return block as uint;
|
||||
}
|
||||
|
||||
pub unsafe fn free_lock(h: uint) {
|
||||
let block = h as *c_void;
|
||||
assert_eq!(pthread_mutex_destroy(block), 0);
|
||||
libc::free(block);
|
||||
}
|
||||
|
||||
pub unsafe fn free_cond(h: uint) {
|
||||
let block = h as *c_void;
|
||||
assert_eq!(pthread_cond_destroy(block), 0);
|
||||
libc::free(block);
|
||||
}
|
||||
|
||||
pub unsafe fn lock(l: *pthread_mutex_t) {
|
||||
assert_eq!(pthread_mutex_lock(l), 0);
|
||||
}
|
||||
|
||||
pub unsafe fn trylock(l: *c_void) -> bool {
|
||||
pthread_mutex_trylock(l) == 0
|
||||
}
|
||||
|
||||
pub unsafe fn unlock(l: *pthread_mutex_t) {
|
||||
assert_eq!(pthread_mutex_unlock(l), 0);
|
||||
}
|
||||
|
||||
pub unsafe fn wait(cond: *pthread_cond_t, m: *pthread_mutex_t) {
|
||||
assert_eq!(pthread_cond_wait(cond, m), 0);
|
||||
}
|
||||
|
||||
pub unsafe fn signal(cond: *pthread_cond_t) {
|
||||
assert_eq!(pthread_cond_signal(cond), 0);
|
||||
}
|
||||
|
||||
extern {
|
||||
fn rust_pthread_mutex_t_size() -> libc::c_int;
|
||||
fn rust_pthread_cond_t_size() -> libc::c_int;
|
||||
}
|
||||
|
||||
extern {
|
||||
fn pthread_mutex_init(lock: *pthread_mutex_t,
|
||||
attr: *pthread_mutexattr_t) -> libc::c_int;
|
||||
fn pthread_mutex_destroy(lock: *pthread_mutex_t) -> libc::c_int;
|
||||
fn pthread_cond_init(cond: *pthread_cond_t,
|
||||
attr: *pthread_condattr_t) -> libc::c_int;
|
||||
fn pthread_cond_destroy(cond: *pthread_cond_t) -> libc::c_int;
|
||||
fn pthread_mutex_lock(lock: *pthread_mutex_t) -> libc::c_int;
|
||||
fn pthread_mutex_trylock(lock: *pthread_mutex_t) -> libc::c_int;
|
||||
fn pthread_mutex_unlock(lock: *pthread_mutex_t) -> libc::c_int;
|
||||
|
||||
fn pthread_cond_wait(cond: *pthread_cond_t,
|
||||
lock: *pthread_mutex_t) -> libc::c_int;
|
||||
fn pthread_cond_signal(cond: *pthread_cond_t) -> libc::c_int;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
mod imp {
|
||||
use libc;
|
||||
use libc::{HANDLE, BOOL, LPSECURITY_ATTRIBUTES, c_void, DWORD, LPCSTR};
|
||||
use ptr;
|
||||
type LPCRITICAL_SECTION = *c_void;
|
||||
static SPIN_COUNT: DWORD = 4000;
|
||||
|
||||
pub unsafe fn init_lock() -> uint {
|
||||
let block = libc::malloc(rust_crit_section_size() as libc::size_t);
|
||||
assert!(!block.is_null());
|
||||
InitializeCriticalSectionAndSpinCount(block, SPIN_COUNT);
|
||||
return block as uint;
|
||||
}
|
||||
|
||||
pub unsafe fn init_cond() -> uint {
|
||||
return CreateEventA(ptr::mut_null(), libc::FALSE, libc::FALSE,
|
||||
ptr::null()) as uint;
|
||||
}
|
||||
|
||||
pub unsafe fn free_lock(h: uint) {
|
||||
DeleteCriticalSection(h as LPCRITICAL_SECTION);
|
||||
libc::free(h as *c_void);
|
||||
}
|
||||
|
||||
pub unsafe fn free_cond(h: uint) {
|
||||
let block = h as HANDLE;
|
||||
libc::CloseHandle(block);
|
||||
}
|
||||
|
||||
pub unsafe fn lock(l: *c_void) {
|
||||
EnterCriticalSection(l as LPCRITICAL_SECTION)
|
||||
}
|
||||
|
||||
pub unsafe fn trylock(l: *c_void) -> bool {
|
||||
TryEnterCriticalSection(l as LPCRITICAL_SECTION) != 0
|
||||
}
|
||||
|
||||
pub unsafe fn unlock(l: *c_void) {
|
||||
LeaveCriticalSection(l as LPCRITICAL_SECTION)
|
||||
}
|
||||
|
||||
pub unsafe fn wait(cond: *c_void, m: *c_void) {
|
||||
unlock(m);
|
||||
WaitForSingleObject(cond as HANDLE, 0);
|
||||
lock(m);
|
||||
}
|
||||
|
||||
pub unsafe fn signal(cond: *c_void) {
|
||||
assert!(SetEvent(cond as HANDLE) != 0);
|
||||
}
|
||||
|
||||
extern {
|
||||
fn rust_crit_section_size() -> libc::c_int;
|
||||
}
|
||||
|
||||
extern "system" {
|
||||
fn CreateEventA(lpSecurityAttributes: LPSECURITY_ATTRIBUTES,
|
||||
bManualReset: BOOL,
|
||||
bInitialState: BOOL,
|
||||
lpName: LPCSTR) -> HANDLE;
|
||||
fn InitializeCriticalSectionAndSpinCount(
|
||||
lpCriticalSection: LPCRITICAL_SECTION,
|
||||
dwSpinCount: DWORD) -> BOOL;
|
||||
fn DeleteCriticalSection(lpCriticalSection: LPCRITICAL_SECTION);
|
||||
fn EnterCriticalSection(lpCriticalSection: LPCRITICAL_SECTION);
|
||||
fn LeaveCriticalSection(lpCriticalSection: LPCRITICAL_SECTION);
|
||||
fn TryEnterCriticalSection(lpCriticalSection: LPCRITICAL_SECTION) -> BOOL;
|
||||
fn SetEvent(hEvent: HANDLE) -> BOOL;
|
||||
fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::{Mutex, MUTEX_INIT};
|
||||
use rt::thread::Thread;
|
||||
|
||||
#[test]
|
||||
fn somke_lock() {
|
||||
static mut lock: Mutex = MUTEX_INIT;
|
||||
unsafe {
|
||||
lock.lock();
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn somke_cond() {
|
||||
static mut lock: Mutex = MUTEX_INIT;
|
||||
unsafe {
|
||||
let t = do Thread::start {
|
||||
lock.lock();
|
||||
lock.signal();
|
||||
lock.unlock();
|
||||
};
|
||||
lock.lock();
|
||||
lock.wait();
|
||||
lock.unlock();
|
||||
t.join();
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -14,53 +14,53 @@ char **backtrace_symbols(void *const *array, int size) { return 0; }
|
||||
|
||||
void backtrace_symbols_fd (void *const *array, int size, int fd) {}
|
||||
|
||||
extern "C" volatile int* __errno_location() {
|
||||
volatile int* __errno_location() {
|
||||
return &errno;
|
||||
}
|
||||
|
||||
extern "C" float log2f(float f)
|
||||
float log2f(float f)
|
||||
{
|
||||
return logf( f ) / logf( 2 );
|
||||
}
|
||||
|
||||
extern "C" double log2( double n )
|
||||
double log2( double n )
|
||||
{
|
||||
return log( n ) / log( 2 );
|
||||
}
|
||||
|
||||
extern "C" void telldir()
|
||||
void telldir()
|
||||
{
|
||||
}
|
||||
|
||||
extern "C" void seekdir()
|
||||
void seekdir()
|
||||
{
|
||||
}
|
||||
|
||||
extern "C" void mkfifo()
|
||||
void mkfifo()
|
||||
{
|
||||
}
|
||||
|
||||
extern "C" void abs()
|
||||
void abs()
|
||||
{
|
||||
}
|
||||
|
||||
extern "C" void labs()
|
||||
void labs()
|
||||
{
|
||||
}
|
||||
|
||||
extern "C" void rand()
|
||||
void rand()
|
||||
{
|
||||
}
|
||||
|
||||
extern "C" void srand()
|
||||
void srand()
|
||||
{
|
||||
}
|
||||
|
||||
extern "C" void atof()
|
||||
void atof()
|
||||
{
|
||||
}
|
||||
|
||||
extern "C" int glob(const char *pattern,
|
||||
int glob(const char *pattern,
|
||||
int flags,
|
||||
int (*errfunc) (const char *epath, int eerrno),
|
||||
glob_t *pglob)
|
||||
@ -68,38 +68,38 @@ extern "C" int glob(const char *pattern,
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" void globfree(glob_t *pglob)
|
||||
void globfree(glob_t *pglob)
|
||||
{
|
||||
}
|
||||
|
||||
extern "C" int pthread_atfork(void (*prefork)(void),
|
||||
int pthread_atfork(void (*prefork)(void),
|
||||
void (*postfork_parent)(void),
|
||||
void (*postfork_child)(void))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" int mlockall(int flags)
|
||||
int mlockall(int flags)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" int munlockall(void)
|
||||
int munlockall(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" int shm_open(const char *name, int oflag, mode_t mode)
|
||||
int shm_open(const char *name, int oflag, mode_t mode)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" int shm_unlink(const char *name)
|
||||
int shm_unlink(const char *name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" int posix_madvise(void *addr, size_t len, int advice)
|
||||
int posix_madvise(void *addr, size_t len, int advice)
|
||||
{
|
||||
return 0;
|
||||
}
|
@ -10,7 +10,7 @@
|
||||
|
||||
/* Foreign builtins. */
|
||||
|
||||
#include "sync/lock_and_signal.h"
|
||||
#include "rust_globals.h"
|
||||
#include "vg/valgrind.h"
|
||||
|
||||
#include <time.h>
|
||||
@ -58,12 +58,12 @@ timegm(struct tm *tm)
|
||||
#endif
|
||||
|
||||
#if defined(__WIN32__)
|
||||
extern "C" CDECL char**
|
||||
char**
|
||||
rust_env_pairs() {
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
extern "C" CDECL char**
|
||||
char**
|
||||
rust_env_pairs() {
|
||||
#if defined(__APPLE__) && !(TARGET_OS_IPHONE)
|
||||
char **environ = *_NSGetEnviron();
|
||||
@ -72,18 +72,18 @@ rust_env_pairs() {
|
||||
}
|
||||
#endif
|
||||
|
||||
extern "C" CDECL char*
|
||||
char*
|
||||
#if defined(__WIN32__)
|
||||
rust_list_dir_val(WIN32_FIND_DATA* entry_ptr) {
|
||||
return entry_ptr->cFileName;
|
||||
}
|
||||
#else
|
||||
rust_list_dir_val(dirent* entry_ptr) {
|
||||
rust_list_dir_val(struct dirent* entry_ptr) {
|
||||
return entry_ptr->d_name;
|
||||
}
|
||||
#endif
|
||||
|
||||
extern "C" CDECL size_t
|
||||
size_t
|
||||
#if defined(__WIN32__)
|
||||
rust_list_dir_wfd_size() {
|
||||
return sizeof(WIN32_FIND_DATAW);
|
||||
@ -94,7 +94,7 @@ rust_list_dir_wfd_size() {
|
||||
}
|
||||
#endif
|
||||
|
||||
extern "C" CDECL void*
|
||||
void*
|
||||
#if defined(__WIN32__)
|
||||
rust_list_dir_wfd_fp_buf(WIN32_FIND_DATAW* wfd) {
|
||||
if(wfd == NULL) {
|
||||
@ -110,7 +110,7 @@ rust_list_dir_wfd_fp_buf(void* wfd) {
|
||||
}
|
||||
#endif
|
||||
|
||||
extern "C" CDECL int
|
||||
int
|
||||
rust_path_is_dir(const char *path) {
|
||||
struct stat buf;
|
||||
if (stat(path, &buf)) {
|
||||
@ -119,7 +119,7 @@ rust_path_is_dir(const char *path) {
|
||||
return S_ISDIR(buf.st_mode);
|
||||
}
|
||||
|
||||
extern "C" CDECL int
|
||||
int
|
||||
#if defined(__WIN32__)
|
||||
rust_path_is_dir_u16(const wchar_t *path) {
|
||||
struct _stat buf;
|
||||
@ -137,7 +137,7 @@ rust_path_is_dir_u16(const void *path) {
|
||||
}
|
||||
#endif
|
||||
|
||||
extern "C" CDECL int
|
||||
int
|
||||
rust_path_exists(const char *path) {
|
||||
struct stat buf;
|
||||
if (stat(path, &buf)) {
|
||||
@ -146,7 +146,7 @@ rust_path_exists(const char *path) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
extern "C" CDECL int
|
||||
int
|
||||
#if defined(__WIN32__)
|
||||
rust_path_exists_u16(const wchar_t *path) {
|
||||
struct _stat buf;
|
||||
@ -162,12 +162,12 @@ rust_path_exists_u16(const void *path) {
|
||||
}
|
||||
#endif
|
||||
|
||||
extern "C" CDECL FILE* rust_get_stdin() {return stdin;}
|
||||
extern "C" CDECL FILE* rust_get_stdout() {return stdout;}
|
||||
extern "C" CDECL FILE* rust_get_stderr() {return stderr;}
|
||||
FILE* rust_get_stdin() {return stdin;}
|
||||
FILE* rust_get_stdout() {return stdout;}
|
||||
FILE* rust_get_stderr() {return stderr;}
|
||||
|
||||
#if defined(__WIN32__)
|
||||
extern "C" CDECL void
|
||||
void
|
||||
rust_get_time(int64_t *sec, int32_t *nsec) {
|
||||
FILETIME fileTime;
|
||||
GetSystemTimeAsFileTime(&fileTime);
|
||||
@ -186,7 +186,7 @@ rust_get_time(int64_t *sec, int32_t *nsec) {
|
||||
*nsec = (ns_since_1970 % 1000000) * 1000;
|
||||
}
|
||||
#else
|
||||
extern "C" CDECL void
|
||||
void
|
||||
rust_get_time(int64_t *sec, int32_t *nsec) {
|
||||
#ifdef __APPLE__
|
||||
struct timeval tv;
|
||||
@ -194,7 +194,7 @@ rust_get_time(int64_t *sec, int32_t *nsec) {
|
||||
*sec = tv.tv_sec;
|
||||
*nsec = tv.tv_usec * 1000;
|
||||
#else
|
||||
timespec ts;
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_REALTIME, &ts);
|
||||
*sec = ts.tv_sec;
|
||||
*nsec = ts.tv_nsec;
|
||||
@ -204,7 +204,7 @@ rust_get_time(int64_t *sec, int32_t *nsec) {
|
||||
|
||||
const int64_t ns_per_s = 1000000000LL;
|
||||
|
||||
extern "C" CDECL void
|
||||
void
|
||||
rust_precise_time_ns(uint64_t *ns) {
|
||||
|
||||
#ifdef __APPLE__
|
||||
@ -227,23 +227,22 @@ rust_precise_time_ns(uint64_t *ns) {
|
||||
assert(query_result);
|
||||
*ns = (uint64_t)((ticks.QuadPart * ns_per_s) / ticks_per_s.QuadPart);
|
||||
#else
|
||||
timespec ts;
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
*ns = (uint64_t)(ts.tv_sec * ns_per_s + ts.tv_nsec);
|
||||
#endif
|
||||
}
|
||||
|
||||
struct
|
||||
rust_vec
|
||||
typedef struct
|
||||
{
|
||||
size_t fill; // in bytes; if zero, heapified
|
||||
size_t alloc; // in bytes
|
||||
uint8_t data[0];
|
||||
};
|
||||
} rust_vec;
|
||||
|
||||
typedef rust_vec rust_str;
|
||||
|
||||
struct rust_tm {
|
||||
typedef struct {
|
||||
int32_t tm_sec;
|
||||
int32_t tm_min;
|
||||
int32_t tm_hour;
|
||||
@ -256,10 +255,10 @@ struct rust_tm {
|
||||
int32_t tm_gmtoff;
|
||||
rust_str *tm_zone;
|
||||
int32_t tm_nsec;
|
||||
};
|
||||
} rust_tm;
|
||||
|
||||
void rust_tm_to_tm(rust_tm* in_tm, tm* out_tm) {
|
||||
memset(out_tm, 0, sizeof(tm));
|
||||
void rust_tm_to_tm(rust_tm* in_tm, struct tm* out_tm) {
|
||||
memset(out_tm, 0, sizeof(struct tm));
|
||||
out_tm->tm_sec = in_tm->tm_sec;
|
||||
out_tm->tm_min = in_tm->tm_min;
|
||||
out_tm->tm_hour = in_tm->tm_hour;
|
||||
@ -271,7 +270,7 @@ void rust_tm_to_tm(rust_tm* in_tm, tm* out_tm) {
|
||||
out_tm->tm_isdst = in_tm->tm_isdst;
|
||||
}
|
||||
|
||||
void tm_to_rust_tm(tm* in_tm, rust_tm* out_tm, int32_t gmtoff,
|
||||
void tm_to_rust_tm(struct tm* in_tm, rust_tm* out_tm, int32_t gmtoff,
|
||||
const char *zone, int32_t nsec) {
|
||||
out_tm->tm_sec = in_tm->tm_sec;
|
||||
out_tm->tm_min = in_tm->tm_min;
|
||||
@ -300,13 +299,13 @@ void tm_to_rust_tm(tm* in_tm, rust_tm* out_tm, int32_t gmtoff,
|
||||
#define LOCALTIME(clock, result) localtime_s((result), (clock))
|
||||
#define TIMEGM(result) _mkgmtime64(result)
|
||||
#else
|
||||
struct tm* GMTIME(const time_t *clock, tm *result) {
|
||||
struct tm* GMTIME(const time_t *clock, struct tm *result) {
|
||||
struct tm* t = gmtime(clock);
|
||||
if (t == NULL || result == NULL) { return NULL; }
|
||||
*result = *t;
|
||||
return result;
|
||||
}
|
||||
struct tm* LOCALTIME(const time_t *clock, tm *result) {
|
||||
struct tm* LOCALTIME(const time_t *clock, struct tm *result) {
|
||||
struct tm* t = localtime(clock);
|
||||
if (t == NULL || result == NULL) { return NULL; }
|
||||
*result = *t;
|
||||
@ -321,23 +320,23 @@ struct tm* LOCALTIME(const time_t *clock, tm *result) {
|
||||
#define TIMEGM(result) timegm(result)
|
||||
#endif
|
||||
|
||||
extern "C" CDECL void
|
||||
void
|
||||
rust_tzset() {
|
||||
TZSET();
|
||||
}
|
||||
|
||||
extern "C" CDECL void
|
||||
void
|
||||
rust_gmtime(int64_t sec, int32_t nsec, rust_tm *timeptr) {
|
||||
tm tm;
|
||||
struct tm tm;
|
||||
time_t s = sec;
|
||||
GMTIME(&s, &tm);
|
||||
|
||||
tm_to_rust_tm(&tm, timeptr, 0, "UTC", nsec);
|
||||
}
|
||||
|
||||
extern "C" CDECL void
|
||||
void
|
||||
rust_localtime(int64_t sec, int32_t nsec, rust_tm *timeptr) {
|
||||
tm tm;
|
||||
struct tm tm;
|
||||
time_t s = sec;
|
||||
LOCALTIME(&s, &tm);
|
||||
|
||||
@ -365,128 +364,47 @@ rust_localtime(int64_t sec, int32_t nsec, rust_tm *timeptr) {
|
||||
tm_to_rust_tm(&tm, timeptr, gmtoff, zone, nsec);
|
||||
}
|
||||
|
||||
extern "C" CDECL int64_t
|
||||
int64_t
|
||||
rust_timegm(rust_tm* timeptr) {
|
||||
tm t;
|
||||
struct tm t;
|
||||
rust_tm_to_tm(timeptr, &t);
|
||||
return TIMEGM(&t);
|
||||
}
|
||||
|
||||
extern "C" CDECL int64_t
|
||||
int64_t
|
||||
rust_mktime(rust_tm* timeptr) {
|
||||
tm t;
|
||||
struct tm t;
|
||||
rust_tm_to_tm(timeptr, &t);
|
||||
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>
|
||||
|
||||
extern "C" DIR*
|
||||
DIR*
|
||||
rust_opendir(char *dirname) {
|
||||
return opendir(dirname);
|
||||
}
|
||||
|
||||
extern "C" dirent*
|
||||
struct dirent*
|
||||
rust_readdir(DIR *dirp) {
|
||||
return readdir(dirp);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
extern "C" void
|
||||
void
|
||||
rust_opendir() {
|
||||
}
|
||||
|
||||
extern "C" void
|
||||
void
|
||||
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
|
||||
rust_try(rust_try_fn f, void *fptr, void *env) {
|
||||
try {
|
||||
f(fptr, env);
|
||||
} catch (uintptr_t token) {
|
||||
assert(token != 0);
|
||||
return token;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" CDECL void
|
||||
rust_begin_unwind(uintptr_t token) {
|
||||
throw token;
|
||||
}
|
||||
|
||||
extern "C" CDECL uintptr_t
|
||||
uintptr_t
|
||||
rust_running_on_valgrind() {
|
||||
return RUNNING_ON_VALGRIND;
|
||||
}
|
||||
@ -533,66 +451,24 @@ get_num_cpus() {
|
||||
}
|
||||
#endif
|
||||
|
||||
extern "C" CDECL uintptr_t
|
||||
uintptr_t
|
||||
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
|
||||
unsigned int
|
||||
rust_valgrind_stack_register(void *start, void *end) {
|
||||
return VALGRIND_STACK_REGISTER(start, end);
|
||||
}
|
||||
|
||||
extern "C" CDECL void
|
||||
void
|
||||
rust_valgrind_stack_deregister(unsigned int id) {
|
||||
VALGRIND_STACK_DEREGISTER(id);
|
||||
}
|
||||
|
||||
#if defined(__WIN32__)
|
||||
|
||||
extern "C" CDECL void
|
||||
void
|
||||
rust_unset_sigprocmask() {
|
||||
// empty stub for windows to keep linker happy
|
||||
}
|
||||
@ -602,7 +478,7 @@ rust_unset_sigprocmask() {
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
|
||||
extern "C" CDECL void
|
||||
void
|
||||
rust_unset_sigprocmask() {
|
||||
// this can't be safely converted to rust code because the
|
||||
// representation of sigset_t is platform-dependent
|
||||
@ -631,7 +507,7 @@ win32_require(LPCTSTR fn, BOOL ok) {
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" CDECL void
|
||||
void
|
||||
rust_win32_rand_acquire(HCRYPTPROV* phProv) {
|
||||
win32_require
|
||||
(_T("CryptAcquireContext"),
|
||||
@ -641,12 +517,12 @@ rust_win32_rand_acquire(HCRYPTPROV* phProv) {
|
||||
CRYPT_VERIFYCONTEXT|CRYPT_SILENT));
|
||||
|
||||
}
|
||||
extern "C" CDECL void
|
||||
void
|
||||
rust_win32_rand_gen(HCRYPTPROV hProv, DWORD dwLen, BYTE* pbBuffer) {
|
||||
win32_require
|
||||
(_T("CryptGenRandom"), CryptGenRandom(hProv, dwLen, pbBuffer));
|
||||
}
|
||||
extern "C" CDECL void
|
||||
void
|
||||
rust_win32_rand_release(HCRYPTPROV hProv) {
|
||||
win32_require
|
||||
(_T("CryptReleaseContext"), CryptReleaseContext(hProv, 0));
|
||||
@ -657,20 +533,41 @@ rust_win32_rand_release(HCRYPTPROV hProv) {
|
||||
// these symbols are listed in rustrt.def.in, so they need to exist; but they
|
||||
// should never be called.
|
||||
|
||||
extern "C" CDECL void
|
||||
void
|
||||
rust_win32_rand_acquire() {
|
||||
abort();
|
||||
}
|
||||
extern "C" CDECL void
|
||||
void
|
||||
rust_win32_rand_gen() {
|
||||
abort();
|
||||
}
|
||||
extern "C" CDECL void
|
||||
void
|
||||
rust_win32_rand_release() {
|
||||
abort();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__WIN32__)
|
||||
|
||||
int
|
||||
rust_crit_section_size() { return sizeof(CRITICAL_SECTION); }
|
||||
int
|
||||
rust_pthread_mutex_t_size() { return 0; }
|
||||
int
|
||||
rust_pthread_cond_t_size() { return 0; }
|
||||
|
||||
#else
|
||||
|
||||
int
|
||||
rust_crit_section_size() { return 0; }
|
||||
int
|
||||
rust_pthread_mutex_t_size() { return sizeof(pthread_mutex_t); }
|
||||
int
|
||||
rust_pthread_cond_t_size() { return sizeof(pthread_cond_t); }
|
||||
|
||||
#endif
|
||||
|
||||
//
|
||||
// Local Variables:
|
||||
// mode: C++
|
31
src/rt/rust_cxx_glue.cpp
Normal file
31
src/rt/rust_cxx_glue.cpp
Normal file
@ -0,0 +1,31 @@
|
||||
// Copyright 2013 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.
|
||||
|
||||
/* Foreign builtins which require C++ */
|
||||
|
||||
#include "rust_globals.h"
|
||||
|
||||
typedef void *(rust_try_fn)(void*, void*);
|
||||
|
||||
extern "C" CDECL uintptr_t
|
||||
rust_try(rust_try_fn f, void *fptr, void *env) {
|
||||
try {
|
||||
f(fptr, env);
|
||||
} catch (uintptr_t token) {
|
||||
assert(token != 0);
|
||||
return token;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" CDECL void
|
||||
rust_begin_unwind(uintptr_t token) {
|
||||
throw token;
|
||||
}
|
@ -39,6 +39,10 @@
|
||||
#define __STDC_FORMAT_MACROS 1
|
||||
#endif
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE 1
|
||||
#endif
|
||||
|
||||
#define ERROR 0
|
||||
|
||||
#include <stdlib.h>
|
||||
@ -62,11 +66,15 @@
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#include <tchar.h>
|
||||
#include <wincrypt.h>
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
#elif defined(__GNUC__)
|
||||
#include <unistd.h>
|
||||
#include <dlfcn.h>
|
||||
|
@ -10,80 +10,45 @@
|
||||
|
||||
// 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.
|
||||
|
||||
extern "C" CDECL uint32_t
|
||||
uint32_t
|
||||
rust_dbg_extern_identity_u32(uint32_t u) {
|
||||
return u;
|
||||
}
|
||||
|
||||
extern "C" CDECL uint64_t
|
||||
uint64_t
|
||||
rust_dbg_extern_identity_u64(uint64_t u) {
|
||||
return u;
|
||||
}
|
||||
|
||||
extern "C" CDECL double
|
||||
double
|
||||
rust_dbg_extern_identity_double(double u) {
|
||||
return u;
|
||||
}
|
||||
|
||||
extern "C" CDECL char
|
||||
char
|
||||
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 *
|
||||
void *
|
||||
rust_dbg_call(dbg_callback cb, void *data) {
|
||||
return cb(data);
|
||||
}
|
||||
|
||||
extern "C" CDECL void rust_dbg_do_nothing() { }
|
||||
void rust_dbg_do_nothing() { }
|
||||
|
||||
struct TwoU8s {
|
||||
uint8_t one;
|
||||
uint8_t two;
|
||||
};
|
||||
|
||||
extern "C" CDECL TwoU8s
|
||||
struct TwoU8s
|
||||
rust_dbg_extern_return_TwoU8s() {
|
||||
struct TwoU8s s;
|
||||
s.one = 10;
|
||||
@ -91,8 +56,8 @@ rust_dbg_extern_return_TwoU8s() {
|
||||
return s;
|
||||
}
|
||||
|
||||
extern "C" CDECL TwoU8s
|
||||
rust_dbg_extern_identity_TwoU8s(TwoU8s u) {
|
||||
struct TwoU8s
|
||||
rust_dbg_extern_identity_TwoU8s(struct TwoU8s u) {
|
||||
return u;
|
||||
}
|
||||
|
||||
@ -101,7 +66,7 @@ struct TwoU16s {
|
||||
uint16_t two;
|
||||
};
|
||||
|
||||
extern "C" CDECL TwoU16s
|
||||
struct TwoU16s
|
||||
rust_dbg_extern_return_TwoU16s() {
|
||||
struct TwoU16s s;
|
||||
s.one = 10;
|
||||
@ -109,8 +74,8 @@ rust_dbg_extern_return_TwoU16s() {
|
||||
return s;
|
||||
}
|
||||
|
||||
extern "C" CDECL TwoU16s
|
||||
rust_dbg_extern_identity_TwoU16s(TwoU16s u) {
|
||||
struct TwoU16s
|
||||
rust_dbg_extern_identity_TwoU16s(struct TwoU16s u) {
|
||||
return u;
|
||||
}
|
||||
|
||||
@ -119,7 +84,7 @@ struct TwoU32s {
|
||||
uint32_t two;
|
||||
};
|
||||
|
||||
extern "C" CDECL TwoU32s
|
||||
struct TwoU32s
|
||||
rust_dbg_extern_return_TwoU32s() {
|
||||
struct TwoU32s s;
|
||||
s.one = 10;
|
||||
@ -127,8 +92,8 @@ rust_dbg_extern_return_TwoU32s() {
|
||||
return s;
|
||||
}
|
||||
|
||||
extern "C" CDECL TwoU32s
|
||||
rust_dbg_extern_identity_TwoU32s(TwoU32s u) {
|
||||
struct TwoU32s
|
||||
rust_dbg_extern_identity_TwoU32s(struct TwoU32s u) {
|
||||
return u;
|
||||
}
|
||||
|
||||
@ -137,7 +102,7 @@ struct TwoU64s {
|
||||
uint64_t two;
|
||||
};
|
||||
|
||||
extern "C" CDECL TwoU64s
|
||||
struct TwoU64s
|
||||
rust_dbg_extern_return_TwoU64s() {
|
||||
struct TwoU64s s;
|
||||
s.one = 10;
|
||||
@ -145,8 +110,8 @@ rust_dbg_extern_return_TwoU64s() {
|
||||
return s;
|
||||
}
|
||||
|
||||
extern "C" CDECL TwoU64s
|
||||
rust_dbg_extern_identity_TwoU64s(TwoU64s u) {
|
||||
struct TwoU64s
|
||||
rust_dbg_extern_identity_TwoU64s(struct TwoU64s u) {
|
||||
return u;
|
||||
}
|
||||
|
||||
@ -155,23 +120,12 @@ struct TwoDoubles {
|
||||
double two;
|
||||
};
|
||||
|
||||
extern "C" CDECL TwoDoubles
|
||||
rust_dbg_extern_identity_TwoDoubles(TwoDoubles u) {
|
||||
struct TwoDoubles
|
||||
rust_dbg_extern_identity_TwoDoubles(struct 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
|
||||
intptr_t
|
||||
rust_get_test_int() {
|
||||
return 1;
|
||||
}
|
||||
@ -195,29 +149,29 @@ struct floats {
|
||||
double c;
|
||||
};
|
||||
|
||||
extern "C" quad
|
||||
rust_dbg_abi_1(quad q) {
|
||||
quad qq = { q.c + 1,
|
||||
q.d - 1,
|
||||
q.a + 1,
|
||||
q.b - 1 };
|
||||
struct quad
|
||||
rust_dbg_abi_1(struct quad q) {
|
||||
struct quad qq = { q.c + 1,
|
||||
q.d - 1,
|
||||
q.a + 1,
|
||||
q.b - 1 };
|
||||
return qq;
|
||||
}
|
||||
|
||||
extern "C" floats
|
||||
rust_dbg_abi_2(floats f) {
|
||||
floats ff = { f.c + 1.0,
|
||||
0xff,
|
||||
f.a - 1.0 };
|
||||
struct floats
|
||||
rust_dbg_abi_2(struct floats f) {
|
||||
struct floats ff = { f.c + 1.0,
|
||||
0xff,
|
||||
f.a - 1.0 };
|
||||
return ff;
|
||||
}
|
||||
|
||||
extern "C" int
|
||||
int
|
||||
rust_dbg_static_mut;
|
||||
|
||||
int rust_dbg_static_mut = 3;
|
||||
|
||||
extern "C" void
|
||||
void
|
||||
rust_dbg_static_mut_check_four() {
|
||||
assert(rust_dbg_static_mut == 4);
|
||||
}
|
@ -35,24 +35,24 @@ struct _Unwind_Exception;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
extern "C" _Unwind_Reason_Code
|
||||
_Unwind_Reason_Code
|
||||
PERSONALITY_FUNC(int version,
|
||||
_Unwind_Action actions,
|
||||
uint64_t exception_class,
|
||||
_Unwind_Exception *ue_header,
|
||||
_Unwind_Context *context);
|
||||
struct _Unwind_Exception *ue_header,
|
||||
struct _Unwind_Context *context);
|
||||
|
||||
struct s_rust_personality_args {
|
||||
_Unwind_Reason_Code retval;
|
||||
int version;
|
||||
_Unwind_Action actions;
|
||||
uint64_t exception_class;
|
||||
_Unwind_Exception *ue_header;
|
||||
_Unwind_Context *context;
|
||||
struct _Unwind_Exception *ue_header;
|
||||
struct _Unwind_Context *context;
|
||||
};
|
||||
|
||||
extern "C" void
|
||||
upcall_s_rust_personality(s_rust_personality_args *args) {
|
||||
void
|
||||
upcall_s_rust_personality(struct s_rust_personality_args *args) {
|
||||
args->retval = PERSONALITY_FUNC(args->version,
|
||||
args->actions,
|
||||
args->exception_class,
|
||||
@ -65,15 +65,15 @@ upcall_s_rust_personality(s_rust_personality_args *args) {
|
||||
out what to do with each landing pad. Just a stack-switching
|
||||
wrapper around the C++ personality function.
|
||||
*/
|
||||
extern "C" _Unwind_Reason_Code
|
||||
_Unwind_Reason_Code
|
||||
upcall_rust_personality(int version,
|
||||
_Unwind_Action actions,
|
||||
uint64_t exception_class,
|
||||
_Unwind_Exception *ue_header,
|
||||
_Unwind_Context *context) {
|
||||
s_rust_personality_args args = {(_Unwind_Reason_Code)0,
|
||||
version, actions, exception_class,
|
||||
ue_header, context};
|
||||
struct _Unwind_Exception *ue_header,
|
||||
struct _Unwind_Context *context) {
|
||||
struct s_rust_personality_args args = {(_Unwind_Reason_Code)0,
|
||||
version, actions, exception_class,
|
||||
ue_header, context};
|
||||
upcall_s_rust_personality(&args);
|
||||
return args.retval;
|
||||
}
|
||||
@ -82,7 +82,7 @@ upcall_rust_personality(int version,
|
||||
// correct limit into TLS.
|
||||
// NB: This must run on the Rust stack because it
|
||||
// needs to acquire the value of the stack pointer
|
||||
extern "C" CDECL void
|
||||
void
|
||||
upcall_reset_stack_limit() {
|
||||
}
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
#include "rust_globals.h"
|
||||
|
||||
extern "C" void*
|
||||
void*
|
||||
rust_uv_loop_new() {
|
||||
// XXX libuv doesn't always ignore SIGPIPE even though we don't need it.
|
||||
#ifndef __WIN32__
|
||||
@ -31,67 +31,67 @@ rust_uv_loop_new() {
|
||||
return (void*)uv_loop_new();
|
||||
}
|
||||
|
||||
extern "C" void
|
||||
void
|
||||
rust_uv_loop_set_data(uv_loop_t* loop, void* data) {
|
||||
loop->data = data;
|
||||
}
|
||||
|
||||
extern "C" uv_udp_t*
|
||||
uv_udp_t*
|
||||
rust_uv_get_udp_handle_from_send_req(uv_udp_send_t* send_req) {
|
||||
return send_req->handle;
|
||||
}
|
||||
|
||||
extern "C" uv_stream_t*
|
||||
uv_stream_t*
|
||||
rust_uv_get_stream_handle_from_connect_req(uv_connect_t* connect) {
|
||||
return connect->handle;
|
||||
}
|
||||
extern "C" uv_stream_t*
|
||||
uv_stream_t*
|
||||
rust_uv_get_stream_handle_from_write_req(uv_write_t* write_req) {
|
||||
return write_req->handle;
|
||||
}
|
||||
|
||||
extern "C" uv_loop_t*
|
||||
uv_loop_t*
|
||||
rust_uv_get_loop_for_uv_handle(uv_handle_t* handle) {
|
||||
return handle->loop;
|
||||
}
|
||||
|
||||
extern "C" void*
|
||||
void*
|
||||
rust_uv_get_data_for_uv_loop(uv_loop_t* loop) {
|
||||
return loop->data;
|
||||
}
|
||||
|
||||
extern "C" void
|
||||
void
|
||||
rust_uv_set_data_for_uv_loop(uv_loop_t* loop,
|
||||
void* data) {
|
||||
loop->data = data;
|
||||
}
|
||||
|
||||
extern "C" void*
|
||||
void*
|
||||
rust_uv_get_data_for_uv_handle(uv_handle_t* handle) {
|
||||
return handle->data;
|
||||
}
|
||||
|
||||
extern "C" void
|
||||
void
|
||||
rust_uv_set_data_for_uv_handle(uv_handle_t* handle, void* data) {
|
||||
handle->data = data;
|
||||
}
|
||||
|
||||
extern "C" void*
|
||||
void*
|
||||
rust_uv_get_data_for_req(uv_req_t* req) {
|
||||
return req->data;
|
||||
}
|
||||
|
||||
extern "C" void
|
||||
void
|
||||
rust_uv_set_data_for_req(uv_req_t* req, void* data) {
|
||||
req->data = data;
|
||||
}
|
||||
|
||||
extern "C" int
|
||||
int
|
||||
rust_sockaddr_size() {
|
||||
return sizeof(struct sockaddr_storage);
|
||||
}
|
||||
|
||||
extern "C" struct sockaddr*
|
||||
struct sockaddr*
|
||||
rust_malloc_ip4_addr(char *name, int port) {
|
||||
struct sockaddr_in *addr = (struct sockaddr_in*) calloc(1, rust_sockaddr_size());
|
||||
assert(addr != NULL);
|
||||
@ -101,7 +101,7 @@ rust_malloc_ip4_addr(char *name, int port) {
|
||||
return (struct sockaddr*) addr;
|
||||
}
|
||||
|
||||
extern "C" struct sockaddr*
|
||||
struct sockaddr*
|
||||
rust_malloc_ip6_addr(char *name, int port) {
|
||||
struct sockaddr_in6 *addr = (struct sockaddr_in6*) calloc(1, rust_sockaddr_size());
|
||||
assert(addr != NULL);
|
||||
@ -111,58 +111,58 @@ rust_malloc_ip6_addr(char *name, int port) {
|
||||
return (struct sockaddr*) addr;
|
||||
}
|
||||
|
||||
extern "C" unsigned int
|
||||
unsigned int
|
||||
rust_ip4_port(struct sockaddr_in* src) {
|
||||
return ntohs(src->sin_port);
|
||||
}
|
||||
extern "C" unsigned int
|
||||
unsigned int
|
||||
rust_ip6_port(struct sockaddr_in6* src) {
|
||||
return ntohs(src->sin6_port);
|
||||
}
|
||||
|
||||
extern "C" int
|
||||
rust_is_ipv4_sockaddr(sockaddr* addr) {
|
||||
int
|
||||
rust_is_ipv4_sockaddr(struct sockaddr* addr) {
|
||||
return addr->sa_family == AF_INET;
|
||||
}
|
||||
|
||||
extern "C" int
|
||||
rust_is_ipv6_sockaddr(sockaddr* addr) {
|
||||
int
|
||||
rust_is_ipv6_sockaddr(struct sockaddr* addr) {
|
||||
return addr->sa_family == AF_INET6;
|
||||
}
|
||||
|
||||
extern "C" uintptr_t
|
||||
uintptr_t
|
||||
rust_uv_handle_type_max() {
|
||||
return UV_HANDLE_TYPE_MAX;
|
||||
}
|
||||
|
||||
extern "C" uintptr_t
|
||||
uintptr_t
|
||||
rust_uv_req_type_max() {
|
||||
return UV_REQ_TYPE_MAX;
|
||||
}
|
||||
|
||||
extern "C" int
|
||||
int
|
||||
rust_uv_get_result_from_fs_req(uv_fs_t* req) {
|
||||
return req->result;
|
||||
}
|
||||
extern "C" const char*
|
||||
const char*
|
||||
rust_uv_get_path_from_fs_req(uv_fs_t* req) {
|
||||
return req->path;
|
||||
}
|
||||
extern "C" void*
|
||||
void*
|
||||
rust_uv_get_ptr_from_fs_req(uv_fs_t* req) {
|
||||
return req->ptr;
|
||||
}
|
||||
extern "C" uv_loop_t*
|
||||
uv_loop_t*
|
||||
rust_uv_get_loop_from_fs_req(uv_fs_t* req) {
|
||||
return req->loop;
|
||||
}
|
||||
|
||||
extern "C" uv_loop_t*
|
||||
uv_loop_t*
|
||||
rust_uv_get_loop_from_getaddrinfo_req(uv_getaddrinfo_t* req) {
|
||||
return req->loop;
|
||||
}
|
||||
|
||||
extern "C" void
|
||||
void
|
||||
rust_uv_populate_uv_stat(uv_fs_t* req_in, uv_stat_t* stat_out) {
|
||||
stat_out->st_dev = req_in->statbuf.st_dev;
|
||||
stat_out->st_mode = req_in->statbuf.st_mode;
|
||||
@ -186,27 +186,27 @@ rust_uv_populate_uv_stat(uv_fs_t* req_in, uv_stat_t* stat_out) {
|
||||
stat_out->st_birthtim.tv_nsec = req_in->statbuf.st_birthtim.tv_nsec;
|
||||
}
|
||||
|
||||
extern "C" void
|
||||
void
|
||||
rust_set_stdio_container_flags(uv_stdio_container_t *c, int flags) {
|
||||
c->flags = (uv_stdio_flags) flags;
|
||||
}
|
||||
|
||||
extern "C" void
|
||||
void
|
||||
rust_set_stdio_container_fd(uv_stdio_container_t *c, int fd) {
|
||||
c->data.fd = fd;
|
||||
}
|
||||
|
||||
extern "C" void
|
||||
void
|
||||
rust_set_stdio_container_stream(uv_stdio_container_t *c, uv_stream_t *stream) {
|
||||
c->data.stream = stream;
|
||||
}
|
||||
|
||||
extern "C" int
|
||||
int
|
||||
rust_uv_process_pid(uv_process_t* p) {
|
||||
return p->pid;
|
||||
}
|
||||
|
||||
extern "C" int
|
||||
int
|
||||
rust_uv_guess_handle(int fd) {
|
||||
return uv_guess_handle(fd);
|
||||
}
|
@ -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,13 @@ 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_take_dlerror_lock
|
||||
rust_drop_dlerror_lock
|
||||
rust_pthread_mutex_t_size
|
||||
rust_pthread_cond_t_size
|
||||
rust_crit_section_size
|
||||
|
@ -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:
|
@ -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 */
|
Loading…
x
Reference in New Issue
Block a user