diff options
| author | Valentin <[email protected]> | 2018-06-15 18:57:24 +0200 |
|---|---|---|
| committer | FenrirWolf <[email protected]> | 2018-06-15 10:57:24 -0600 |
| commit | f2a90174bb36b9ad528e863ab34c02ebce002b02 (patch) | |
| tree | 959e8d67883d3a89e179b3549b1f30d28e51a87c /ctr-std/src/sys/cloudabi/condvar.rs | |
| parent | Merge pull request #68 from linouxis9/master (diff) | |
| download | ctru-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.rs | 169 |
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" + ); + } +} |