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))
}
}