rust/src/libstd/comm/blocking.rs
Aaron Turon a27fbac868 Revise std::thread API to join by default
This commit is part of a series that introduces a `std::thread` API to
replace `std::task`.

In the new API, `spawn` returns a `JoinGuard`, which by default will
join the spawned thread when dropped. It can also be used to join
explicitly at any time, returning the thread's result. Alternatively,
the spawned thread can be explicitly detached (so no join takes place).

As part of this change, Rust processes now terminate when the main
thread exits, even if other detached threads are still running, moving
Rust closer to standard threading models. This new behavior may break code
that was relying on the previously implicit join-all.

In addition to the above, the new thread API also offers some built-in
support for building blocking abstractions in user space; see the module
doc for details.

Closes #18000

[breaking-change]
2014-12-18 23:31:52 -08:00

83 lines
2 KiB
Rust

// Copyright 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 <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.
//! Generic support for building blocking abstractions.
use thread::Thread;
use sync::atomic::{AtomicBool, INIT_ATOMIC_BOOL, Ordering};
use sync::Arc;
use kinds::marker::{NoSend, NoSync};
use mem;
use clone::Clone;
struct Inner {
thread: Thread,
woken: AtomicBool,
}
#[deriving(Clone)]
pub struct SignalToken {
inner: Arc<Inner>,
}
pub struct WaitToken {
inner: Arc<Inner>,
no_send: NoSend,
no_sync: NoSync,
}
pub fn tokens() -> (WaitToken, SignalToken) {
let inner = Arc::new(Inner {
thread: Thread::current(),
woken: INIT_ATOMIC_BOOL,
});
let wait_token = WaitToken {
inner: inner.clone(),
no_send: NoSend,
no_sync: NoSync,
};
let signal_token = SignalToken {
inner: inner
};
(wait_token, signal_token)
}
impl SignalToken {
pub fn signal(&self) -> bool {
let wake = !self.inner.woken.compare_and_swap(false, true, Ordering::SeqCst);
if wake {
self.inner.thread.unpark();
}
wake
}
/// Convert to an unsafe uint value. Useful for storing in a pipe's state
/// flag.
#[inline]
pub unsafe fn cast_to_uint(self) -> uint {
mem::transmute(self.inner)
}
/// Convert from an unsafe uint value. Useful for retrieving a pipe's state
/// flag.
#[inline]
pub unsafe fn cast_from_uint(signal_ptr: uint) -> SignalToken {
SignalToken { inner: mem::transmute(signal_ptr) }
}
}
impl WaitToken {
pub fn wait(self) {
while !self.inner.woken.load(Ordering::SeqCst) {
Thread::park()
}
}
}