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