Skip to main content

win_sync_sys/
event.rs

1// Copyright (c) 2026 Mike Grier
2//! Event objects: `CreateEventW`, `SetEvent` and `ResetEvent`.
3
4use std::io;
5use std::os::windows::io::{
6    AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, OwnedHandle, RawHandle,
7};
8use std::ptr;
9
10use windows_sys::Win32::Foundation::{FALSE, TRUE};
11use windows_sys::Win32::System::Threading::{CreateEventW, ResetEvent, SetEvent};
12
13use crate::duplicate::{Access, duplicate_handle_with_access};
14
15/// How an event returns to unsignalled after it is set.
16///
17/// Fixed when the event is created: Windows offers no way to change it, or to
18/// ask an existing event which it is.
19#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
20pub enum ResetMode {
21    /// The event returns to unsignalled as soon as it releases one waiting
22    /// thread. Each [`Event::set`] therefore releases exactly one waiter; with
23    /// nobody waiting, the event stays signalled until somebody waits.
24    Auto,
25    /// The event stays signalled, releasing every waiter, until
26    /// [`Event::reset`] is called.
27    Manual,
28}
29
30/// An owned event object.
31///
32/// Holds a handle to an event and closes it on drop. Because the handle is
33/// owned and is known to be an event, [`set`](Self::set) and
34/// [`reset`](Self::reset) need no `unsafe`.
35///
36/// **The handle being an event is what other crates may rely on**
37/// ([WS-D-4](../DESIGN-NOTES.md#ws-d-4)).
38/// Ownership alone keeps `set` memory-safe; it is event-ness that lets a
39/// consumer such as the thread pool, which cannot wait on a mutex, accept an
40/// `Event` without `unsafe`. That is why adopting an existing handle,
41/// [`from_owned_handle`](Self::from_owned_handle), is `unsafe`.
42///
43/// Setting and resetting take `&self`: they are atomic kernel operations, and
44/// an `Event` is `Send` and `Sync`. Setting an event that is already signalled
45/// changes nothing -- an event is either signalled or not, and does not count
46/// how often it was set.
47///
48/// There is no `pulse`; see the crate documentation for why.
49#[derive(Debug)]
50pub struct Event {
51    handle: OwnedHandle,
52}
53
54impl Event {
55    /// Create an unnamed event.
56    ///
57    /// # Errors
58    ///
59    /// Returns the error from `CreateEventW`. No test reaches this path:
60    /// creating an unnamed event fails only when the process cannot get
61    /// another handle or the kernel cannot allocate the object, which a test
62    /// can produce only by exhausting a resource the rest of the run needs.
63    pub fn new(reset: ResetMode, initially_signalled: bool) -> io::Result<Self> {
64        let manual_reset = match reset {
65            ResetMode::Auto => FALSE,
66            ResetMode::Manual => TRUE,
67        };
68        let initial_state = if initially_signalled { TRUE } else { FALSE };
69        // SAFETY: an unnamed event with default security; every pointer
70        // argument is null, which the function accepts for both.
71        let raw = unsafe { CreateEventW(ptr::null(), manual_reset, initial_state, ptr::null()) };
72        if raw.is_null() {
73            return Err(io::Error::last_os_error());
74        }
75        // SAFETY: the call returned a new handle that nothing else owns.
76        let handle = unsafe { OwnedHandle::from_raw_handle(raw) };
77        Ok(Self { handle })
78    }
79
80    /// Adopt a handle the caller already owns as an event.
81    ///
82    /// For an event that came from somewhere this crate did not create it, such
83    /// as another library or a handle passed in by a parent process.
84    ///
85    /// A handle without `EVENT_MODIFY_STATE` access is accepted: [`set`](Self::set)
86    /// and [`reset`](Self::reset) then report the access error rather than
87    /// changing the event.
88    ///
89    /// # Safety
90    ///
91    /// The caller guarantees that `handle`:
92    ///
93    /// - refers to an **event** object -- not a mutex, a semaphore or any other
94    ///   kind, because code holding an `Event` may rely on that; and
95    /// - carries `SYNCHRONIZE` access, so that anything given the `Event` to
96    ///   wait on can wait on it. What a thread-pool wait does with a handle it
97    ///   cannot wait on is not documented, and an `Event` must be safe to hand
98    ///   it.
99    #[must_use]
100    pub unsafe fn from_owned_handle(handle: OwnedHandle) -> Self {
101        Self { handle }
102    }
103
104    /// Set the event to signalled.
105    ///
106    /// Releases one waiter if the event is [`ResetMode::Auto`], and every
107    /// waiter until it is reset if it is [`ResetMode::Manual`]. Setting an
108    /// event that is already signalled succeeds and changes nothing.
109    ///
110    /// # Errors
111    ///
112    /// Returns the error from `SetEvent`: an access-denied error when the
113    /// handle was adopted without `EVENT_MODIFY_STATE`.
114    pub fn set(&self) -> io::Result<()> {
115        // SAFETY: the handle is owned by `self`, so it is open.
116        if unsafe { SetEvent(self.handle.as_raw_handle()) } == FALSE {
117            return Err(io::Error::last_os_error());
118        }
119        Ok(())
120    }
121
122    /// Set the event to unsignalled.
123    ///
124    /// Resetting an event that is already unsignalled succeeds and changes
125    /// nothing. Resetting an auto-reset event withdraws a signal no waiter
126    /// has taken yet.
127    ///
128    /// # Errors
129    ///
130    /// Returns the error from `ResetEvent`: an access-denied error when the
131    /// handle was adopted without `EVENT_MODIFY_STATE`.
132    pub fn reset(&self) -> io::Result<()> {
133        // SAFETY: the handle is owned by `self`, so it is open.
134        if unsafe { ResetEvent(self.handle.as_raw_handle()) } == FALSE {
135            return Err(io::Error::last_os_error());
136        }
137        Ok(())
138    }
139
140    /// A second handle to the same event, with the same access.
141    ///
142    /// Setting or resetting either affects both, and the event lives until
143    /// every handle to it is closed, so a clone may outlive the original.
144    ///
145    /// # Errors
146    ///
147    /// Returns the error from `DuplicateHandle`. Like [`new`](Self::new)'s, no
148    /// test reaches it: duplicating a handle this process owns fails only when
149    /// the process cannot get another handle.
150    pub fn try_clone(&self) -> io::Result<Self> {
151        Ok(Self {
152            handle: self.handle.try_clone()?,
153        })
154    }
155
156    /// A second handle to the same event that can wait on it and do nothing else.
157    ///
158    /// The handle carries `SYNCHRONIZE` access alone, so it can neither set nor reset the event:
159    /// the kernel refuses a `SetEvent` or `ResetEvent` on it. That is something [`try_clone`] cannot
160    /// give, since its clone holds whatever access the original does. See [`WaitOnlyEvent`] for
161    /// what the result is, why it is not an `Event`, and what the guarantee does not cover.
162    ///
163    /// A wait through it takes what a signalled event gives, as any wait does: waiting through a
164    /// wait-only handle consumes an auto-reset event's signal. What it cannot do is signal or
165    /// withdraw one.
166    ///
167    /// # Errors
168    ///
169    /// Returns the error from `DuplicateHandle`. Like [`try_clone`](Self::try_clone)'s, no test
170    /// reaches it: duplicating a handle this process owns fails only when the process cannot get
171    /// another handle.
172    ///
173    /// [`try_clone`]: Self::try_clone
174    pub fn try_clone_wait_only(&self) -> io::Result<WaitOnlyEvent> {
175        Ok(WaitOnlyEvent {
176            handle: duplicate_handle_with_access(self, Access::SYNCHRONIZE)?,
177        })
178    }
179}
180
181/// A handle to an event that can wait on it and cannot set or reset it.
182///
183/// Made by [`Event::try_clone_wait_only`], carrying `SYNCHRONIZE` access and no more. It is its own
184/// type, not an [`Event`] that fails when set, because what it cannot do is not an error to be
185/// discovered at run time: it has no `set` and no `reset`, and the kernel would refuse them if it
186/// were handed to code that tried ([WS-D-7](../DESIGN-NOTES.md#ws-d-7)).
187///
188/// **What that guarantees**: the handle cannot be used to signal the event, by this crate or by a
189/// raw call, because the kernel refuses. **What it does not**: code that holds the handle can
190/// duplicate it asking for more access, which Windows allows
191/// ([`duplicate_handle_with_access`](crate::duplicate_handle_with_access)), so this guards against
192/// a handle used for what it was not handed out for, not against a holder bent on signalling.
193///
194/// **It is still known to be an event**, so what [WS-D-4](../DESIGN-NOTES.md#ws-d-4) lets a consumer
195/// rely on holds here too: the handle is not a mutex, which is the one kind of object a thread-pool
196/// wait cannot take. There is no way to adopt a handle as one, so that stays true without `unsafe`.
197///
198/// It lends its handle, so [`wait_for_single_object`](crate::wait_for_single_object) waits on it.
199/// `Send` and `Sync`, as an event is.
200#[derive(Debug)]
201pub struct WaitOnlyEvent {
202    handle: OwnedHandle,
203}
204
205impl WaitOnlyEvent {
206    /// A second wait-only handle to the same event.
207    ///
208    /// It holds the same access as this one, so the clone cannot signal either.
209    ///
210    /// # Errors
211    ///
212    /// Returns the error from `DuplicateHandle`; no test reaches it, as for
213    /// [`Event::try_clone`].
214    pub fn try_clone(&self) -> io::Result<Self> {
215        Ok(Self {
216            handle: self.handle.try_clone()?,
217        })
218    }
219}
220
221impl AsHandle for WaitOnlyEvent {
222    fn as_handle(&self) -> BorrowedHandle<'_> {
223        self.handle.as_handle()
224    }
225}
226
227impl AsRawHandle for WaitOnlyEvent {
228    fn as_raw_handle(&self) -> RawHandle {
229        self.handle.as_raw_handle()
230    }
231}
232
233impl From<WaitOnlyEvent> for OwnedHandle {
234    fn from(event: WaitOnlyEvent) -> Self {
235        event.handle
236    }
237}
238
239impl AsHandle for Event {
240    fn as_handle(&self) -> BorrowedHandle<'_> {
241        self.handle.as_handle()
242    }
243}
244
245impl AsRawHandle for Event {
246    fn as_raw_handle(&self) -> RawHandle {
247        self.handle.as_raw_handle()
248    }
249}
250
251impl From<Event> for OwnedHandle {
252    fn from(event: Event) -> Self {
253        event.handle
254    }
255}
256
257#[cfg(test)]
258mod tests;