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:
bors 2013-11-18 21:51:31 -08:00
commit f5f5d5aac7
23 changed files with 695 additions and 740 deletions

View File

@ -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):

View File

@ -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)) \

View File

@ -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))) $$<

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,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};

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

@ -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;

View 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();
}
}
}

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

@ -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;
}

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>
@ -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
View 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;
}

View File

@ -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>

View File

@ -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);
}

View File

@ -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() {
}

View File

@ -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);
}

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,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

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 */