1use core::cell::UnsafeCell;
2use core::mem;
3use core::convert::TryFrom;
4
5use error_code::PosixError;
6
7pub struct Sem {
11 handle: UnsafeCell<libc::sem_t>,
12}
13
14impl super::Semaphore for Sem {
15 fn new(init: u32) -> Option<Self> {
16 let mut handle = mem::MaybeUninit::uninit();
17
18 let res = unsafe {
19 libc::sem_init(handle.as_mut_ptr(), 0, init as libc::c_uint)
20 };
21
22 match res {
23 0 => Some(Self {
24 handle: UnsafeCell::new(unsafe {
25 handle.assume_init()
26 })
27 }),
28 _ => None,
29 }
30 }
31
32 fn wait(&self) {
33 loop {
34 let res = unsafe {
35 libc::sem_wait(self.handle.get())
36 };
37
38 if res == -1 {
39 let errno = PosixError::last();
40 debug_assert_eq!(errno.raw_code(), libc::EINTR, "Unexpected error");
41 continue;
42 }
43
44 break
45 }
46 }
47
48 fn try_wait(&self) -> bool {
49 loop {
50 let res = unsafe {
51 libc::sem_trywait(self.handle.get())
52 };
53
54 if res == -1 {
55 let errno = PosixError::last();
56 if errno.is_would_block() {
57 break false;
58 }
59
60 debug_assert_eq!(errno.raw_code(), libc::EINTR, "Unexpected error");
61 continue;
62 }
63
64 break true
65 }
66 }
67
68 fn wait_timeout(&self, timeout: core::time::Duration) -> bool {
69 let timeout = libc::timespec {
70 tv_sec: timeout.as_secs() as libc::time_t,
71 #[cfg(target_pointer_width = "64")]
72 tv_nsec: libc::suseconds_t::from(timeout.subsec_nanos()),
73 #[cfg(not(target_pointer_width = "64"))]
74 tv_nsec: libc::suseconds_t::try_from(timeout.subsec_nanos()).unwrap_or(libc::suseconds_t::max_value()),
75 };
76
77 loop {
78 let res = unsafe {
79 libc::sem_timedwait(self.handle.get(), &timeout)
80 };
81
82 if res == -1 {
83 let errno = PosixError::last();
84 if errno.is_would_block() || errno.raw_code() == libc::ETIMEDOUT {
85 break false;
86 }
87
88 debug_assert_eq!(errno.raw_code(), libc::EINTR, "Unexpected error");
89 continue;
90 }
91
92 break true
93 }
94 }
95
96 fn signal(&self) {
97 let res = unsafe {
98 libc::sem_post(self.handle.get())
99 };
100 debug_assert_eq!(res, 0);
101 }
102
103 fn post(&self) -> bool {
104 let mut val = 0;
105 unsafe {
106 libc::sem_getvalue(self.handle.get(), &mut val);
107 }
108
109 self.signal();
110
111 val == 0
112 }
113}
114
115impl Drop for Sem {
116 fn drop(&mut self) {
117 unsafe {
118 libc::sem_destroy(self.handle.get());
119 }
120 }
121}
122
123unsafe impl Send for Sem {}
124unsafe impl Sync for Sem {}