diff --git a/src/condvar.rs b/src/condvar.rs deleted file mode 100644 index 4d94a31..0000000 --- a/src/condvar.rs +++ /dev/null @@ -1,117 +0,0 @@ -//! PThread condition variables implemented using libctru. - -#[no_mangle] -pub unsafe extern "C" fn pthread_cond_init( - cond: *mut libc::pthread_cond_t, - _attr: *const libc::pthread_condattr_t, -) -> libc::c_int { - ctru_sys::CondVar_Init(cond as _); - - 0 -} - -#[no_mangle] -pub unsafe extern "C" fn pthread_cond_signal(cond: *mut libc::pthread_cond_t) -> libc::c_int { - ctru_sys::CondVar_WakeUp(cond as _, 1); - - 0 -} - -#[no_mangle] -pub unsafe extern "C" fn pthread_cond_broadcast(cond: *mut libc::pthread_cond_t) -> libc::c_int { - ctru_sys::CondVar_WakeUp(cond as _, -1); - - 0 -} - -#[no_mangle] -pub unsafe extern "C" fn pthread_cond_wait( - cond: *mut libc::pthread_cond_t, - lock: *mut libc::pthread_mutex_t, -) -> libc::c_int { - ctru_sys::CondVar_Wait(cond as _, lock as _); - - 0 -} - -#[no_mangle] -pub unsafe extern "C" fn pthread_cond_timedwait( - cond: *mut libc::pthread_cond_t, - lock: *mut libc::pthread_mutex_t, - abstime: *const libc::timespec, -) -> libc::c_int { - // libctru expects a duration, but we have an absolute timestamp. - // Convert to a duration before calling libctru. - - // Get the current time so we can make a duration - let mut now = libc::timeval { - tv_sec: 0, - tv_usec: 0, - }; - let r = libc::gettimeofday(&mut now, std::ptr::null_mut()); - if r != 0 { - return r; - } - - // Calculate the duration - let duration_nsec = (*abstime) - .tv_sec - // Get the difference in seconds - .saturating_sub(now.tv_sec) - // Convert to nanoseconds - .saturating_mul(1_000_000_000) - // Add the difference in nanoseconds - .saturating_add((*abstime).tv_nsec as i64) - .saturating_sub(now.tv_usec as i64 * 1_000) - // Don't go negative - .max(0); - - let r = ctru_sys::CondVar_WaitTimeout(cond as _, lock as _, duration_nsec); - - // CondVar_WaitTimeout returns a boolean which is true (nonzero) if it timed out - if r == 0 { - 0 - } else { - libc::ETIMEDOUT - } -} - -#[no_mangle] -pub unsafe extern "C" fn pthread_cond_destroy(_cond: *mut libc::pthread_cond_t) -> libc::c_int { - 0 -} - -#[no_mangle] -pub extern "C" fn pthread_condattr_init(_attr: *const libc::pthread_condattr_t) -> libc::c_int { - 0 -} - -#[no_mangle] -pub extern "C" fn pthread_condattr_destroy(_attr: *const libc::pthread_condattr_t) -> libc::c_int { - 0 -} - -#[no_mangle] -pub extern "C" fn pthread_condattr_getclock( - _attr: *const libc::pthread_condattr_t, - clock_id: *mut libc::clockid_t, -) -> libc::c_int { - unsafe { - *clock_id = libc::CLOCK_REALTIME; - } - - 0 -} - -#[no_mangle] -pub extern "C" fn pthread_condattr_setclock( - _attr: *mut libc::pthread_condattr_t, - clock_id: libc::clockid_t, -) -> libc::c_int { - // only one clock is supported, so all other options are considered an error - if clock_id == libc::CLOCK_REALTIME { - 0 - } else { - libc::EINVAL - } -} diff --git a/src/lib.rs b/src/lib.rs index 28046e4..653716a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,9 +2,6 @@ #![allow(non_camel_case_types)] #![allow(clippy::missing_safety_doc)] -mod condvar; mod misc; -mod mutex; -mod rwlock; mod thread; mod thread_keys; diff --git a/src/misc.rs b/src/misc.rs index 1ff9ba0..0ce81e4 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -1,26 +1,13 @@ //! Miscellaneous pthread functions +// The implementation within `newlib` stubs this out *entirely*. It's not possible to use a "syscall". +/* #[no_mangle] pub unsafe extern "C" fn sched_yield() -> libc::c_int { ctru_sys::svcSleepThread(0); 0 } +*/ -#[no_mangle] -pub unsafe extern "C" fn pthread_sigmask( - _how: ::libc::c_int, - _set: *const libc::sigset_t, - _oldset: *mut libc::sigset_t, -) -> ::libc::c_int { - -1 -} - -#[no_mangle] -pub extern "C" fn pthread_atfork( - _prepare: Option, - _parent: Option, - _child: Option, -) -> libc::c_int { - 0 -} +// `pthread_sigmask` and `pthread_atfork` are stubbed out by `newlib` \ No newline at end of file diff --git a/src/mutex.rs b/src/mutex.rs deleted file mode 100644 index 568cb6e..0000000 --- a/src/mutex.rs +++ /dev/null @@ -1,91 +0,0 @@ -//! PThread mutex implemented using libctru. - -#[no_mangle] -pub unsafe extern "C" fn pthread_mutexattr_init( - _attr: *mut libc::pthread_mutexattr_t, -) -> libc::c_int { - 0 -} - -#[no_mangle] -pub unsafe extern "C" fn pthread_mutexattr_settype( - attr: *mut libc::pthread_mutexattr_t, - _type: libc::c_int, -) -> libc::c_int { - let attr: *mut libc::c_int = attr as _; - - *attr = _type as _; - - 0 -} - -#[no_mangle] -pub unsafe extern "C" fn pthread_mutex_init( - lock: *mut libc::pthread_mutex_t, - attr: *const libc::pthread_mutexattr_t, -) -> libc::c_int { - let lock = lock as *mut u8; - - let attr: libc::c_int = *(attr as *const libc::c_int); - - if attr == libc::PTHREAD_MUTEX_NORMAL { - ctru_sys::LightLock_Init(lock as _); - } else if attr == libc::PTHREAD_MUTEX_RECURSIVE { - ctru_sys::RecursiveLock_Init(lock as _) - } - - *(lock.offset(39)) = attr as u8; - - 0 -} - -#[no_mangle] -pub unsafe extern "C" fn pthread_mutex_destroy(_lock: *mut libc::pthread_mutex_t) -> libc::c_int { - 0 -} - -#[no_mangle] -pub unsafe extern "C" fn pthread_mutex_lock(lock: *mut libc::pthread_mutex_t) -> libc::c_int { - let lock = lock as *const u8; - - if *(lock.offset(39)) as u8 == libc::PTHREAD_MUTEX_NORMAL as u8 { - ctru_sys::LightLock_Lock(lock as _); - } else if *(lock.offset(39)) as u8 == libc::PTHREAD_MUTEX_RECURSIVE as u8 { - ctru_sys::RecursiveLock_Lock(lock as _); - } - - 0 -} - -#[no_mangle] -pub unsafe extern "C" fn pthread_mutex_trylock(lock: *mut libc::pthread_mutex_t) -> libc::c_int { - let lock = lock as *const u8; - - if *(lock.offset(39)) as u8 == libc::PTHREAD_MUTEX_NORMAL as u8 { - return ctru_sys::LightLock_TryLock(lock as _); - } else if *(lock.offset(39)) as u8 == libc::PTHREAD_MUTEX_RECURSIVE as u8 { - return ctru_sys::RecursiveLock_TryLock(lock as _); - } - - -1 -} - -#[no_mangle] -pub unsafe extern "C" fn pthread_mutex_unlock(lock: *mut libc::pthread_mutex_t) -> libc::c_int { - let lock = lock as *const u8; - - if *(lock.offset(39)) as u8 == libc::PTHREAD_MUTEX_NORMAL as u8 { - ctru_sys::LightLock_Unlock(lock as _); - } else if *(lock.offset(39)) as u8 == libc::PTHREAD_MUTEX_RECURSIVE as u8 { - ctru_sys::RecursiveLock_Unlock(lock as _); - } - - 0 -} - -#[no_mangle] -pub unsafe extern "C" fn pthread_mutexattr_destroy( - _attr: *mut libc::pthread_mutexattr_t, -) -> libc::c_int { - 0 -} diff --git a/src/rwlock.rs b/src/rwlock.rs deleted file mode 100644 index 365e960..0000000 --- a/src/rwlock.rs +++ /dev/null @@ -1,169 +0,0 @@ -//! PThread read-write lock implemented using libctru. - -use crate::{condvar, mutex}; - -struct rwlock_clear { - mutex: libc::pthread_mutex_t, - cvar: i32, - num_readers: i32, - writer_active: bool, - initialized: bool, -} - -/// Initializes the rwlock internal members if they weren't already -fn init_rwlock(lock: *mut libc::pthread_rwlock_t) { - let lock = lock as *mut rwlock_clear; - - unsafe { - if !(*lock).initialized { - let mut attr = std::mem::MaybeUninit::::uninit(); - mutex::pthread_mutexattr_init(attr.as_mut_ptr()); - let mut attr = attr.assume_init(); - mutex::pthread_mutexattr_settype(&mut attr, libc::PTHREAD_MUTEX_NORMAL); - - mutex::pthread_mutex_init(&mut (*lock).mutex, &attr); - condvar::pthread_cond_init(&mut (*lock).cvar as *mut i32 as *mut _, core::ptr::null()); - - (*lock).num_readers = 0; - (*lock).writer_active = false; - - (*lock).initialized = true; - } - } -} - -#[no_mangle] -pub unsafe extern "C" fn pthread_rwlock_init( - lock: *mut libc::pthread_rwlock_t, - _attr: *const libc::pthread_rwlockattr_t, -) -> libc::c_int { - init_rwlock(lock); - - 0 -} - -#[no_mangle] -pub unsafe extern "C" fn pthread_rwlock_destroy(_lock: *mut libc::pthread_rwlock_t) -> libc::c_int { - 0 -} - -#[no_mangle] -pub unsafe extern "C" fn pthread_rwlock_rdlock(lock: *mut libc::pthread_rwlock_t) -> libc::c_int { - init_rwlock(lock); - let lock = lock as *mut rwlock_clear; - - mutex::pthread_mutex_lock(&mut (*lock).mutex); - - while (*lock).writer_active { - condvar::pthread_cond_wait(&mut (*lock).cvar as *mut i32 as _, &mut (*lock).mutex); - } - - (*lock).num_readers += 1; - - mutex::pthread_mutex_unlock(&mut (*lock).mutex); - - 0 -} - -#[no_mangle] -pub unsafe extern "C" fn pthread_rwlock_tryrdlock( - lock: *mut libc::pthread_rwlock_t, -) -> libc::c_int { - init_rwlock(lock); - let lock = lock as *mut rwlock_clear; - - if mutex::pthread_mutex_trylock(&mut (*lock).mutex) != 0 { - return -1; - } - - while (*lock).writer_active { - condvar::pthread_cond_wait(&mut (*lock).cvar as *mut i32 as _, &mut (*lock).mutex); - } - - (*lock).num_readers += 1; - - mutex::pthread_mutex_unlock(&mut (*lock).mutex); - - 0 -} - -#[no_mangle] -pub unsafe extern "C" fn pthread_rwlock_wrlock(lock: *mut libc::pthread_rwlock_t) -> libc::c_int { - init_rwlock(lock); - let lock = lock as *mut rwlock_clear; - - mutex::pthread_mutex_lock(&mut (*lock).mutex); - - while (*lock).writer_active || (*lock).num_readers > 0 { - condvar::pthread_cond_wait(&mut (*lock).cvar as *mut i32 as _, &mut (*lock).mutex); - } - - (*lock).writer_active = true; - - mutex::pthread_mutex_unlock(&mut (*lock).mutex); - - 0 -} - -#[no_mangle] -pub unsafe extern "C" fn pthread_rwlock_trywrlock( - lock: *mut libc::pthread_rwlock_t, -) -> libc::c_int { - init_rwlock(lock); - let lock = lock as *mut rwlock_clear; - - if mutex::pthread_mutex_trylock(&mut (*lock).mutex) != 0 { - return -1; - } - - while (*lock).writer_active || (*lock).num_readers > 0 { - condvar::pthread_cond_wait(&mut (*lock).cvar as *mut i32 as _, &mut (*lock).mutex); - } - - (*lock).writer_active = true; - - mutex::pthread_mutex_unlock(&mut (*lock).mutex); - - 0 -} - -#[no_mangle] -pub unsafe extern "C" fn pthread_rwlock_unlock(lock: *mut libc::pthread_rwlock_t) -> libc::c_int { - init_rwlock(lock); - let lock = lock as *mut rwlock_clear; - - mutex::pthread_mutex_lock(&mut (*lock).mutex); - - // If there are readers and no writer => Must be a reader - if (*lock).num_readers > 0 && !(*lock).writer_active { - (*lock).num_readers -= 1; - - // If there are no more readers, signal to a waiting writer - if (*lock).num_readers == 0 { - condvar::pthread_cond_signal(&mut (*lock).cvar as *mut i32 as _); - } - // If there are no readers and a writer => Must be a writer - } else if (*lock).num_readers == 0 && (*lock).writer_active { - (*lock).writer_active = false; - - condvar::pthread_cond_broadcast(&mut (*lock).cvar as *mut i32 as _); - } - - mutex::pthread_mutex_unlock(&mut (*lock).mutex); - - 0 -} - -#[no_mangle] -pub unsafe extern "C" fn pthread_rwlockattr_init( - _attr: *mut libc::pthread_rwlockattr_t, -) -> libc::c_int { - 0 -} - -#[no_mangle] -pub unsafe extern "C" fn pthread_rwlockattr_destroy( - _attr: *mut libc::pthread_rwlockattr_t, -) -> libc::c_int { - 0 -} diff --git a/src/thread.rs b/src/thread.rs index 01f2550..c118fb9 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -1,6 +1,5 @@ //! PThread threads implemented using libctru. -use attr::PThreadAttr; use spin::rwlock::RwLock; use std::collections::BTreeMap; use std::ptr; @@ -47,16 +46,18 @@ impl Clone for ShareablePtr { } #[no_mangle] -pub unsafe extern "C" fn pthread_create( +pub unsafe extern "C" fn __syscall_thread_create( native: *mut libc::pthread_t, - attr: *const libc::pthread_attr_t, entrypoint: extern "C" fn(_: *mut libc::c_void) -> *mut libc::c_void, - value: *mut libc::c_void, + arg: *mut libc::c_void, + _stackaddr: *const libc::c_void, + stacksize: libc::size_t, ) -> libc::c_int { - let attr = attr as *const PThreadAttr; - let stack_size = (*attr).stack_size; - let priority = (*attr).priority; - let processor_id = (*attr).processor_id; + let stack_size = stacksize; + // let priority = (*attr).schedparam.sched_priority; + let mut priority = 0; + let _ = ctru_sys::svcGetThreadPriority(&mut priority, ctru_sys::CUR_THREAD_HANDLE); + // let processor_id = (*attr).processor_id; let thread_id = NEXT_ID.fetch_add(1, Ordering::SeqCst) as libc::pthread_t; @@ -74,7 +75,7 @@ pub unsafe extern "C" fn pthread_create( let main: *mut Box = Box::into_raw(Box::new(Box::new(move || { THREAD_ID = thread_id; - let result = entrypoint(value); + let result = entrypoint(arg); // Update the threads map with the result, and remove this thread if // it's detached. @@ -97,9 +98,9 @@ pub unsafe extern "C" fn pthread_create( let thread = ctru_sys::threadCreate( Some(thread_start), main as *mut libc::c_void, - stack_size, + stack_size as usize, priority, - processor_id, + 0, // Normal CPU false, ); @@ -138,19 +139,18 @@ pub unsafe extern "C" fn pthread_create( } #[no_mangle] -pub unsafe extern "C" fn pthread_join( +pub unsafe extern "C" fn __syscall_thread_join( thread_id: libc::pthread_t, - return_value: *mut *mut libc::c_void, -) -> libc::c_int { +) -> *const libc::c_void { // The return value is returned as a pointer if thread_id == MAIN_THREAD_ID { // This is not a valid thread to join on - return libc::EINVAL; + return std::ptr::null(); } let thread_map = THREADS.read(); let Some(&pthread) = thread_map.get(&thread_id) else { // This is not a valid thread ID - return libc::ESRCH + return std::ptr::null(); }; // We need to drop our read guard so it doesn't stay locked while joining // the thread. @@ -158,13 +158,13 @@ pub unsafe extern "C" fn pthread_join( if pthread.is_detached { // Cannot join on a detached thread - return libc::EINVAL; + return std::ptr::null(); } let result = ctru_sys::threadJoin(pthread.thread.0, u64::MAX); if ctru_sys::R_FAILED(result) { // TODO: improve the error code by checking the result further? - return libc::EINVAL; + return std::ptr::null(); } ctru_sys::threadFree(pthread.thread.0); @@ -172,16 +172,14 @@ pub unsafe extern "C" fn pthread_join( // This should always be Some, but we use an if let just in case. if let Some(thread_data) = thread_data { - if !return_value.is_null() { - *return_value = thread_data.result.0; - } + return thread_data.result.0; } - 0 + std::ptr::null() } #[no_mangle] -pub unsafe extern "C" fn pthread_detach(thread_id: libc::pthread_t) -> libc::c_int { +pub unsafe extern "C" fn __syscall_thread_detach(thread_id: libc::pthread_t) -> libc::c_int { if thread_id == MAIN_THREAD_ID { // This is not a valid thread to detach return libc::EINVAL; @@ -210,7 +208,7 @@ pub unsafe extern "C" fn pthread_detach(thread_id: libc::pthread_t) -> libc::c_i } #[no_mangle] -pub unsafe extern "C" fn pthread_self() -> libc::pthread_t { +pub unsafe extern "C" fn __syscall_thread_self() -> libc::pthread_t { let thread_id = THREAD_ID; if thread_id == MAIN_THREAD_ID { @@ -339,8 +337,9 @@ pub unsafe extern "C" fn pthread_setschedparam( 0 } - +/* #[no_mangle] pub unsafe extern "C" fn pthread_getprocessorid_np() -> libc::c_int { ctru_sys::svcGetProcessorID() } +*/ diff --git a/src/thread/attr.rs b/src/thread/attr.rs index b445ddb..cd05d9a 100644 --- a/src/thread/attr.rs +++ b/src/thread/attr.rs @@ -1,92 +1,16 @@ use static_assertions::const_assert; use std::mem; -/// Internal struct for storing pthread attribute data -/// Must be less than or equal to the size of `libc::pthread_attr_t`. We assert -/// this below via static_assertions. -pub struct PThreadAttr { - pub(crate) stack_size: libc::size_t, - pub(crate) priority: libc::c_int, - pub(crate) processor_id: libc::c_int, -} - -const_assert!(mem::size_of::() <= mem::size_of::()); - -impl Default for PThreadAttr { - fn default() -> Self { - // Note: we are ignoring the result here, but errors shouldn't occur - // since we're using a valid handle. - let mut priority = 0; - unsafe { ctru_sys::svcGetThreadPriority(&mut priority, ctru_sys::CUR_THREAD_HANDLE) }; - - PThreadAttr { - stack_size: libc::PTHREAD_STACK_MIN, - - // If no priority value is specified, spawn with the same priority - // as the current thread - priority, - - // If no processor is specified, spawn on the default core. - // (determined by the application's Exheader) - processor_id: -2, - } - } -} - -#[no_mangle] -pub unsafe extern "C" fn pthread_attr_init(attr: *mut libc::pthread_attr_t) -> libc::c_int { - let attr = attr as *mut PThreadAttr; - *attr = PThreadAttr::default(); - - 0 -} - -#[no_mangle] -pub unsafe extern "C" fn pthread_attr_destroy(attr: *mut libc::pthread_attr_t) -> libc::c_int { - std::ptr::drop_in_place(attr as *mut PThreadAttr); - 0 -} - -#[no_mangle] -pub unsafe extern "C" fn pthread_attr_setstacksize( - attr: *mut libc::pthread_attr_t, - stack_size: libc::size_t, -) -> libc::c_int { - let attr = attr as *mut PThreadAttr; - (*attr).stack_size = stack_size; - - 0 -} - -#[no_mangle] -pub unsafe extern "C" fn pthread_attr_getschedparam( - attr: *const libc::pthread_attr_t, - param: *mut libc::sched_param, -) -> libc::c_int { - let attr = attr as *const PThreadAttr; - (*param).sched_priority = (*attr).priority; - 0 -} - -#[no_mangle] -pub unsafe extern "C" fn pthread_attr_setschedparam( - attr: *mut libc::pthread_attr_t, - param: *const libc::sched_param, -) -> libc::c_int { - let attr = attr as *mut PThreadAttr; - (*attr).priority = (*param).sched_priority; - - // TODO: we could validate the priority here if we wanted? - - 0 -} +const_assert!(mem::size_of::() <= mem::size_of::()); +// No way to currently use any of these functions, since the thread creation syscall doesn't support them. +/* #[no_mangle] pub unsafe extern "C" fn pthread_attr_getprocessorid_np( attr: *const libc::pthread_attr_t, processor_id: *mut libc::c_int, ) -> libc::c_int { - let attr = attr as *mut PThreadAttr; + let attr = attr as *mut pthread_attr_t; (*processor_id) = (*attr).processor_id; 0 @@ -97,10 +21,11 @@ pub unsafe extern "C" fn pthread_attr_setprocessorid_np( attr: *mut libc::pthread_attr_t, processor_id: libc::c_int, ) -> libc::c_int { - let attr = attr as *mut PThreadAttr; + let attr = attr as *mut pthread_attr_t; (*attr).processor_id = processor_id; // TODO: we could validate the processor ID here if we wanted? 0 } +*/ \ No newline at end of file diff --git a/src/thread_keys.rs b/src/thread_keys.rs index 5486d4e..006adbe 100644 --- a/src/thread_keys.rs +++ b/src/thread_keys.rs @@ -20,7 +20,7 @@ fn is_valid_key(key: Key) -> bool { } #[no_mangle] -pub unsafe extern "C" fn pthread_key_create( +pub unsafe extern "C" fn __syscall_tls_create( key: *mut libc::pthread_key_t, destructor: Option, ) -> libc::c_int { @@ -33,7 +33,7 @@ pub unsafe extern "C" fn pthread_key_create( } #[no_mangle] -pub unsafe extern "C" fn pthread_key_delete(key: libc::pthread_key_t) -> libc::c_int { +pub unsafe extern "C" fn __syscall_tls_delete(key: libc::pthread_key_t) -> libc::c_int { match KEYS.write().remove(&(key as Key)) { // We had a entry, so it was a valid key. // It's officially undefined behavior if they use the key after this, @@ -46,7 +46,7 @@ pub unsafe extern "C" fn pthread_key_delete(key: libc::pthread_key_t) -> libc::c } #[no_mangle] -pub unsafe extern "C" fn pthread_getspecific(key: libc::pthread_key_t) -> *mut libc::c_void { +pub unsafe extern "C" fn __syscall_tls_get(key: libc::pthread_key_t) -> *mut libc::c_void { if let Some(&value) = LOCALS.get(&(key as Key)) { value as _ } else { @@ -56,7 +56,7 @@ pub unsafe extern "C" fn pthread_getspecific(key: libc::pthread_key_t) -> *mut l } #[no_mangle] -pub unsafe extern "C" fn pthread_setspecific( +pub unsafe extern "C" fn __syscall_tls_set( key: libc::pthread_key_t, value: *const libc::c_void, ) -> libc::c_int {