1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
// Copyright 2020 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::time::Duration;

use serde::Deserialize;
use serde::Serialize;

use crate::descriptor::AsRawDescriptor;
use crate::descriptor::FromRawDescriptor;
use crate::descriptor::IntoRawDescriptor;
use crate::descriptor::SafeDescriptor;
use crate::platform::PlatformEvent;
use crate::RawDescriptor;
use crate::Result;

/// An inter-process event wait/notify mechanism. Loosely speaking: Writes signal the event. Reads
/// block until the event is signaled and then clear the signal.
///
/// Supports multiple simultaneous writers (i.e. signalers) but only one simultaneous reader (i.e.
/// waiter). The behavior of multiple readers is undefined in cross platform code.
///
/// Multiple `Event`s can be polled at once via `WaitContext`.
///
/// Implementation notes:
/// - Uses eventfd on Linux.
/// - Uses synchapi event objects on Windows.
/// - The `Event` and `WaitContext` APIs together cannot easily be implemented with the same
///   semantics on all platforms. In particular, it is difficult to support multiple readers, so
///   only a single reader is allowed for now. Multiple readers will result in undefined behavior.
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(transparent)]
pub struct Event(pub(crate) PlatformEvent);

#[derive(PartialEq, Eq, Debug)]
pub enum EventWaitResult {
    /// The `Event` was signaled.
    Signaled,
    /// Timeout limit reached.
    TimedOut,
}

impl Event {
    /// Creates new event in an unsignaled state.
    pub fn new() -> Result<Event> {
        PlatformEvent::new().map(Event)
    }

    /// Signals the event.
    pub fn signal(&self) -> Result<()> {
        self.0.signal()
    }

    /// Blocks until the event is signaled and clears the signal.
    ///
    /// It is undefined behavior to wait on an event from multiple threads or processes
    /// simultaneously.
    pub fn wait(&self) -> Result<()> {
        self.0.wait()
    }

    /// Blocks until the event is signaled and clears the signal, or until the timeout duration
    /// expires.
    ///
    /// It is undefined behavior to wait on an event from multiple threads or processes
    /// simultaneously.
    pub fn wait_timeout(&self, timeout: Duration) -> Result<EventWaitResult> {
        self.0.wait_timeout(timeout)
    }

    /// Clears the event without blocking.
    ///
    /// If the event is not signaled, this has no effect and returns immediately.
    pub fn reset(&self) -> Result<()> {
        self.0.reset()
    }

    /// Clones the event. The event's state is shared between cloned instances.
    ///
    /// The documented caveats for `Event` also apply to a set of cloned instances, e.g., it is
    /// undefined behavior to clone an event and then call `Event::wait` simultaneously on both
    /// objects.
    ///
    /// Implementation notes:
    ///   * Linux: The cloned instance uses a separate file descriptor.
    ///   * Windows: The cloned instance uses a separate handle.
    pub fn try_clone(&self) -> Result<Event> {
        self.0.try_clone().map(Event)
    }
}

impl AsRawDescriptor for Event {
    fn as_raw_descriptor(&self) -> RawDescriptor {
        self.0.as_raw_descriptor()
    }
}

impl FromRawDescriptor for Event {
    unsafe fn from_raw_descriptor(descriptor: RawDescriptor) -> Self {
        Event(PlatformEvent::from_raw_descriptor(descriptor))
    }
}

impl IntoRawDescriptor for Event {
    fn into_raw_descriptor(self) -> RawDescriptor {
        self.0.into_raw_descriptor()
    }
}

impl From<Event> for SafeDescriptor {
    fn from(evt: Event) -> Self {
        Self::from(evt.0)
    }
}

impl From<SafeDescriptor> for Event {
    fn from(sd: SafeDescriptor) -> Self {
        Event(PlatformEvent::from(sd))
    }
}