Browse Source

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.
pull/9/head
AzureMarker 3 years ago
parent
commit
db26a42401
No known key found for this signature in database
GPG Key ID: 47A133F3BF9D03D3
  1. 3
      Cargo.toml
  2. 102
      src/lib.rs

3
Cargo.toml

@ -8,4 +8,5 @@ edition = "2021"
[dependencies] [dependencies]
libc = "0.2.116" libc = "0.2.116"
ctru-sys = { git = "https://github.com/Meziu/ctru-rs.git" } ctru-sys = { git = "https://github.com/Meziu/ctru-rs.git" }
spin = { version = "0.9", default-features = false, features = ["rwlock", "std"] } spin = { version = "0.9", default-features = false, features = ["rwlock", "std"] }
static_assertions = "1.0"

102
src/lib.rs

@ -3,6 +3,8 @@
#![allow(non_camel_case_types)] #![allow(non_camel_case_types)]
#![allow(clippy::missing_safety_doc)] #![allow(clippy::missing_safety_doc)]
use std::ptr;
/// Call this somewhere to force Rust to link this module. /// Call this somewhere to force Rust to link this module.
/// The call doesn't need to execute, just exist. /// The call doesn't need to execute, just exist.
/// ///
@ -15,27 +17,50 @@ pub fn init() {}
pub unsafe extern "C" fn pthread_create( pub unsafe extern "C" fn pthread_create(
native: *mut libc::pthread_t, native: *mut libc::pthread_t,
attr: *const libc::pthread_attr_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, value: *mut libc::c_void,
) -> libc::c_int { ) -> libc::c_int {
let mut priority = 0; let attr = attr as *const PThreadAttr;
ctru_sys::svcGetThreadPriority(&mut priority, 0xFFFF8000);
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) { extern "C" fn thread_start(main: *mut libc::c_void) {
unsafe { unsafe {
Box::from_raw(main as *mut Box<dyn FnOnce()>)(); Box::from_raw(main as *mut Box<dyn FnOnce() -> *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<dyn FnOnce() -> *mut libc::c_void> =
Box::into_raw(Box::new(Box::new(move || entrypoint(value))));
let handle = ctru_sys::threadCreate( let handle = ctru_sys::threadCreate(
Some(thread_start), Some(thread_start),
value, main as *mut libc::c_void,
*(attr as *mut ctru_sys::size_t), stack_size,
priority, priority,
-2, affinity,
false, 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 _; *native = handle as _;
0 0
@ -46,7 +71,7 @@ pub unsafe extern "C" fn pthread_join(
native: libc::pthread_t, native: libc::pthread_t,
_value: *mut *mut libc::c_void, _value: *mut *mut libc::c_void,
) -> libc::c_int { ) -> 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); ctru_sys::threadFree(native as ctru_sys::Thread);
0 0
@ -54,18 +79,46 @@ pub unsafe extern "C" fn pthread_join(
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn pthread_detach(thread: libc::pthread_t) -> libc::c_int { 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 0
} }
#[no_mangle] #[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<libc::size_t>,
priority: Option<libc::c_int>,
affinity: Option<libc::c_int>,
}
static_assertions::const_assert!(
std::mem::size_of::<PThreadAttr>() <= std::mem::size_of::<libc::pthread_attr_t>()
);
#[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 0
} }
#[no_mangle] #[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 0
} }
@ -74,8 +127,30 @@ pub unsafe extern "C" fn pthread_attr_setstacksize(
attr: *mut libc::pthread_attr_t, attr: *mut libc::pthread_attr_t,
stack_size: libc::size_t, stack_size: libc::size_t,
) -> libc::c_int { ) -> libc::c_int {
let pointer = attr as *mut libc::size_t; let attr = attr as *mut PThreadAttr;
*pointer = stack_size; (*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 0
} }
@ -428,7 +503,6 @@ pub unsafe extern "C" fn pthread_rwlockattr_destroy(
use spin::rwlock::RwLock; use spin::rwlock::RwLock;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::ptr;
use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::atomic::{AtomicUsize, Ordering};
type Key = usize; type Key = usize;

Loading…
Cancel
Save