blob: 29b3181992b1163b396a0d24c4c00017c49c7c16 [file] [log] [blame]
#![allow(unused)]
use std::ffi::c_void;
use libc::{self, pthread_attr_t, pthread_t};
/// Spawn a thread using `pthread_create`, abort the process on any errors.
pub unsafe fn spawn_pthread(
f: extern "C" fn(*mut c_void) -> *mut c_void,
value: *mut c_void,
) -> pthread_t {
let mut thread_id: pthread_t = 0;
let attr: *const pthread_attr_t = std::ptr::null();
if unsafe { libc::pthread_create(&raw mut thread_id, attr, f, value) } != 0 {
std::process::abort();
}
thread_id
}
/// Unsafe because we do *not* check that `F` is `Send + 'static`.
/// That makes it much easier to write tests...
pub unsafe fn spawn_pthread_closure<F: FnOnce()>(f: F) -> pthread_t {
let mut thread_id: pthread_t = 0;
let attr: *const pthread_attr_t = std::ptr::null();
let f = Box::new(f);
extern "C" fn thread_func<F: FnOnce()>(f: *mut c_void) -> *mut c_void {
let f = unsafe { Box::from_raw(f as *mut F) };
f();
std::ptr::null_mut()
}
if unsafe {
libc::pthread_create(
&raw mut thread_id,
attr,
thread_func::<F>,
Box::into_raw(f) as *mut c_void,
)
} != 0
{
std::process::abort();
}
thread_id
}
// Join the given pthread, abort the process on any errors.
pub unsafe fn join_pthread(thread_id: pthread_t) {
if unsafe { libc::pthread_join(thread_id, std::ptr::null_mut()) } != 0 {
std::process::abort();
}
}
/// Spawn `N` threads using `pthread_create` without any arguments, abort the process on any errors.
pub unsafe fn spawn_pthreads_no_params<const N: usize>(
functions: [extern "C" fn(*mut c_void) -> *mut c_void; N],
) -> [pthread_t; N] {
functions.map(|func| spawn_pthread(func, std::ptr::null_mut()))
}
// Join the `N` given pthreads, abort the process on any errors.
pub unsafe fn join_pthreads<const N: usize>(thread_ids: [pthread_t; N]) {
let _ = thread_ids.map(|id| join_pthread(id));
}