aboutsummaryrefslogtreecommitdiff
path: root/ctr-std/src/sync/mpsc/blocking.rs
diff options
context:
space:
mode:
authorFenrir <[email protected]>2017-03-05 22:57:34 -0700
committerFenrir <[email protected]>2017-03-05 22:57:34 -0700
commit5c02db6cb953433d3837faed1451b2f804dc81a9 (patch)
treeb21b480d42a630e9f85d9fb88b6d74f7efe827f1 /ctr-std/src/sync/mpsc/blocking.rs
parentInitial thread support (diff)
downloadctru-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.rs96
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
+ }
+}