diff --git a/src/libgreen/sched.rs b/src/libgreen/sched.rs index d28e74a2b80b7..0eb6a66406253 100644 --- a/src/libgreen/sched.rs +++ b/src/libgreen/sched.rs @@ -14,7 +14,7 @@ use std::rt::rtio::{RemoteCallback, PausableIdleCallback, Callback, EventLoop}; use std::rt::task::BlockedTask; use std::rt::task::Task; use std::sync::deque; -use std::unstable::mutex::NativeMutex; +use std::rt::mutex::NativeMutex; use std::raw; use rand::{XorShiftRng, Rng, Rand}; @@ -1474,7 +1474,7 @@ mod test { #[test] fn test_spawn_sched_blocking() { - use std::unstable::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT}; + use std::rt::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT}; static mut LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT; // Testing that a task in one scheduler can block in foreign code diff --git a/src/libgreen/simple.rs b/src/libgreen/simple.rs index 49aef15f93b61..30b473b4fc415 100644 --- a/src/libgreen/simple.rs +++ b/src/libgreen/simple.rs @@ -18,7 +18,7 @@ use std::rt::local::Local; use std::rt::rtio; use std::rt::task::{Task, BlockedTask}; use std::task::TaskOpts; -use std::unstable::mutex::NativeMutex; +use std::rt::mutex::NativeMutex; struct SimpleTask { lock: NativeMutex, diff --git a/src/libgreen/task.rs b/src/libgreen/task.rs index f50f65af6f9eb..bfe61bec832bf 100644 --- a/src/libgreen/task.rs +++ b/src/libgreen/task.rs @@ -28,7 +28,7 @@ use std::rt::rtio; use std::rt::stack; use std::rt::task::{Task, BlockedTask, SendMessage}; use std::task::TaskOpts; -use std::unstable::mutex::NativeMutex; +use std::rt::mutex::NativeMutex; use context::Context; use coroutine::Coroutine; diff --git a/src/libnative/io/net.rs b/src/libnative/io/net.rs index cacd38c2efde3..d2bba1941473b 100644 --- a/src/libnative/io/net.rs +++ b/src/libnative/io/net.rs @@ -14,7 +14,8 @@ use std::io::net::ip; use std::io; use std::mem; use std::rt::rtio; -use std::unstable::mutex; +use std::sync::arc::UnsafeArc; +use std::rt::mutex; use super::{IoResult, retry, keep_going}; use super::c; @@ -215,7 +216,7 @@ pub fn init() {} pub fn init() { unsafe { - use std::unstable::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT}; + use std::rt::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT}; static mut INITIALIZED: bool = false; static mut LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT; diff --git a/src/libnative/io/pipe_unix.rs b/src/libnative/io/pipe_unix.rs index a53a58b6cec43..e82b6c51f2f3f 100644 --- a/src/libnative/io/pipe_unix.rs +++ b/src/libnative/io/pipe_unix.rs @@ -15,7 +15,8 @@ use std::intrinsics; use std::io; use std::mem; use std::rt::rtio; -use std::unstable::mutex; +use std::sync::arc::UnsafeArc; +use std::rt::mutex; use super::{IoResult, retry}; use super::net; diff --git a/src/libnative/io/pipe_win32.rs b/src/libnative/io/pipe_win32.rs index cd4cbf2c90f32..995ee91271956 100644 --- a/src/libnative/io/pipe_win32.rs +++ b/src/libnative/io/pipe_win32.rs @@ -94,7 +94,7 @@ use std::os; use std::ptr; use std::rt::rtio; use std::sync::atomics; -use std::unstable::mutex; +use std::rt::mutex; use super::IoResult; use super::c; diff --git a/src/libnative/io/timer_helper.rs b/src/libnative/io/timer_helper.rs new file mode 100644 index 0000000000000..105922203a753 --- /dev/null +++ b/src/libnative/io/timer_helper.rs @@ -0,0 +1,149 @@ +// Copyright 2013-2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Implementation of the helper thread for the timer module +//! +//! This module contains the management necessary for the timer worker thread. +//! This thread is responsible for performing the send()s on channels for timers +//! that are using channels instead of a blocking call. +//! +//! The timer thread is lazily initialized, and it's shut down via the +//! `shutdown` function provided. It must be maintained as an invariant that +//! `shutdown` is only called when the entire program is finished. No new timers +//! can be created in the future and there must be no active timers at that +//! time. + +use std::mem; +use std::rt::bookkeeping; +use std::rt; +use std::rt::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT}; + +use io::timer::{Req, Shutdown}; +use task; + +// You'll note that these variables are *not* protected by a lock. These +// variables are initialized with a Once before any Timer is created and are +// only torn down after everything else has exited. This means that these +// variables are read-only during use (after initialization) and both of which +// are safe to use concurrently. +static mut HELPER_CHAN: *mut Sender = 0 as *mut Sender; +static mut HELPER_SIGNAL: imp::signal = 0 as imp::signal; + +static mut TIMER_HELPER_EXIT: StaticNativeMutex = NATIVE_MUTEX_INIT; + +pub fn boot(helper: fn(imp::signal, Receiver)) { + static mut LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT; + static mut INITIALIZED: bool = false; + + unsafe { + let mut _guard = LOCK.lock(); + if !INITIALIZED { + let (tx, rx) = channel(); + // promote this to a shared channel + drop(tx.clone()); + HELPER_CHAN = mem::transmute(box tx); + let (receive, send) = imp::new(); + HELPER_SIGNAL = send; + + task::spawn(proc() { + bookkeeping::decrement(); + helper(receive, rx); + TIMER_HELPER_EXIT.lock().signal() + }); + + rt::at_exit(proc() { shutdown() }); + INITIALIZED = true; + } + } +} + +pub fn send(req: Req) { + unsafe { + assert!(!HELPER_CHAN.is_null()); + (*HELPER_CHAN).send(req); + imp::signal(HELPER_SIGNAL); + } +} + +fn shutdown() { + // Request a shutdown, and then wait for the task to exit + unsafe { + let guard = TIMER_HELPER_EXIT.lock(); + send(Shutdown); + guard.wait(); + drop(guard); + TIMER_HELPER_EXIT.destroy(); + } + + + // Clean up after ther helper thread + unsafe { + imp::close(HELPER_SIGNAL); + let _chan: Box> = mem::transmute(HELPER_CHAN); + HELPER_CHAN = 0 as *mut Sender; + HELPER_SIGNAL = 0 as imp::signal; + } +} + +#[cfg(unix)] +mod imp { + use libc; + use std::os; + + use io::file::FileDesc; + + pub type signal = libc::c_int; + + pub fn new() -> (signal, signal) { + let pipe = os::pipe(); + (pipe.input, pipe.out) + } + + pub fn signal(fd: libc::c_int) { + FileDesc::new(fd, false).inner_write([0]).unwrap(); + } + + pub fn close(fd: libc::c_int) { + let _fd = FileDesc::new(fd, true); + } +} + +#[cfg(windows)] +mod imp { + use libc::{BOOL, LPCSTR, HANDLE, LPSECURITY_ATTRIBUTES, CloseHandle}; + use std::ptr; + use libc; + + pub type signal = HANDLE; + + pub fn new() -> (HANDLE, HANDLE) { + unsafe { + let handle = CreateEventA(ptr::mut_null(), libc::FALSE, libc::FALSE, + ptr::null()); + (handle, handle) + } + } + + pub fn signal(handle: HANDLE) { + assert!(unsafe { SetEvent(handle) != 0 }); + } + + pub fn close(handle: HANDLE) { + assert!(unsafe { CloseHandle(handle) != 0 }); + } + + extern "system" { + fn CreateEventA(lpSecurityAttributes: LPSECURITY_ATTRIBUTES, + bManualReset: BOOL, + bInitialState: BOOL, + lpName: LPCSTR) -> HANDLE; + fn SetEvent(hEvent: HANDLE) -> BOOL; + } +} diff --git a/src/libnative/task.rs b/src/libnative/task.rs index 4183dec19d02d..1f23c385c901a 100644 --- a/src/libnative/task.rs +++ b/src/libnative/task.rs @@ -25,7 +25,7 @@ use std::rt::task::{Task, BlockedTask, SendMessage}; use std::rt::thread::Thread; use std::rt; use std::task::TaskOpts; -use std::unstable::mutex::NativeMutex; +use std::rt::mutex::NativeMutex; use io; use task; diff --git a/src/librustuv/queue.rs b/src/librustuv/queue.rs index 98ae865cb1da3..2e55c1a7067c9 100644 --- a/src/librustuv/queue.rs +++ b/src/librustuv/queue.rs @@ -24,7 +24,8 @@ use alloc::arc::Arc; use libc::c_void; use std::mem; use std::rt::task::BlockedTask; -use std::unstable::mutex::NativeMutex; +use std::sync::arc::UnsafeArc; +use std::rt::mutex::NativeMutex; use mpsc = std::sync::mpsc_queue; use async::AsyncWatcher; diff --git a/src/libstd/comm/shared.rs b/src/libstd/comm/shared.rs index 3fde584a46f71..9c9cb9a99e614 100644 --- a/src/libstd/comm/shared.rs +++ b/src/libstd/comm/shared.rs @@ -30,7 +30,7 @@ use rt::local::Local; use rt::task::{Task, BlockedTask}; use rt::thread::Thread; use sync::atomics; -use unstable::mutex::NativeMutex; +use rt::mutex::NativeMutex; use mpsc = sync::mpsc_queue; diff --git a/src/libstd/comm/sync.rs b/src/libstd/comm/sync.rs index 819e885526cbf..db09f4ecbfb2b 100644 --- a/src/libstd/comm/sync.rs +++ b/src/libstd/comm/sync.rs @@ -46,7 +46,7 @@ use rt::local::Local; use rt::task::{Task, BlockedTask}; use sync::atomics; use ty::Unsafe; -use unstable::mutex::{NativeMutex, LockGuard}; +use rt::mutex::{NativeMutex, LockGuard}; use vec::Vec; pub struct Packet { diff --git a/src/libstd/os.rs b/src/libstd/os.rs index dbddee8fce286..04c71f94634fa 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -161,7 +161,7 @@ Accessing environment variables is not generally threadsafe. Serialize access through a global lock. */ fn with_env_lock(f: || -> T) -> T { - use unstable::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT}; + use rt::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT}; static mut lock: StaticNativeMutex = NATIVE_MUTEX_INIT; diff --git a/src/libstd/rt/args.rs b/src/libstd/rt/args.rs index e016c9da418e1..30f7abc81447d 100644 --- a/src/libstd/rt/args.rs +++ b/src/libstd/rt/args.rs @@ -48,7 +48,7 @@ mod imp { use iter::Iterator; use option::{Option, Some, None}; use owned::Box; - use unstable::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT}; + use rt::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT}; use mem; use vec::Vec; use ptr::RawPtr; diff --git a/src/libstd/rt/backtrace.rs b/src/libstd/rt/backtrace.rs index f4cb770544c46..c37fae9746847 100644 --- a/src/libstd/rt/backtrace.rs +++ b/src/libstd/rt/backtrace.rs @@ -242,7 +242,7 @@ mod imp { use mem; use option::{Some, None, Option}; use result::{Ok, Err}; - use unstable::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT}; + use rt::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT}; use uw = rt::libunwind; struct Context<'a> { @@ -515,7 +515,7 @@ mod imp { use str::StrSlice; use unstable::dynamic_lib::DynamicLibrary; use intrinsics; - use unstable::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT}; + use rt::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT}; use slice::ImmutableVector; extern "system" { diff --git a/src/libstd/rt/bookkeeping.rs b/src/libstd/rt/bookkeeping.rs index 9e772d8ad2385..b20f6b852302f 100644 --- a/src/libstd/rt/bookkeeping.rs +++ b/src/libstd/rt/bookkeeping.rs @@ -22,7 +22,7 @@ #![doc(hidden)] use sync::atomics; -use unstable::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT}; +use rt::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT}; static mut TASK_COUNT: atomics::AtomicUint = atomics::INIT_ATOMIC_UINT; static mut TASK_LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT; diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs index d2131ad44fb30..26a9813c07d75 100644 --- a/src/libstd/rt/mod.rs +++ b/src/libstd/rt/mod.rs @@ -92,9 +92,10 @@ pub mod shouldnt_be_public { // Internal macros used by the runtime. mod macros; -/// Implementations of language-critical runtime features like @. pub mod task; +pub mod mutex; + // The EventLoop and internal synchronous I/O interface. pub mod rtio; diff --git a/src/libstd/unstable/mutex.rs b/src/libstd/rt/mutex.rs similarity index 99% rename from src/libstd/unstable/mutex.rs rename to src/libstd/rt/mutex.rs index 04da7dab6c658..683d142b86ab3 100644 --- a/src/libstd/unstable/mutex.rs +++ b/src/libstd/rt/mutex.rs @@ -33,7 +33,7 @@ //! # Example //! //! ```rust -//! use std::unstable::mutex::{NativeMutex, StaticNativeMutex, NATIVE_MUTEX_INIT}; +//! use std::rt::mutex::{NativeMutex, StaticNativeMutex, NATIVE_MUTEX_INIT}; //! //! // Use a statically initialized mutex //! static mut LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT; @@ -109,7 +109,7 @@ impl StaticNativeMutex { /// # Example /// /// ```rust - /// use std::unstable::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT}; + /// use std::rt::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT}; /// static mut LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT; /// unsafe { /// let _guard = LOCK.lock(); @@ -183,7 +183,7 @@ impl NativeMutex { /// /// # Example /// ```rust - /// use std::unstable::mutex::NativeMutex; + /// use std::rt::mutex::NativeMutex; /// unsafe { /// let mut lock = NativeMutex::new(); /// diff --git a/src/libstd/unstable/dynamic_lib.rs b/src/libstd/unstable/dynamic_lib.rs index 6302ab39dd87c..55dc5f5cdd6e4 100644 --- a/src/libstd/unstable/dynamic_lib.rs +++ b/src/libstd/unstable/dynamic_lib.rs @@ -223,8 +223,8 @@ pub mod dl { dlopen(ptr::null(), Lazy as libc::c_int) as *u8 } - pub fn check_for_errors_in(f: || -> T) -> Result { - use unstable::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT}; + pub fn check_for_errors_in(f: || -> T) -> Result { + use rt::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT}; static mut lock: StaticNativeMutex = NATIVE_MUTEX_INIT; unsafe { // dlerror isn't thread safe, so we need to lock around this entire diff --git a/src/libstd/unstable/mod.rs b/src/libstd/unstable/mod.rs index d8de6463fabbd..081e1534843a1 100644 --- a/src/libstd/unstable/mod.rs +++ b/src/libstd/unstable/mod.rs @@ -13,5 +13,4 @@ pub mod dynamic_lib; pub mod sync; -pub mod mutex; diff --git a/src/libstd/unstable/sync.rs b/src/libstd/unstable/sync.rs index f0f7e40ce09b8..73705a3be01f2 100644 --- a/src/libstd/unstable/sync.rs +++ b/src/libstd/unstable/sync.rs @@ -13,7 +13,8 @@ use alloc::arc::Arc; use clone::Clone; use kinds::Send; use ty::Unsafe; -use unstable::mutex::NativeMutex; +use sync::arc::UnsafeArc; +use rt::mutex::NativeMutex; struct ExData { lock: NativeMutex, diff --git a/src/libsync/mutex.rs b/src/libsync/mutex.rs index 54c3a9c77f816..4ab59c0fa1401 100644 --- a/src/libsync/mutex.rs +++ b/src/libsync/mutex.rs @@ -64,7 +64,7 @@ use std::rt::task::{BlockedTask, Task}; use std::rt::thread::Thread; use std::sync::atomics; use std::ty::Unsafe; -use std::unstable::mutex; +use std::rt::mutex; use q = mpsc_intrusive; diff --git a/src/llvm b/src/llvm index 0a894645cf120..4b4d0533b4f76 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit 0a894645cf120539876e9eb4eb0d7b572dfa9d14 +Subproject commit 4b4d0533b4f76cc3fbba31bd9e7ac02e0c738b1d