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]
1517pub 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]
2572pub 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]
48128pub 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]
56161pub 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
408515use spin:: rwlock:: RwLock ;
409516use std:: collections:: BTreeMap ;
410- use std:: ptr;
411517use std:: sync:: atomic:: { AtomicUsize , Ordering } ;
412518
413519type Key = usize ;
0 commit comments