1pub mod barrier;
4pub mod cond;
5pub mod mutex;
7
8pub mod once;
9pub mod pthread_mutex;
10pub mod rwlock;
11pub mod semaphore;
12pub mod waitval;
13
14pub use self::{
15 mutex::{Mutex, MutexGuard},
16 once::Once,
17 semaphore::Semaphore,
18};
19
20use crate::{
21 error::Errno,
22 header::{
23 errno::{EAGAIN, EINTR, ETIMEDOUT},
24 time::timespec,
25 },
26 out::Out,
27 platform::{Pal, Sys, types::c_int},
28};
29use core::{
30 hint,
31 mem::MaybeUninit,
32 ops::Deref,
33 ptr,
34 sync::atomic::{AtomicI32, AtomicI32 as AtomicInt, AtomicU32},
35};
36
37const FUTEX_WAIT: c_int = 0;
38const FUTEX_WAKE: c_int = 1;
39
40#[derive(Clone, Copy, PartialEq, Eq)]
41pub enum AttemptStatus {
42 Desired,
43 Waiting,
44 Other,
45}
46
47pub trait FutexTy {
48 fn conv(self) -> u32;
49}
50pub trait FutexAtomicTy {
51 type Ty: FutexTy;
52
53 fn ptr(&self) -> *mut Self::Ty;
54}
55impl FutexTy for u32 {
56 fn conv(self) -> u32 {
57 self
58 }
59}
60impl FutexTy for i32 {
61 fn conv(self) -> u32 {
62 self as u32
63 }
64}
65impl FutexAtomicTy for AtomicU32 {
66 type Ty = u32;
67
68 fn ptr(&self) -> *mut u32 {
69 ptr::from_ref::<AtomicU32>(self) as *mut u32
84 }
85}
86impl FutexAtomicTy for AtomicI32 {
87 type Ty = i32;
88
89 fn ptr(&self) -> *mut i32 {
90 ptr::from_ref::<AtomicI32>(self) as *mut i32
98 }
99}
100
101pub unsafe fn futex_wake_ptr(ptr: *mut impl FutexTy, n: i32) -> usize {
102 unsafe { Sys::futex_wake(ptr.cast(), n as u32) }.unwrap() as usize
104}
105pub unsafe fn futex_wait_ptr<T: FutexTy>(
106 ptr: *mut T,
107 value: T,
108 deadline_opt: Option<×pec>,
109) -> FutexWaitResult {
110 match unsafe { Sys::futex_wait(ptr.cast(), value.conv(), deadline_opt) } {
111 Ok(()) | Err(Errno(EINTR)) => FutexWaitResult::Waited,
112 Err(Errno(EAGAIN)) => FutexWaitResult::Stale,
113 Err(Errno(ETIMEDOUT)) if deadline_opt.is_some() => FutexWaitResult::TimedOut,
114 Err(err) => {
115 todo_error!(0, err, "futex failed");
116 FutexWaitResult::Waited
117 }
118 }
119}
120pub fn futex_wake(atomic: &impl FutexAtomicTy, n: i32) -> usize {
121 unsafe { futex_wake_ptr(atomic.ptr(), n) }
122}
123pub fn futex_wait<T: FutexAtomicTy>(
124 atomic: &T,
125 value: T::Ty,
126 deadline_opt: Option<×pec>,
127) -> FutexWaitResult {
128 unsafe { futex_wait_ptr(atomic.ptr(), value, deadline_opt) }
129}
130
131#[derive(Clone, Copy, Debug, Eq, PartialEq)]
132pub enum FutexWaitResult {
133 Waited, Stale, TimedOut,
136}
137
138pub fn rttime() -> timespec {
139 unsafe {
140 let mut time = MaybeUninit::uninit();
141
142 if let Ok(()) = Sys::clock_gettime(
143 crate::header::time::CLOCK_REALTIME,
144 Out::from_uninit_mut(&mut time),
145 ) {}; time.assume_init()
148 }
149}
150
151pub fn wait_until_generic<F1, F2>(word: &AtomicInt, attempt: F1, mark_long: F2, long: c_int)
152where
153 F1: Fn(&AtomicInt) -> AttemptStatus,
154 F2: Fn(&AtomicInt) -> AttemptStatus,
155{
156 for _ in 0..999 {
158 hint::spin_loop();
159 if attempt(word) == AttemptStatus::Desired {
160 return;
161 }
162 }
163
164 let mut previous = attempt(word);
166
167 loop {
170 if previous == AttemptStatus::Desired {
171 return;
172 }
173
174 if
175 previous == AttemptStatus::Waiting ||
178 mark_long(word) != AttemptStatus::Desired
181 {
182 futex_wait(word, long, None);
183 }
184
185 previous = attempt(word);
186 }
187}
188
189#[repr(C)]
192pub(crate) struct AtomicLock {
193 pub(crate) atomic: AtomicInt,
194}
195impl AtomicLock {
196 pub const fn new(value: c_int) -> Self {
197 Self {
198 atomic: AtomicInt::new(value),
199 }
200 }
201 pub fn notify_one(&self) {
202 futex_wake(&self.atomic, 1);
203 }
204 pub fn notify_all(&self) {
205 futex_wake(&self.atomic, i32::MAX);
206 }
207 pub fn wait_if(&self, value: c_int, timeout_opt: Option<×pec>) {
208 self.wait_if_raw(value, timeout_opt);
209 }
210 pub fn wait_if_raw(&self, value: c_int, timeout_opt: Option<×pec>) -> FutexWaitResult {
211 futex_wait(&self.atomic, value, timeout_opt)
212 }
213
214 pub fn wait_until<F1, F2>(&self, attempt: F1, mark_long: F2, long: c_int)
234 where
235 F1: Fn(&AtomicInt) -> AttemptStatus,
236 F2: Fn(&AtomicInt) -> AttemptStatus,
237 {
238 wait_until_generic(&self.atomic, attempt, mark_long, long)
239 }
240}
241impl Deref for AtomicLock {
242 type Target = AtomicInt;
243
244 fn deref(&self) -> &Self::Target {
245 &self.atomic
246 }
247}