diff options
| author | Fenrir <[email protected]> | 2017-03-05 22:57:34 -0700 |
|---|---|---|
| committer | Fenrir <[email protected]> | 2017-03-05 22:57:34 -0700 |
| commit | 5c02db6cb953433d3837faed1451b2f804dc81a9 (patch) | |
| tree | b21b480d42a630e9f85d9fb88b6d74f7efe827f1 /ctr-std/src/sync/mpsc/blocking.rs | |
| parent | Initial thread support (diff) | |
| download | ctru-rs-5c02db6cb953433d3837faed1451b2f804dc81a9.tar.xz ctru-rs-5c02db6cb953433d3837faed1451b2f804dc81a9.zip | |
Add the rest of std::sync
Diffstat (limited to 'ctr-std/src/sync/mpsc/blocking.rs')
| -rw-r--r-- | ctr-std/src/sync/mpsc/blocking.rs | 96 |
1 files changed, 96 insertions, 0 deletions
diff --git a/ctr-std/src/sync/mpsc/blocking.rs b/ctr-std/src/sync/mpsc/blocking.rs new file mode 100644 index 0000000..0f9ef6f --- /dev/null +++ b/ctr-std/src/sync/mpsc/blocking.rs @@ -0,0 +1,96 @@ +// 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::{self, Thread}; +use sync::atomic::{AtomicBool, Ordering}; +use sync::Arc; +use mem; +use time::Instant; + +struct Inner { + thread: Thread, + woken: AtomicBool, +} + +unsafe impl Send for Inner {} +unsafe impl Sync for Inner {} + +#[derive(Clone)] +pub struct SignalToken { + inner: Arc<Inner>, +} + +pub struct WaitToken { + inner: Arc<Inner>, +} + +impl !Send for WaitToken {} + +impl !Sync for WaitToken {} + +pub fn tokens() -> (WaitToken, SignalToken) { + let inner = Arc::new(Inner { + thread: thread::current(), + woken: AtomicBool::new(false), + }); + let wait_token = WaitToken { + inner: inner.clone(), + }; + 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 usize value. Useful for storing in a pipe's state + /// flag. + #[inline] + pub unsafe fn cast_to_usize(self) -> usize { + mem::transmute(self.inner) + } + + /// Convert from an unsafe usize value. Useful for retrieving a pipe's state + /// flag. + #[inline] + pub unsafe fn cast_from_usize(signal_ptr: usize) -> SignalToken { + SignalToken { inner: mem::transmute(signal_ptr) } + } +} + +impl WaitToken { + pub fn wait(self) { + while !self.inner.woken.load(Ordering::SeqCst) { + thread::park() + } + } + + /// Returns true if we wake up normally, false otherwise. + pub fn wait_max_until(self, end: Instant) -> bool { + while !self.inner.woken.load(Ordering::SeqCst) { + let now = Instant::now(); + if now >= end { + return false; + } + thread::park_timeout(end - now) + } + true + } +} |