From c82ce62c9be0fdc86a4998fa03549a36915edb4e Mon Sep 17 00:00:00 2001 From: AzureMarker Date: Sun, 6 Feb 2022 20:14:34 -0800 Subject: [PATCH 1/3] Add back basic pthread threading support Had to fix a few compile errors since we switched to using ctru_sys directly. This is also just the basic support that was there before. More work needs to be done to support std. --- src/lib.rs | 58 +++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 14 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 16dc8b3..a19c3de 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,48 +13,78 @@ pub fn init() {} #[no_mangle] pub unsafe extern "C" fn pthread_create( - _native: *mut libc::pthread_t, - _attr: *const libc::pthread_attr_t, + native: *mut libc::pthread_t, + attr: *const libc::pthread_attr_t, _f: extern "C" fn(_: *mut libc::c_void) -> *mut libc::c_void, - _value: *mut libc::c_void, + value: *mut libc::c_void, ) -> libc::c_int { - 1 + let mut priority = 0; + ctru_sys::svcGetThreadPriority(&mut priority, 0xFFFF8000); + + extern "C" fn thread_start(main: *mut libc::c_void) { + unsafe { + Box::from_raw(main as *mut Box)(); + } + } + + let handle = ctru_sys::threadCreate( + Some(thread_start), + value, + *(attr as *mut ctru_sys::size_t), + priority, + -2, + false, + ); + + *native = handle as _; + + 0 } #[no_mangle] pub unsafe extern "C" fn pthread_join( - _native: libc::pthread_t, + native: libc::pthread_t, _value: *mut *mut libc::c_void, ) -> libc::c_int { - 1 + ctru_sys::threadJoin(native as ctru_sys::Thread, u64::max_value()); + ctru_sys::threadFree(native as ctru_sys::Thread); + + 0 } #[no_mangle] -pub unsafe extern "C" fn pthread_detach(_thread: libc::pthread_t) -> libc::c_int { - 1 +pub unsafe extern "C" fn pthread_detach(thread: libc::pthread_t) -> libc::c_int { + ctru_sys::threadDetach(thread as _); + + 0 } #[no_mangle] pub unsafe extern "C" fn pthread_attr_init(_attr: *mut libc::pthread_attr_t) -> libc::c_int { - 1 + 0 } #[no_mangle] pub unsafe extern "C" fn pthread_attr_destroy(_attr: *mut libc::pthread_attr_t) -> libc::c_int { - 1 + 0 } #[no_mangle] pub unsafe extern "C" fn pthread_attr_setstacksize( - _attr: *mut libc::pthread_attr_t, - _stack_size: libc::size_t, + attr: *mut libc::pthread_attr_t, + stack_size: libc::size_t, ) -> libc::c_int { - 1 + let pointer = attr as *mut libc::size_t; + *pointer = stack_size; + + 0 } #[no_mangle] pub unsafe extern "C" fn sched_yield() -> libc::c_int { - 1 + ctru_sys::svcSleepThread(0); + + 0 } #[no_mangle] From db26a42401992b87f13e10924906bd039d698e10 Mon Sep 17 00:00:00 2001 From: AzureMarker Date: Wed, 9 Feb 2022 21:29:47 -0800 Subject: [PATCH 2/3] Implement pthread extensions and improve pthread_create pthread_create wasn't actually calling the entrypoint it was given, which was incorrect. It also didn't handle errors. --- Cargo.toml | 3 +- src/lib.rs | 102 +++++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 90 insertions(+), 15 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 31c8006..7df95aa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,4 +8,5 @@ edition = "2021" [dependencies] libc = "0.2.116" ctru-sys = { git = "https://github.com/Meziu/ctru-rs.git" } -spin = { version = "0.9", default-features = false, features = ["rwlock", "std"] } \ No newline at end of file +spin = { version = "0.9", default-features = false, features = ["rwlock", "std"] } +static_assertions = "1.0" \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index a19c3de..e7a8a77 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,8 @@ #![allow(non_camel_case_types)] #![allow(clippy::missing_safety_doc)] +use std::ptr; + /// Call this somewhere to force Rust to link this module. /// The call doesn't need to execute, just exist. /// @@ -15,27 +17,50 @@ pub fn init() {} pub unsafe extern "C" fn pthread_create( native: *mut libc::pthread_t, attr: *const libc::pthread_attr_t, - _f: extern "C" fn(_: *mut libc::c_void) -> *mut libc::c_void, + entrypoint: extern "C" fn(_: *mut libc::c_void) -> *mut libc::c_void, value: *mut libc::c_void, ) -> libc::c_int { - let mut priority = 0; - ctru_sys::svcGetThreadPriority(&mut priority, 0xFFFF8000); + let attr = attr as *const PThreadAttr; + + let stack_size = (*attr).stack_size.unwrap_or(libc::PTHREAD_STACK_MIN) as ctru_sys::size_t; + + // If no priority value is specified, spawn with the same + // priority as the parent thread + let priority = (*attr).priority.unwrap_or_else(|| pthread_getpriority()); + + // If no affinity is specified, spawn on the default core (determined by + // the application's Exheader) + let affinity = (*attr).affinity.unwrap_or(-2); extern "C" fn thread_start(main: *mut libc::c_void) { unsafe { - Box::from_raw(main as *mut Box)(); + Box::from_raw(main as *mut Box *mut libc::c_void>)(); } } + // The closure needs a fat pointer (64 bits) to work since it captures a variable and is thus a + // trait object, but *mut void is only 32 bits. We need double indirection to pass along the + // full closure data. + // We make this closure in the first place because threadCreate expects a void return type, but + // entrypoint returns a pointer so the types are incompatible. + let main: *mut Box *mut libc::c_void> = + Box::into_raw(Box::new(Box::new(move || entrypoint(value)))); + let handle = ctru_sys::threadCreate( Some(thread_start), - value, - *(attr as *mut ctru_sys::size_t), + main as *mut libc::c_void, + stack_size, priority, - -2, + affinity, false, ); + if handle.is_null() { + // There was some error, but libctru doesn't expose the result. + // We assume there was an incorrect parameter (such as too low of a priority). + return libc::EINVAL; + } + *native = handle as _; 0 @@ -46,7 +71,7 @@ pub unsafe extern "C" fn pthread_join( native: libc::pthread_t, _value: *mut *mut libc::c_void, ) -> libc::c_int { - ctru_sys::threadJoin(native as ctru_sys::Thread, u64::max_value()); + ctru_sys::threadJoin(native as ctru_sys::Thread, u64::MAX); ctru_sys::threadFree(native as ctru_sys::Thread); 0 @@ -54,18 +79,46 @@ pub unsafe extern "C" fn pthread_join( #[no_mangle] pub unsafe extern "C" fn pthread_detach(thread: libc::pthread_t) -> libc::c_int { - ctru_sys::threadDetach(thread as _); + ctru_sys::threadDetach(thread as ctru_sys::Thread); 0 } #[no_mangle] -pub unsafe extern "C" fn pthread_attr_init(_attr: *mut libc::pthread_attr_t) -> libc::c_int { +pub unsafe extern "C" fn pthread_getpriority() -> libc::c_int { + let mut priority = 0; + ctru_sys::svcGetThreadPriority(&mut priority, ctru_sys::CUR_THREAD_HANDLE); + priority +} + +/// 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. +struct PThreadAttr { + stack_size: Option, + priority: Option, + affinity: Option, +} + +static_assertions::const_assert!( + std::mem::size_of::() <= std::mem::size_of::() +); + +#[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 { + stack_size: None, + priority: None, + affinity: None, + }; + 0 } #[no_mangle] -pub unsafe extern "C" fn pthread_attr_destroy(_attr: *mut libc::pthread_attr_t) -> libc::c_int { +pub unsafe extern "C" fn pthread_attr_destroy(attr: *mut libc::pthread_attr_t) -> libc::c_int { + ptr::drop_in_place(attr as *mut PThreadAttr); 0 } @@ -74,8 +127,30 @@ pub unsafe extern "C" fn pthread_attr_setstacksize( attr: *mut libc::pthread_attr_t, stack_size: libc::size_t, ) -> libc::c_int { - let pointer = attr as *mut libc::size_t; - *pointer = stack_size; + let attr = attr as *mut PThreadAttr; + (*attr).stack_size = Some(stack_size); + + 0 +} + +#[no_mangle] +pub unsafe extern "C" fn pthread_attr_setpriority( + attr: *mut libc::pthread_attr_t, + priority: libc::c_int, +) -> libc::c_int { + let attr = attr as *mut PThreadAttr; + (*attr).priority = Some(priority); + + 0 +} + +#[no_mangle] +pub unsafe extern "C" fn pthread_attr_setaffinity( + attr: *mut libc::pthread_attr_t, + affinity: libc::c_int, +) -> libc::c_int { + let attr = attr as *mut PThreadAttr; + (*attr).affinity = Some(affinity); 0 } @@ -428,7 +503,6 @@ pub unsafe extern "C" fn pthread_rwlockattr_destroy( use spin::rwlock::RwLock; use std::collections::BTreeMap; -use std::ptr; use std::sync::atomic::{AtomicUsize, Ordering}; type Key = usize; From 17045056143d33fd05f53e97d323f9fefd584429 Mon Sep 17 00:00:00 2001 From: AzureMarker Date: Wed, 9 Feb 2022 21:36:14 -0800 Subject: [PATCH 3/3] Deallocate the closure if thread spawning failed --- src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index e7a8a77..768ff76 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -58,6 +58,8 @@ pub unsafe extern "C" fn pthread_create( if handle.is_null() { // There was some error, but libctru doesn't expose the result. // We assume there was an incorrect parameter (such as too low of a priority). + // We also need to clean up the closure at this time. + drop(Box::from_raw(main)); return libc::EINVAL; }