1use crate::{
5 error::{Errno, Result},
6 header::{
7 errno,
8 time::{CLOCK_MONOTONIC, CLOCK_REALTIME, timespec, timespec_realtime_to_monotonic},
9 },
10 platform::{
11 Pal, Sys,
12 types::{c_uint, clockid_t},
13 },
14 sync::FutexAtomicTy,
15};
16
17use core::sync::atomic::{AtomicU32, Ordering};
18
19pub struct Semaphore {
20 count: AtomicU32,
21}
22
23impl Semaphore {
24 pub const fn new(value: c_uint) -> Self {
25 Self {
26 count: AtomicU32::new(value),
27 }
28 }
29
30 pub fn post(&self, count: c_uint) {
33 self.count.fetch_add(count, Ordering::SeqCst);
34 crate::sync::futex_wake(&self.count, i32::MAX);
36 }
37
38 pub fn try_wait(&self) -> bool {
39 loop {
40 let value = self.count.load(Ordering::SeqCst);
41
42 if value == 0 {
43 return false;
44 }
45
46 if self
47 .count
48 .compare_exchange_weak(value, value - 1, Ordering::SeqCst, Ordering::SeqCst)
49 .is_ok()
50 {
51 return true;
53 }
54 }
56 }
57
58 pub fn wait(&self, timeout_opt: Option<×pec>, clock_id: clockid_t) -> Result<()> {
59 loop {
60 if self.try_wait() {
61 return Ok(());
62 }
63 if let Some(timeout) = timeout_opt {
65 let relative = match clock_id {
66 CLOCK_MONOTONIC => timeout.clone(),
68 CLOCK_REALTIME => timespec_realtime_to_monotonic(timeout)?,
69 _ => return Err(Errno(errno::EINVAL)),
70 };
71 unsafe { Sys::futex_wait(self.count.ptr(), 0, Some(&relative))? };
72 } else {
73 unsafe { Sys::futex_wait(self.count.ptr(), 0, None)? };
75 }
76 }
77 }
78 pub fn value(&self) -> c_uint {
79 self.count.load(Ordering::SeqCst)
80 }
81}