aboutsummaryrefslogtreecommitdiff
path: root/ctr-std/src/sys/cloudabi/condvar.rs
diff options
context:
space:
mode:
authorValentin <[email protected]>2018-06-15 18:57:24 +0200
committerFenrirWolf <[email protected]>2018-06-15 10:57:24 -0600
commitf2a90174bb36b9ad528e863ab34c02ebce002b02 (patch)
tree959e8d67883d3a89e179b3549b1f30d28e51a87c /ctr-std/src/sys/cloudabi/condvar.rs
parentMerge pull request #68 from linouxis9/master (diff)
downloadctru-rs-f2a90174bb36b9ad528e863ab34c02ebce002b02.tar.xz
ctru-rs-f2a90174bb36b9ad528e863ab34c02ebce002b02.zip
Update for latest nightly 2018-06-09 (#70)
* Update for latest nightly 2018-06-09 * We now have a proper horizon os and sys modules in libstd
Diffstat (limited to 'ctr-std/src/sys/cloudabi/condvar.rs')
-rw-r--r--ctr-std/src/sys/cloudabi/condvar.rs169
1 files changed, 169 insertions, 0 deletions
diff --git a/ctr-std/src/sys/cloudabi/condvar.rs b/ctr-std/src/sys/cloudabi/condvar.rs
new file mode 100644
index 0000000..c05c837
--- /dev/null
+++ b/ctr-std/src/sys/cloudabi/condvar.rs
@@ -0,0 +1,169 @@
+// Copyright 2018 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.
+
+use cell::UnsafeCell;
+use mem;
+use sync::atomic::{AtomicU32, Ordering};
+use sys::cloudabi::abi;
+use sys::mutex::{self, Mutex};
+use sys::time::dur2intervals;
+use time::Duration;
+
+extern "C" {
+ #[thread_local]
+ static __pthread_thread_id: abi::tid;
+}
+
+pub struct Condvar {
+ condvar: UnsafeCell<AtomicU32>,
+}
+
+unsafe impl Send for Condvar {}
+unsafe impl Sync for Condvar {}
+
+impl Condvar {
+ pub const fn new() -> Condvar {
+ Condvar {
+ condvar: UnsafeCell::new(AtomicU32::new(abi::CONDVAR_HAS_NO_WAITERS.0)),
+ }
+ }
+
+ pub unsafe fn init(&mut self) {}
+
+ pub unsafe fn notify_one(&self) {
+ let condvar = self.condvar.get();
+ if (*condvar).load(Ordering::Relaxed) != abi::CONDVAR_HAS_NO_WAITERS.0 {
+ let ret = abi::condvar_signal(condvar as *mut abi::condvar, abi::scope::PRIVATE, 1);
+ assert_eq!(
+ ret,
+ abi::errno::SUCCESS,
+ "Failed to signal on condition variable"
+ );
+ }
+ }
+
+ pub unsafe fn notify_all(&self) {
+ let condvar = self.condvar.get();
+ if (*condvar).load(Ordering::Relaxed) != abi::CONDVAR_HAS_NO_WAITERS.0 {
+ let ret = abi::condvar_signal(
+ condvar as *mut abi::condvar,
+ abi::scope::PRIVATE,
+ abi::nthreads::max_value(),
+ );
+ assert_eq!(
+ ret,
+ abi::errno::SUCCESS,
+ "Failed to broadcast on condition variable"
+ );
+ }
+ }
+
+ pub unsafe fn wait(&self, mutex: &Mutex) {
+ let mutex = mutex::raw(mutex);
+ assert_eq!(
+ (*mutex).load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0,
+ __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
+ "This lock is not write-locked by this thread"
+ );
+
+ // Call into the kernel to wait on the condition variable.
+ let condvar = self.condvar.get();
+ let subscription = abi::subscription {
+ type_: abi::eventtype::CONDVAR,
+ union: abi::subscription_union {
+ condvar: abi::subscription_condvar {
+ condvar: condvar as *mut abi::condvar,
+ condvar_scope: abi::scope::PRIVATE,
+ lock: mutex as *mut abi::lock,
+ lock_scope: abi::scope::PRIVATE,
+ },
+ },
+ ..mem::zeroed()
+ };
+ let mut event: abi::event = mem::uninitialized();
+ let mut nevents: usize = mem::uninitialized();
+ let ret = abi::poll(&subscription, &mut event, 1, &mut nevents);
+ assert_eq!(
+ ret,
+ abi::errno::SUCCESS,
+ "Failed to wait on condition variable"
+ );
+ assert_eq!(
+ event.error,
+ abi::errno::SUCCESS,
+ "Failed to wait on condition variable"
+ );
+ }
+
+ pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
+ let mutex = mutex::raw(mutex);
+ assert_eq!(
+ (*mutex).load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0,
+ __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
+ "This lock is not write-locked by this thread"
+ );
+
+ // Call into the kernel to wait on the condition variable.
+ let condvar = self.condvar.get();
+ let subscriptions = [
+ abi::subscription {
+ type_: abi::eventtype::CONDVAR,
+ union: abi::subscription_union {
+ condvar: abi::subscription_condvar {
+ condvar: condvar as *mut abi::condvar,
+ condvar_scope: abi::scope::PRIVATE,
+ lock: mutex as *mut abi::lock,
+ lock_scope: abi::scope::PRIVATE,
+ },
+ },
+ ..mem::zeroed()
+ },
+ abi::subscription {
+ type_: abi::eventtype::CLOCK,
+ union: abi::subscription_union {
+ clock: abi::subscription_clock {
+ clock_id: abi::clockid::MONOTONIC,
+ timeout: dur2intervals(&dur),
+ ..mem::zeroed()
+ },
+ },
+ ..mem::zeroed()
+ },
+ ];
+ let mut events: [abi::event; 2] = mem::uninitialized();
+ let mut nevents: usize = mem::uninitialized();
+ let ret = abi::poll(subscriptions.as_ptr(), events.as_mut_ptr(), 2, &mut nevents);
+ assert_eq!(
+ ret,
+ abi::errno::SUCCESS,
+ "Failed to wait on condition variable"
+ );
+ for i in 0..nevents {
+ assert_eq!(
+ events[i].error,
+ abi::errno::SUCCESS,
+ "Failed to wait on condition variable"
+ );
+ if events[i].type_ == abi::eventtype::CONDVAR {
+ return true;
+ }
+ }
+ false
+ }
+
+ pub unsafe fn destroy(&self) {
+ let condvar = self.condvar.get();
+ assert_eq!(
+ (*condvar).load(Ordering::Relaxed),
+ abi::CONDVAR_HAS_NO_WAITERS.0,
+ "Attempted to destroy a condition variable with blocked threads"
+ );
+ }
+}