Skip to main content

relibc/header/threads/
mod.rs

1//! `threads.h` implementation.
2//! Based on the musl implementation, with regard for our special implementation of pthread types
3//!
4//! See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/threads.h.html>.
5#![allow(non_camel_case_types)]
6#![allow(non_upper_case_globals)]
7use super::{
8    bits_limits_ptdi::PTHREAD_DESTRUCTOR_ITERATIONS,
9    bits_pthread::{self, pthread_cond_t, pthread_key_t, pthread_mutex_t, pthread_mutexattr_t},
10    errno::{EBUSY, EINTR, ENOMEM, ETIMEDOUT},
11    pthread::{
12        self, PTHREAD_MUTEX_NORMAL, PTHREAD_MUTEX_RECURSIVE, RlctCond, pthread_cond_broadcast,
13        pthread_cond_destroy, pthread_cond_signal, pthread_cond_timedwait, pthread_cond_wait,
14        pthread_create, pthread_detach, pthread_equal, pthread_exit, pthread_getspecific,
15        pthread_join, pthread_key_create, pthread_key_delete, pthread_mutex_destroy,
16        pthread_mutex_init, pthread_mutex_lock, pthread_mutex_timedlock, pthread_mutex_trylock,
17        pthread_mutex_unlock, pthread_mutexattr_init, pthread_mutexattr_settype, pthread_self,
18        pthread_setspecific,
19    },
20    sched::sched_yield,
21    time::{CLOCK_REALTIME, clock_nanosleep, timespec},
22};
23use crate::platform::{
24    ERRNO,
25    types::{c_int, c_long, c_void},
26};
27use core::mem::MaybeUninit;
28
29pub type thrd_t = bits_pthread::pthread_t;
30pub type once_flag = bits_pthread::pthread_once_t;
31pub type tss_t = bits_pthread::pthread_key_t;
32pub type mtx_t = bits_pthread::pthread_mutex_t;
33pub type cnd_t = bits_pthread::pthread_cond_t;
34
35pub type thrd_start_t = extern "C" fn(*mut c_void) -> c_int;
36pub type tss_dtor_t = Option<extern "C" fn(*mut c_void)>;
37
38pub const thrd_success: c_int = 0;
39pub const thrd_busy: c_int = 1;
40pub const thrd_error: c_int = 2;
41pub const thrd_nomem: c_int = 3;
42pub const thrd_timedout: c_int = 4;
43
44pub const mtx_plain: c_int = 0;
45pub const mtx_recursive: c_int = 1;
46pub const mtx_timed: c_int = 2;
47
48pub const TSS_DTOR_ITERATIONS: c_long = PTHREAD_DESTRUCTOR_ITERATIONS;
49
50/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/call_once.html>.
51#[unsafe(no_mangle)]
52pub unsafe extern "C" fn call_once(flag: *mut once_flag, func: extern "C" fn()) {
53    unsafe {
54        pthread::pthread_once(flag, func);
55    };
56}
57
58/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/cnd_broadcast.html>.
59#[unsafe(no_mangle)]
60pub unsafe extern "C" fn cnd_broadcast(cnd: *mut cnd_t) -> c_int {
61    if unsafe { pthread_cond_broadcast(cnd.cast::<pthread_cond_t>()) } == 0 {
62        thrd_success
63    } else {
64        thrd_error
65    }
66}
67
68/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/cnd_destroy.html>.
69#[unsafe(no_mangle)]
70pub unsafe extern "C" fn cnd_destroy(cnd: *mut cnd_t) {
71    unsafe { pthread_cond_destroy(cnd.cast::<pthread_cond_t>()) };
72}
73
74/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/cnd_init.html>.
75#[unsafe(no_mangle)]
76pub unsafe extern "C" fn cnd_init(cnd: *mut cnd_t) -> c_int {
77    unsafe {
78        cnd.cast::<RlctCond>().write(RlctCond::new());
79    }
80    thrd_success
81}
82
83/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/cnd_signal.html>.
84#[unsafe(no_mangle)]
85pub unsafe extern "C" fn cnd_signal(cnd: *mut cnd_t) -> c_int {
86    if unsafe { pthread_cond_signal(cnd.cast::<pthread_cond_t>()) } == 0 {
87        thrd_success
88    } else {
89        thrd_error
90    }
91}
92
93/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/cnd_timedwait.html>.
94#[unsafe(no_mangle)]
95pub unsafe extern "C" fn cnd_timedwait(
96    cnd: *mut cnd_t,
97    mtx: *mut mtx_t,
98    timeout: *const timespec,
99) -> c_int {
100    ERRNO.set(0);
101    let ret = unsafe {
102        pthread_cond_timedwait(
103            cnd.cast::<pthread_cond_t>(),
104            mtx.cast::<pthread_mutex_t>(),
105            timeout,
106        )
107    };
108    let new_errno = ERRNO.get();
109    match ret {
110        0 => thrd_success,
111        _ if new_errno == ETIMEDOUT => thrd_timedout,
112        _ => thrd_error,
113    }
114}
115
116/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/cnd_wait.html>.
117#[unsafe(no_mangle)]
118pub unsafe extern "C" fn cnd_wait(cnd: *mut cnd_t, mtx: *mut mtx_t) -> c_int {
119    if unsafe { pthread_cond_wait(cnd.cast::<pthread_cond_t>(), mtx.cast::<pthread_mutex_t>()) }
120        == 0
121    {
122        thrd_success
123    } else {
124        thrd_error
125    }
126}
127
128/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/mtx_destroy.html>.
129#[unsafe(no_mangle)]
130pub unsafe extern "C" fn mtx_destroy(mtx: *mut mtx_t) {
131    unsafe {
132        pthread_mutex_destroy(mtx.cast::<pthread_mutex_t>());
133    }
134}
135
136/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/mtx_init.html>.
137#[unsafe(no_mangle)]
138pub unsafe extern "C" fn mtx_init(mtx: *mut mtx_t, ty: c_int) -> c_int {
139    let mut attr = MaybeUninit::<pthread_mutexattr_t>::uninit();
140    unsafe {
141        pthread_mutexattr_init(attr.as_mut_ptr());
142    }
143    let mut attr = unsafe { attr.assume_init() };
144
145    let _ = unsafe {
146        pthread_mutexattr_settype(
147            &raw mut attr,
148            if ty & mtx_recursive == mtx_recursive {
149                PTHREAD_MUTEX_RECURSIVE
150            } else {
151                PTHREAD_MUTEX_NORMAL
152            },
153        )
154    };
155    if unsafe { pthread_mutex_init(mtx.cast::<pthread_mutex_t>(), &raw const attr) } == 0 {
156        thrd_success
157    } else {
158        thrd_error
159    }
160}
161
162/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/mtx_lock.html>.
163#[unsafe(no_mangle)]
164pub unsafe extern "C" fn mtx_lock(mtx: *mut mtx_t) -> c_int {
165    if unsafe { pthread_mutex_lock(mtx.cast::<pthread_mutex_t>()) } == 0 {
166        thrd_success
167    } else {
168        thrd_error
169    }
170}
171
172/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/mtx_timedlock.html>.
173#[unsafe(no_mangle)]
174pub unsafe extern "C" fn mtx_timedlock(mtx: *mut mtx_t, timeout: &timespec) -> c_int {
175    ERRNO.set(0);
176    let ret = unsafe { pthread_mutex_timedlock(mtx.cast::<pthread_mutex_t>(), timeout) };
177    let new_errno = ERRNO.get();
178    match ret {
179        0 => thrd_success,
180        _ if new_errno == ETIMEDOUT => thrd_timedout,
181        _ => thrd_error,
182    }
183}
184
185/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/mtx_trylock.html>.
186#[unsafe(no_mangle)]
187pub unsafe extern "C" fn mtx_trylock(mtx: *mut mtx_t) -> c_int {
188    ERRNO.set(0);
189    let ret = unsafe { pthread_mutex_trylock(mtx.cast::<pthread_mutex_t>()) };
190    let new_errno = ERRNO.get();
191    match ret {
192        0 => thrd_success,
193        _ if new_errno == EBUSY => thrd_busy,
194        _ => thrd_error,
195    }
196}
197
198/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/mtx_unlock.html>.
199#[unsafe(no_mangle)]
200pub unsafe extern "C" fn mtx_unlock(mtx: *mut mtx_t) -> c_int {
201    if unsafe { pthread_mutex_unlock(mtx.cast::<pthread_mutex_t>()) } == 0 {
202        thrd_success
203    } else {
204        thrd_error
205    }
206}
207
208/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/thrd_create.html>.
209#[unsafe(no_mangle)]
210pub unsafe extern "C" fn thrd_create(
211    thrd: *mut thrd_t,
212    start: thrd_start_t,
213    arg: *mut c_void,
214) -> c_int {
215    ERRNO.set(0);
216    let ret = unsafe {
217        pthread_create(
218            thrd,
219            core::ptr::null(),
220            #[expect(clippy::missing_transmute_annotations)] // too verbose
221            core::mem::transmute::<_, extern "C" fn(*mut c_void) -> *mut c_void>(start),
222            arg,
223        )
224    };
225    let new_errno = ERRNO.get();
226    match ret {
227        0 => thrd_success,
228        _ if new_errno == ENOMEM => thrd_nomem,
229        _ => thrd_error,
230    }
231}
232
233/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/thrd_current.html>.
234#[unsafe(no_mangle)]
235pub unsafe extern "C" fn thrd_current() -> thrd_t {
236    unsafe { pthread_self() }
237}
238
239/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/thrd_detach.html>.
240#[unsafe(no_mangle)]
241pub unsafe extern "C" fn thrd_detach(thrd: thrd_t) -> c_int {
242    if unsafe { pthread_detach(thrd) } == 0 {
243        thrd_success
244    } else {
245        thrd_error
246    }
247}
248
249/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/thrd_equal.html>.
250#[unsafe(no_mangle)]
251pub extern "C" fn thrd_equal(thrd1: thrd_t, thrd2: thrd_t) -> c_int {
252    pthread_equal(thrd1, thrd2)
253}
254
255/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/thrd_exit.html>.
256#[unsafe(no_mangle)]
257pub unsafe extern "C" fn thrd_exit(ret: c_int) -> ! {
258    unsafe { pthread_exit(ret as *mut c_void) }
259}
260
261/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/thrd_join.html>.
262#[unsafe(no_mangle)]
263pub unsafe extern "C" fn thrd_join(thrd: thrd_t, retval: *mut c_int) -> c_int {
264    if unsafe { pthread_join(thrd, retval.cast::<*mut c_void>()) } == 0 {
265        thrd_success
266    } else {
267        thrd_error
268    }
269}
270
271/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/thrd_sleep.html>.
272#[unsafe(no_mangle)]
273pub unsafe extern "C" fn thrd_sleep(time1: &timespec, time2: *mut timespec) -> c_int {
274    ERRNO.set(0);
275    let ret = clock_nanosleep(CLOCK_REALTIME, 0, time1, time2);
276    let new_errno = ERRNO.get();
277    match ret {
278        0 => 0,
279        -1 if new_errno == EINTR => -1,
280        _ => -2,
281    }
282}
283
284/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/thrd_yield.html>.
285#[unsafe(no_mangle)]
286pub unsafe extern "C" fn thrd_yield() {
287    sched_yield();
288}
289
290/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/tss_create.html>.
291#[unsafe(no_mangle)]
292pub unsafe extern "C" fn tss_create(tss: *mut tss_t, dtor: tss_dtor_t) -> c_int {
293    if unsafe { pthread_key_create(tss.cast::<pthread_key_t>(), dtor) } == 0 {
294        thrd_success
295    } else {
296        thrd_error
297    }
298}
299
300/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/tss_delete.html>.
301#[unsafe(no_mangle)]
302pub unsafe extern "C" fn tss_delete(tss: tss_t) {
303    // note: tss_t is a transparent type alias to pthread_key_t
304    unsafe {
305        pthread_key_delete(tss);
306    }
307}
308
309/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/tss_get.html>.
310#[unsafe(no_mangle)]
311pub unsafe extern "C" fn tss_get(tss: tss_t) -> *mut c_void {
312    // note: tss_t is a transparent type alias to pthread_key_t
313    unsafe { pthread_getspecific(tss) }
314}
315
316/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/tss_set.html>.
317#[unsafe(no_mangle)]
318pub unsafe extern "C" fn tss_set(tss: tss_t, value: *mut c_void) -> c_int {
319    // note: tss_t is a transparent type alias to pthread_key_t
320    if unsafe { pthread_setspecific(tss, value) } == 0 {
321        thrd_success
322    } else {
323        thrd_error
324    }
325}