zx/
wait.rs

1// Copyright 2024 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::{sys, HandleRef, MonotonicInstant, Signals, Status};
6
7/// A "wait item" containing a handle reference and information about what signals
8/// to wait on, and, on return from `object_wait_many`, which are pending.
9#[repr(C)]
10#[derive(Debug)]
11pub struct WaitItem<'a> {
12    /// The handle to wait on.
13    pub handle: HandleRef<'a>,
14    /// A set of signals to wait for.
15    pub waitfor: Signals,
16    /// The set of signals pending, on return of `object_wait_many`.
17    pub pending: Signals,
18}
19
20/// Wait on multiple handles.
21/// The success return value is a bool indicating whether one or more of the
22/// provided handle references was closed during the wait.
23///
24/// Wraps the
25/// [zx_object_wait_many](https://fuchsia.dev/fuchsia-src/reference/syscalls/object_wait_many.md)
26/// syscall.
27pub fn object_wait_many(
28    items: &mut [WaitItem<'_>],
29    deadline: MonotonicInstant,
30) -> Result<bool, Status> {
31    let items_ptr = items.as_mut_ptr().cast::<sys::zx_wait_item_t>();
32    let status = unsafe { sys::zx_object_wait_many(items_ptr, items.len(), deadline.into_nanos()) };
33    if status == sys::ZX_ERR_CANCELED {
34        return Ok(true);
35    }
36    Status::ok(status).map(|()| false)
37}
38
39#[cfg(test)]
40mod tests {
41    use super::*;
42    use crate::{AsHandleRef, Duration, Event};
43
44    #[test]
45    fn wait_and_signal() {
46        let event = Event::create();
47        let ten_ms = Duration::from_millis(10);
48
49        // Waiting on it without setting any signal should time out.
50        assert_eq!(
51            event.wait_handle(Signals::USER_0, MonotonicInstant::after(ten_ms)),
52            Err(Status::TIMED_OUT)
53        );
54
55        // If we set a signal, we should be able to wait for it.
56        assert!(event.signal_handle(Signals::NONE, Signals::USER_0).is_ok());
57        assert_eq!(
58            event.wait_handle(Signals::USER_0, MonotonicInstant::after(ten_ms)).unwrap(),
59            Signals::USER_0
60        );
61
62        // Should still work, signals aren't automatically cleared.
63        assert_eq!(
64            event.wait_handle(Signals::USER_0, MonotonicInstant::after(ten_ms)).unwrap(),
65            Signals::USER_0
66        );
67
68        // Now clear it, and waiting should time out again.
69        assert!(event.signal_handle(Signals::USER_0, Signals::NONE).is_ok());
70        assert_eq!(
71            event.wait_handle(Signals::USER_0, MonotonicInstant::after(ten_ms)),
72            Err(Status::TIMED_OUT)
73        );
74    }
75
76    #[test]
77    fn wait_many_and_signal() {
78        let ten_ms = Duration::from_millis(10);
79        let e1 = Event::create();
80        let e2 = Event::create();
81
82        // Waiting on them now should time out.
83        let mut items = vec![
84            WaitItem {
85                handle: e1.as_handle_ref(),
86                waitfor: Signals::USER_0,
87                pending: Signals::NONE,
88            },
89            WaitItem {
90                handle: e2.as_handle_ref(),
91                waitfor: Signals::USER_1,
92                pending: Signals::NONE,
93            },
94        ];
95        assert_eq!(
96            object_wait_many(&mut items, MonotonicInstant::after(ten_ms)),
97            Err(Status::TIMED_OUT)
98        );
99        assert_eq!(items[0].pending, Signals::NONE);
100        assert_eq!(items[1].pending, Signals::NONE);
101
102        // Signal one object and it should return success.
103        assert!(e1.signal_handle(Signals::NONE, Signals::USER_0).is_ok());
104        assert!(object_wait_many(&mut items, MonotonicInstant::after(ten_ms)).is_ok());
105        assert_eq!(items[0].pending, Signals::USER_0);
106        assert_eq!(items[1].pending, Signals::NONE);
107
108        // Signal the other and it should return both.
109        assert!(e2.signal_handle(Signals::NONE, Signals::USER_1).is_ok());
110        assert!(object_wait_many(&mut items, MonotonicInstant::after(ten_ms)).is_ok());
111        assert_eq!(items[0].pending, Signals::USER_0);
112        assert_eq!(items[1].pending, Signals::USER_1);
113
114        // Clear signals on both; now it should time out again.
115        assert!(e1.signal_handle(Signals::USER_0, Signals::NONE).is_ok());
116        assert!(e2.signal_handle(Signals::USER_1, Signals::NONE).is_ok());
117        assert_eq!(
118            object_wait_many(&mut items, MonotonicInstant::after(ten_ms)),
119            Err(Status::TIMED_OUT)
120        );
121        assert_eq!(items[0].pending, Signals::NONE);
122        assert_eq!(items[1].pending, Signals::NONE);
123    }
124}