diff options
| author | Ronald Kinard <[email protected]> | 2017-03-11 23:20:34 -0600 |
|---|---|---|
| committer | GitHub <[email protected]> | 2017-03-11 23:20:34 -0600 |
| commit | 368ee624e72342db4b142946ae0f4e3443bdf0d4 (patch) | |
| tree | 8ed882bdd90d8d7a7f00cef25a99e06ed0ed2cc6 /ctr-std/src/sys | |
| parent | Merge pull request #24 from FenrirWolf/unit_type (diff) | |
| parent | Bump minimum thread stack size (diff) | |
| download | ctru-rs-368ee624e72342db4b142946ae0f4e3443bdf0d4.tar.xz ctru-rs-368ee624e72342db4b142946ae0f4e3443bdf0d4.zip | |
Merge pull request #26 from FenrirWolf/thread
Initial thread support
Diffstat (limited to 'ctr-std/src/sys')
| -rw-r--r-- | ctr-std/src/sys/unix/condvar.rs | 111 | ||||
| -rw-r--r-- | ctr-std/src/sys/unix/mod.rs | 3 | ||||
| -rw-r--r-- | ctr-std/src/sys/unix/rwlock.rs | 61 | ||||
| -rw-r--r-- | ctr-std/src/sys/unix/thread.rs | 97 | ||||
| -rw-r--r-- | ctr-std/src/sys/unix/time.rs | 19 |
5 files changed, 285 insertions, 6 deletions
diff --git a/ctr-std/src/sys/unix/condvar.rs b/ctr-std/src/sys/unix/condvar.rs new file mode 100644 index 0000000..f19922c --- /dev/null +++ b/ctr-std/src/sys/unix/condvar.rs @@ -0,0 +1,111 @@ +// Copyright 2016 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. + +// *Implementation adapted from `/sys/redox/condvar.rs` + +use cell::UnsafeCell; +use intrinsics::atomic_cxchg; +use ptr; +use time::Duration; + +use sys::mutex::{self, Mutex}; + +use libctru::synchronization::{__sync_get_arbiter, LightLock}; +use libctru::svc::{svcArbitrateAddress, ArbitrationType}; + +pub struct Condvar { + lock: UnsafeCell<*mut LightLock>, +} + +unsafe impl Send for Condvar {} +unsafe impl Sync for Condvar {} + +impl Condvar { + pub const fn new() -> Condvar { + Condvar { + lock: UnsafeCell::new(ptr::null_mut()), + } + } + + #[inline] + pub unsafe fn init(&self) { + *self.lock.get() = ptr::null_mut(); + } + + #[inline] + pub fn notify_one(&self) { + unsafe { + let arbiter = __sync_get_arbiter(); + + svcArbitrateAddress(arbiter, + *self.lock.get() as u32, + ArbitrationType::ARBITRATION_SIGNAL, + 1, + 0); + } + } + + #[inline] + pub fn notify_all(&self) { + unsafe { + let lock = self.lock.get(); + + if *lock == ptr::null_mut() { + return; + } + + let arbiter = __sync_get_arbiter(); + + svcArbitrateAddress(arbiter, + *self.lock.get() as u32, + ArbitrationType::ARBITRATION_SIGNAL, + -1, + 0); + } + } + + #[inline] + pub fn wait(&self, mutex: &Mutex) { + unsafe { + let lock = self.lock.get(); + + if *lock != mutex::raw(mutex) { + if *lock != ptr::null_mut() { + panic!("Condvar used with more than one Mutex"); + } + + atomic_cxchg(lock as *mut usize, 0, mutex::raw(mutex) as usize); + } + + mutex.unlock(); + + let arbiter = __sync_get_arbiter(); + + svcArbitrateAddress(arbiter, + *self.lock.get() as u32, + ArbitrationType::ARBITRATION_WAIT_IF_LESS_THAN, + 0, + 0); + + mutex.lock(); + } + } + + #[inline] + pub fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool { + ::sys_common::util::dumb_print(format_args!("condvar wait_timeout\n")); + unimplemented!(); + } + + #[inline] + pub unsafe fn destroy(&self) { + *self.lock.get() = ptr::null_mut(); + } +} diff --git a/ctr-std/src/sys/unix/mod.rs b/ctr-std/src/sys/unix/mod.rs index 0da1d3b..76a4555 100644 --- a/ctr-std/src/sys/unix/mod.rs +++ b/ctr-std/src/sys/unix/mod.rs @@ -13,6 +13,7 @@ use io::{self, ErrorKind}; use libc; +pub mod condvar; pub mod ext; pub mod fast_thread_local; pub mod fd; @@ -22,6 +23,8 @@ pub mod mutex; pub mod os; pub mod os_str; pub mod path; +pub mod rwlock; +pub mod thread; pub mod thread_local; pub mod time; diff --git a/ctr-std/src/sys/unix/rwlock.rs b/ctr-std/src/sys/unix/rwlock.rs new file mode 100644 index 0000000..d74b614 --- /dev/null +++ b/ctr-std/src/sys/unix/rwlock.rs @@ -0,0 +1,61 @@ +// Copyright 2016 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 super::mutex::Mutex; + +pub struct RWLock { + mutex: Mutex +} + +unsafe impl Send for RWLock {} +unsafe impl Sync for RWLock {} + +impl RWLock { + pub const fn new() -> RWLock { + RWLock { + mutex: Mutex::new() + } + } + + #[inline] + pub unsafe fn read(&self) { + self.mutex.lock(); + } + + #[inline] + pub unsafe fn try_read(&self) -> bool { + self.mutex.try_lock() + } + + #[inline] + pub unsafe fn write(&self) { + self.mutex.lock(); + } + + #[inline] + pub unsafe fn try_write(&self) -> bool { + self.mutex.try_lock() + } + + #[inline] + pub unsafe fn read_unlock(&self) { + self.mutex.unlock(); + } + + #[inline] + pub unsafe fn write_unlock(&self) { + self.mutex.unlock(); + } + + #[inline] + pub unsafe fn destroy(&self) { + self.mutex.destroy(); + } +} diff --git a/ctr-std/src/sys/unix/thread.rs b/ctr-std/src/sys/unix/thread.rs new file mode 100644 index 0000000..572ac72 --- /dev/null +++ b/ctr-std/src/sys/unix/thread.rs @@ -0,0 +1,97 @@ +// Copyright 2016 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 alloc::boxed::FnBox; +use libc; +use cmp; +use ffi::CStr; +use io; +use mem; +use ptr; +use sys_common::thread::start_thread; +use time::Duration; + +use libctru::svc::{svcSleepThread, svcGetThreadPriority}; +use libctru::thread::{threadCreate, threadJoin, threadFree}; +use libctru::thread::Thread as ThreadHandle; + +pub struct Thread { + handle: ThreadHandle, +} + +// Some platforms may have pthread_t as a pointer in which case we still want +// a thread to be Send/Sync +unsafe impl Send for Thread {} +unsafe impl Sync for Thread {} + +impl Thread { + pub unsafe fn new<'a>(stack: usize, p: Box<FnBox() + 'a>) -> io::Result<Thread> { + let p = box p; + let stack_size = cmp::max(stack, 0x10000); + + // this retrieves the main thread's priority value. child threads need + // to be spawned with a greater priority (smaller priority value) than + // the main thread + let mut priority = 0; + svcGetThreadPriority(&mut priority, 0xFFFF8000); + priority -= 1; + + let handle = threadCreate(Some(thread_func), &*p as *const _ as *mut _, + stack_size, priority, -2, 0); + + return if handle == ptr::null_mut() { + Err(io::Error::from_raw_os_error(libc::EAGAIN)) + } else { + mem::forget(p); // ownership passed to the new thread + Ok(Thread { handle: handle }) + }; + + extern "C" fn thread_func(start: *mut libc::c_void) { + unsafe { start_thread(start) } + } + } + + pub fn yield_now() { + unimplemented!() + } + + pub fn set_name(_name: &CStr) { + // can't set thread names on the 3DS + } + + pub fn sleep(dur: Duration) { + unsafe { + let nanos = dur.as_secs() * 1_000_000_000 + dur.subsec_nanos() as u64; + svcSleepThread(nanos as i64) + } + } + + pub fn join(self) { + unsafe { + let ret = threadJoin(self.handle, u64::max_value()); + threadFree(self.handle); + mem::forget(self); + debug_assert_eq!(ret, 0); + } + } + + pub fn id(&self) -> usize { + unimplemented!() + } + + pub fn into_id(self) -> usize { + unimplemented!() + } +} + +pub mod guard { + pub unsafe fn current() -> Option<usize> { None } + pub unsafe fn init() -> Option<usize> { None } +} diff --git a/ctr-std/src/sys/unix/time.rs b/ctr-std/src/sys/unix/time.rs index 052bd32..e8c0632 100644 --- a/ctr-std/src/sys/unix/time.rs +++ b/ctr-std/src/sys/unix/time.rs @@ -106,6 +106,7 @@ impl Ord for Timespec { mod inner { use fmt; use libc; + use sync::Once; use sys::cvt; use sys_common::mul_div_u64; use time::Duration; @@ -113,7 +114,6 @@ mod inner { use super::NSEC_PER_SEC; use super::Timespec; - use spin; use libctru; #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] @@ -164,7 +164,7 @@ mod inner { } // The initial system tick after which all Instants occur - static TICK: spin::Once<u64> = spin::Once::new(); + static mut TICK: u64 = 0; // A source of monotonic time based on ticks of the 3DS CPU. Returns the // number of system ticks elapsed since an arbitrary point in the past @@ -180,7 +180,13 @@ mod inner { // subsequent calls to this function return the previously generated // tick value fn get_first_tick() -> u64 { - *TICK.call_once(get_system_tick) + static ONCE: Once = Once::new(); + unsafe { + ONCE.call_once(|| { + TICK = get_system_tick(); + }); + TICK + } } // Gets the current system tick @@ -201,11 +207,12 @@ mod inner { // on a New 3DS running in 804MHz mode // // See https://www.3dbrew.org/wiki/Hardware#Common_hardware - fn info() -> CtrClockInfo { - CtrClockInfo { + fn info() -> &'static CtrClockInfo { + static INFO: CtrClockInfo = CtrClockInfo { numer: 1_000_000_000, denom: 268_111_856, - } + }; + &INFO } fn dur2intervals(dur: &Duration) -> u64 { |