Skip to main content

relibc/sync/
waitval.rs

1use core::{
2    cell::UnsafeCell,
3    mem::MaybeUninit,
4    sync::atomic::{AtomicU32 as AtomicUint, Ordering},
5};
6
7/// An unsafe "one thread to one thread" synchronization primitive. Used for and modeled after
8/// pthread_join only, at the moment.
9#[derive(Debug)]
10pub struct Waitval<T> {
11    state: AtomicUint,
12    value: UnsafeCell<MaybeUninit<T>>,
13}
14
15unsafe impl<T: Send + Sync> Send for Waitval<T> {}
16unsafe impl<T: Send + Sync> Sync for Waitval<T> {}
17
18impl<T> Waitval<T> {
19    #[allow(clippy::new_without_default)]
20    pub const fn new() -> Self {
21        Self {
22            state: AtomicUint::new(0),
23            value: UnsafeCell::new(MaybeUninit::uninit()),
24        }
25    }
26
27    // SAFETY: Caller must ensure both (1) that the value has not yet been initialized, and (2)
28    // that this is never run by more than one thread simultaneously.
29    pub unsafe fn post(&self, value: T) {
30        unsafe { self.value.get().write(MaybeUninit::new(value)) };
31        self.state.store(1, Ordering::Release);
32        crate::sync::futex_wake(&self.state, i32::MAX);
33    }
34
35    pub fn wait(&self) -> &T {
36        while self.state.load(Ordering::Acquire) == 0 {
37            crate::sync::futex_wait(&self.state, 0, None);
38        }
39
40        unsafe { (*self.value.get()).assume_init_ref() }
41    }
42}