semka/
win32.rs

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
18///Windows implementation of Semaphore
19pub struct Sem {
20    handle: AtomicPtr<c_void>
21}
22
23impl Sem {
24    ///Creates new uninit instance.
25    ///
26    ///It is UB to use it until `init` is called.
27    pub const unsafe fn new_uninit() -> Self {
28        Self {
29            handle: AtomicPtr::new(ptr::null_mut())
30        }
31    }
32
33    #[inline(always)]
34    ///Returns whether semaphore is successfully initialized
35    pub fn is_init(&self) -> bool {
36        !self.handle.load(Ordering::Acquire).is_null()
37    }
38
39    #[must_use]
40    ///Initializes semaphore with provided `init` as initial value.
41    ///
42    ///Returns `true` on success.
43    ///
44    ///Returns `false` if semaphore is already initialized or initialization failed.
45    pub fn init(&self, init: u32) -> bool {
46        if !self.handle.load(Ordering::Acquire).is_null() {
47            //Similarly to `Once` we give priority to already-init path
48            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    ///Creates new instance, initializing it with `init`
69    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    ///Decrements self, returning immediately if it was signaled.
82    ///
83    ///Otherwise awaits for signal.
84    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            //We cannot really timeout when there is no timeout
92            other => panic!("Unexpected result: {}", other),
93        }
94    }
95
96    #[inline]
97    ///Attempts to decrement self, returning whether self was signaled or not.
98    ///
99    ///Returns `true` if self was signaled.
100    ///
101    ///Returns `false` otherwise.
102    pub fn try_wait(&self) -> bool {
103        self.wait_timeout(core::time::Duration::from_secs(0))
104    }
105
106    ///Attempts to decrement self within provided time, returning whether self was signaled or not.
107    ///
108    ///Returns `true` if self was signaled within specified timeout
109    ///
110    ///Returns `false` otherwise
111    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    ///Increments self, waking any awaiting thread as result.
126    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    ///Performs deinitialization.
135    ///
136    ///Using `Sem` after `close` is undefined behaviour, unless `init` is called
137    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 {}