zx/
eventpair.rs

1// Copyright 2016 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
5//! Type-safe bindings for Zircon event pairs.
6
7use crate::{AsHandleRef, HandleBased, HandleRef, NullableHandle, Peered, ok};
8
9/// An object representing a Zircon
10/// [event_pair](https://fuchsia.dev/fuchsia-src/concepts/kernel/concepts#events_event_pairs)
11///
12/// As essentially a subtype of `NullableHandle`, it can be freely interconverted.
13#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
14#[repr(transparent)]
15pub struct EventPair(NullableHandle);
16impl_handle_based!(EventPair);
17impl Peered for EventPair {}
18
19impl EventPair {
20    /// Create an event pair, a pair of objects which can signal each other. Wraps the
21    /// [zx_eventpair_create](https://fuchsia.dev/fuchsia-src/reference/syscalls/eventpair_create.md)
22    /// syscall.
23    ///
24    /// # Panics
25    ///
26    /// If the kernel reports no available memory to create an event pair or the process' job
27    /// policy disallows EventPair creation.
28    pub fn create() -> (Self, Self) {
29        let mut out0 = 0;
30        let mut out1 = 0;
31        let options = 0;
32        let status = unsafe { crate::sys::zx_eventpair_create(options, &mut out0, &mut out1) };
33        ok(status).expect(
34            "eventpair creation always succeeds except with OOM or when job policy denies it",
35        );
36        unsafe {
37            (Self::from(NullableHandle::from_raw(out0)), Self::from(NullableHandle::from_raw(out1)))
38        }
39    }
40}
41
42#[cfg(test)]
43mod tests {
44    use super::*;
45    use crate::{Duration, MonotonicInstant, Signals, WaitResult};
46
47    #[test]
48    fn wait_and_signal_peer() {
49        let (p1, p2) = EventPair::create();
50        let eighty_ms = Duration::from_millis(80);
51
52        // Waiting on one without setting any signal should time out.
53        assert_eq!(
54            p2.wait_handle(Signals::USER_0, MonotonicInstant::after(eighty_ms)),
55            WaitResult::TimedOut(Signals::empty())
56        );
57
58        // If we set a signal, we should be able to wait for it.
59        assert!(p1.signal_peer(Signals::NONE, Signals::USER_0).is_ok());
60        assert_eq!(
61            p2.wait_handle(Signals::USER_0, MonotonicInstant::after(eighty_ms)).unwrap(),
62            Signals::USER_0
63        );
64
65        // Should still work, signals aren't automatically cleared.
66        assert_eq!(
67            p2.wait_handle(Signals::USER_0, MonotonicInstant::after(eighty_ms)).unwrap(),
68            Signals::USER_0
69        );
70
71        // Now clear it, and waiting should time out again.
72        assert!(p1.signal_peer(Signals::USER_0, Signals::NONE).is_ok());
73        assert_eq!(
74            p2.wait_handle(Signals::USER_0, MonotonicInstant::after(eighty_ms)),
75            WaitResult::TimedOut(Signals::empty())
76        );
77    }
78}