Skip to content

Commit b3498da

Browse files
authored
Merge pull request #9 from Meziu/feature/pthread-threads
Add back threading support and implement extensions
2 parents 9fb7872 + 1704505 commit b3498da

2 files changed

Lines changed: 126 additions & 19 deletions

File tree

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ edition = "2021"
88
[dependencies]
99
libc = "0.2.116"
1010
ctru-sys = { git = "https://github.com/Meziu/ctru-rs.git" }
11-
spin = { version = "0.9", default-features = false, features = ["rwlock", "std"] }
11+
spin = { version = "0.9", default-features = false, features = ["rwlock", "std"] }
12+
static_assertions = "1.0"

src/lib.rs

Lines changed: 124 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
#![allow(non_camel_case_types)]
44
#![allow(clippy::missing_safety_doc)]
55

6+
use std::ptr;
7+
68
/// Call this somewhere to force Rust to link this module.
79
/// The call doesn't need to execute, just exist.
810
///
@@ -13,48 +15,153 @@ pub fn init() {}
1315

1416
#[no_mangle]
1517
pub unsafe extern "C" fn pthread_create(
16-
_native: *mut libc::pthread_t,
17-
_attr: *const libc::pthread_attr_t,
18-
_f: extern "C" fn(_: *mut libc::c_void) -> *mut libc::c_void,
19-
_value: *mut libc::c_void,
18+
native: *mut libc::pthread_t,
19+
attr: *const libc::pthread_attr_t,
20+
entrypoint: extern "C" fn(_: *mut libc::c_void) -> *mut libc::c_void,
21+
value: *mut libc::c_void,
2022
) -> libc::c_int {
21-
1
23+
let attr = attr as *const PThreadAttr;
24+
25+
let stack_size = (*attr).stack_size.unwrap_or(libc::PTHREAD_STACK_MIN) as ctru_sys::size_t;
26+
27+
// If no priority value is specified, spawn with the same
28+
// priority as the parent thread
29+
let priority = (*attr).priority.unwrap_or_else(|| pthread_getpriority());
30+
31+
// If no affinity is specified, spawn on the default core (determined by
32+
// the application's Exheader)
33+
let affinity = (*attr).affinity.unwrap_or(-2);
34+
35+
extern "C" fn thread_start(main: *mut libc::c_void) {
36+
unsafe {
37+
Box::from_raw(main as *mut Box<dyn FnOnce() -> *mut libc::c_void>)();
38+
}
39+
}
40+
41+
// The closure needs a fat pointer (64 bits) to work since it captures a variable and is thus a
42+
// trait object, but *mut void is only 32 bits. We need double indirection to pass along the
43+
// full closure data.
44+
// We make this closure in the first place because threadCreate expects a void return type, but
45+
// entrypoint returns a pointer so the types are incompatible.
46+
let main: *mut Box<dyn FnOnce() -> *mut libc::c_void> =
47+
Box::into_raw(Box::new(Box::new(move || entrypoint(value))));
48+
49+
let handle = ctru_sys::threadCreate(
50+
Some(thread_start),
51+
main as *mut libc::c_void,
52+
stack_size,
53+
priority,
54+
affinity,
55+
false,
56+
);
57+
58+
if handle.is_null() {
59+
// There was some error, but libctru doesn't expose the result.
60+
// We assume there was an incorrect parameter (such as too low of a priority).
61+
// We also need to clean up the closure at this time.
62+
drop(Box::from_raw(main));
63+
return libc::EINVAL;
64+
}
65+
66+
*native = handle as _;
67+
68+
0
2269
}
2370

2471
#[no_mangle]
2572
pub unsafe extern "C" fn pthread_join(
26-
_native: libc::pthread_t,
73+
native: libc::pthread_t,
2774
_value: *mut *mut libc::c_void,
2875
) -> libc::c_int {
29-
1
76+
ctru_sys::threadJoin(native as ctru_sys::Thread, u64::MAX);
77+
ctru_sys::threadFree(native as ctru_sys::Thread);
78+
79+
0
3080
}
3181

3282
#[no_mangle]
33-
pub unsafe extern "C" fn pthread_detach(_thread: libc::pthread_t) -> libc::c_int {
34-
1
83+
pub unsafe extern "C" fn pthread_detach(thread: libc::pthread_t) -> libc::c_int {
84+
ctru_sys::threadDetach(thread as ctru_sys::Thread);
85+
86+
0
3587
}
3688

3789
#[no_mangle]
38-
pub unsafe extern "C" fn pthread_attr_init(_attr: *mut libc::pthread_attr_t) -> libc::c_int {
39-
1
90+
pub unsafe extern "C" fn pthread_getpriority() -> libc::c_int {
91+
let mut priority = 0;
92+
ctru_sys::svcGetThreadPriority(&mut priority, ctru_sys::CUR_THREAD_HANDLE);
93+
priority
4094
}
4195

96+
/// Internal struct for storing pthread attribute data
97+
/// Must be less than or equal to the size of `libc::pthread_attr_t`. We assert
98+
/// this below via static_assertions.
99+
struct PThreadAttr {
100+
stack_size: Option<libc::size_t>,
101+
priority: Option<libc::c_int>,
102+
affinity: Option<libc::c_int>,
103+
}
104+
105+
static_assertions::const_assert!(
106+
std::mem::size_of::<PThreadAttr>() <= std::mem::size_of::<libc::pthread_attr_t>()
107+
);
108+
42109
#[no_mangle]
43-
pub unsafe extern "C" fn pthread_attr_destroy(_attr: *mut libc::pthread_attr_t) -> libc::c_int {
44-
1
110+
pub unsafe extern "C" fn pthread_attr_init(attr: *mut libc::pthread_attr_t) -> libc::c_int {
111+
let attr = attr as *mut PThreadAttr;
112+
*attr = PThreadAttr {
113+
stack_size: None,
114+
priority: None,
115+
affinity: None,
116+
};
117+
118+
0
119+
}
120+
121+
#[no_mangle]
122+
pub unsafe extern "C" fn pthread_attr_destroy(attr: *mut libc::pthread_attr_t) -> libc::c_int {
123+
ptr::drop_in_place(attr as *mut PThreadAttr);
124+
0
45125
}
46126

47127
#[no_mangle]
48128
pub unsafe extern "C" fn pthread_attr_setstacksize(
49-
_attr: *mut libc::pthread_attr_t,
50-
_stack_size: libc::size_t,
129+
attr: *mut libc::pthread_attr_t,
130+
stack_size: libc::size_t,
131+
) -> libc::c_int {
132+
let attr = attr as *mut PThreadAttr;
133+
(*attr).stack_size = Some(stack_size);
134+
135+
0
136+
}
137+
138+
#[no_mangle]
139+
pub unsafe extern "C" fn pthread_attr_setpriority(
140+
attr: *mut libc::pthread_attr_t,
141+
priority: libc::c_int,
51142
) -> libc::c_int {
52-
1
143+
let attr = attr as *mut PThreadAttr;
144+
(*attr).priority = Some(priority);
145+
146+
0
147+
}
148+
149+
#[no_mangle]
150+
pub unsafe extern "C" fn pthread_attr_setaffinity(
151+
attr: *mut libc::pthread_attr_t,
152+
affinity: libc::c_int,
153+
) -> libc::c_int {
154+
let attr = attr as *mut PThreadAttr;
155+
(*attr).affinity = Some(affinity);
156+
157+
0
53158
}
54159

55160
#[no_mangle]
56161
pub unsafe extern "C" fn sched_yield() -> libc::c_int {
57-
1
162+
ctru_sys::svcSleepThread(0);
163+
164+
0
58165
}
59166

60167
#[no_mangle]
@@ -407,7 +514,6 @@ pub unsafe extern "C" fn pthread_sigmask(
407514

408515
use spin::rwlock::RwLock;
409516
use std::collections::BTreeMap;
410-
use std::ptr;
411517
use std::sync::atomic::{AtomicUsize, Ordering};
412518

413519
type Key = usize;

0 commit comments

Comments
 (0)