Skip to main content

win_durable_ioring/windows_backend/
wait.rs

1// Copyright (c) 2026 Mike Grier
2//! The Windows backend's notification, waited on (DI-D-55): the ring's completion event, as the
3//! [`CompletionEvent`] the backend hands out.
4
5use std::io;
6use std::os::windows::io::{AsHandle, BorrowedHandle, OwnedHandle};
7use std::time::Duration;
8
9use win_sync_sys::{WaitOutcome, wait_for_single_object};
10
11use durable_ioring::Waitable;
12
13#[cfg(test)]
14mod tests;
15
16/// The ring's completion event, duplicated for the one that waits on it: the notification the
17/// Windows backend hands out. A type of this crate and not a bare `OwnedHandle`, because
18/// [`Waitable`] is the portable crate's trait and a handle is the standard library's, so neither
19/// side could implement one for the other.
20///
21/// One is only made from the ring's own event, by this crate; no safe constructor takes an
22/// arbitrary handle, which could be a mutex the wait would acquire and never release:
23///
24/// ```compile_fail,E0624
25/// use std::os::windows::io::OwnedHandle;
26/// use win_durable_ioring::windows_backend::CompletionEvent;
27///
28/// fn any_handle(handle: OwnedHandle) -> CompletionEvent {
29///     CompletionEvent::new(handle)
30/// }
31/// ```
32#[derive(Debug)]
33pub struct CompletionEvent(OwnedHandle);
34
35impl CompletionEvent {
36    /// The event, taking the handle it is waited on through. Not public: the handle must be an
37    /// event the ring's own completion edge is, with `SYNCHRONIZE` access, which this crate's
38    /// callers make and an arbitrary `OwnedHandle` -- a mutex, say, which a wait would acquire and
39    /// never release -- does not promise.
40    #[must_use]
41    pub(crate) fn new(handle: OwnedHandle) -> Self {
42        Self(handle)
43    }
44
45    /// The handle, to wait on by other means.
46    #[must_use]
47    pub fn into_handle(self) -> OwnedHandle {
48        self.0
49    }
50}
51
52impl AsHandle for CompletionEvent {
53    fn as_handle(&self) -> BorrowedHandle<'_> {
54        self.0.as_handle()
55    }
56}
57
58/// The ring's completion event is auto-reset (the ring crate's D-21), so a wait that sees it
59/// signalled consumes the signal, and a raising before the first wait is seen by it: the ring crate
60/// signals the event once as it attaches it (its D-20).
61///
62/// **One waiter per ring** is the caller's to keep, as the ring crate states it: a second wait on
63/// the same event, or a duplicate of this handle waited on elsewhere, steals wakes.
64impl Waitable for CompletionEvent {
65    fn wait(&mut self, timeout: Option<Duration>) -> io::Result<bool> {
66        match wait_for_single_object(&self.0, timeout)? {
67            WaitOutcome::Signalled => Ok(true),
68            WaitOutcome::TimedOut => Ok(false),
69            // An event is never abandoned, which only a mutex can be, and only an event is made
70            // into one of these. Not reached by a test here: making a mutex needs `unsafe`, which
71            // this crate forbids. `win-sync-sys`' tests reach the ending in the function this
72            // calls. (A wait failing is reached, with a duplicate that has no `SYNCHRONIZE`
73            // access.) The ending is reported, not taken for a signal.
74            other => Err(io::Error::other(format!(
75                "the notification's wait ended as {other:?}"
76            ))),
77        }
78    }
79}