1use core::ptr;
2use core::ffi::c_void;
3use core::sync::atomic::{AtomicPtr, Ordering};
4
5use crate::unlikely;
6
7const WAIT_OBJECT_0: u32 = 0;
8const WAIT_TIMEOUT: u32 = 0x00000102;
9const INFINITE: u32 = 0xFFFFFFFF;
10
11extern "system" {
12 fn CloseHandle(handle: *mut c_void) -> i32;
13 fn CreateSemaphoreW(attrs: *mut c_void, initial: i32, max: i32, name: *const u16) -> *mut c_void;
14 fn WaitForSingleObject(handle: *mut c_void, timeout_ms: u32) -> u32;
15 fn ReleaseSemaphore(handle: *mut c_void, increment: i32, previous_increment: *mut i32) -> i32;
16}
17
18pub struct Sem {
20 handle: AtomicPtr<c_void>
21}
22
23impl Sem {
24 pub const unsafe fn new_uninit() -> Self {
28 Self {
29 handle: AtomicPtr::new(ptr::null_mut())
30 }
31 }
32
33 #[inline(always)]
34 pub fn is_init(&self) -> bool {
36 !self.handle.load(Ordering::Acquire).is_null()
37 }
38
39 #[must_use]
40 pub fn init(&self, init: u32) -> bool {
46 if !self.handle.load(Ordering::Acquire).is_null() {
47 return false;
49 } else {
50 let handle = unsafe {
51 CreateSemaphoreW(ptr::null_mut(), init as i32, i32::max_value(), ptr::null())
52 };
53
54 let res = match self.handle.compare_exchange(ptr::null_mut(), handle, Ordering::SeqCst, Ordering::Acquire) {
55 Ok(_) => !handle.is_null(),
56 Err(_) => {
57 unsafe {
58 CloseHandle(handle);
59 }
60 unlikely(false)
61 }
62 };
63
64 unlikely(res)
65 }
66 }
67
68 pub fn new(init: u32) -> Option<Self> {
70 let result = unsafe {
71 Self::new_uninit()
72 };
73
74 if result.init(init) {
75 Some(result)
76 } else {
77 unlikely(None)
78 }
79 }
80
81 pub fn wait(&self) {
85 let result = unsafe {
86 WaitForSingleObject(self.handle.load(Ordering::Acquire), INFINITE)
87 };
88
89 match result {
90 WAIT_OBJECT_0 => (),
91 other => panic!("Unexpected result: {}", other),
93 }
94 }
95
96 #[inline]
97 pub fn try_wait(&self) -> bool {
103 self.wait_timeout(core::time::Duration::from_secs(0))
104 }
105
106 pub fn wait_timeout(&self, timeout: core::time::Duration) -> bool {
112 use core::convert::TryInto;
113
114 let result = unsafe {
115 WaitForSingleObject(self.handle.load(Ordering::Acquire), timeout.as_millis().try_into().unwrap_or(u32::max_value()))
116 };
117
118 match result {
119 WAIT_OBJECT_0 => true,
120 WAIT_TIMEOUT => false,
121 other => panic!("Unexpected result: {}", other),
122 }
123 }
124
125 pub fn signal(&self) {
127 let res = unsafe {
128 ReleaseSemaphore(self.handle.load(Ordering::Acquire), 1, ptr::null_mut())
129 };
130 debug_assert_ne!(res, 0);
131 }
132
133
134 pub unsafe fn close(&self) {
138 let handle = self.handle.swap(ptr::null_mut(), Ordering::AcqRel);
139 if !handle.is_null() {
140 CloseHandle(handle);
141 }
142 }
143}
144
145impl Drop for Sem {
146 fn drop(&mut self) {
147 unsafe {
148 self.close();
149 }
150 }
151}
152
153unsafe impl Send for Sem {}
154unsafe impl Sync for Sem {}