base/
wait_context.rs

1// Copyright 2020 The ChromiumOS Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use std::time::Duration;
6
7pub use base_event_token_derive::*;
8use smallvec::SmallVec;
9
10use crate::descriptor::AsRawDescriptor;
11use crate::platform::EventContext;
12use crate::RawDescriptor;
13use crate::Result;
14
15/// Trait that can be used to associate events with arbitrary enums when using
16/// `WaitContext`.
17///
18/// Simple enums that have no or primitive variant data data can use the `#[derive(EventToken)]`
19/// custom derive to implement this trait. See
20/// [event_token_derive::event_token](../base_event_token_derive/fn.event_token.html) for details.
21pub trait EventToken {
22    /// Converts this token into a u64 that can be turned back into a token via `from_raw_token`.
23    fn as_raw_token(&self) -> u64;
24
25    /// Converts a raw token as returned from `as_raw_token` back into a token.
26    ///
27    /// It is invalid to give a raw token that was not returned via `as_raw_token` from the same
28    /// `Self`. The implementation can expect that this will never happen as a result of its usage
29    /// in `WaitContext`.
30    fn from_raw_token(data: u64) -> Self;
31}
32
33impl EventToken for usize {
34    fn as_raw_token(&self) -> u64 {
35        *self as u64
36    }
37
38    fn from_raw_token(data: u64) -> Self {
39        data as Self
40    }
41}
42
43impl EventToken for u64 {
44    fn as_raw_token(&self) -> u64 {
45        *self
46    }
47
48    fn from_raw_token(data: u64) -> Self {
49        data as Self
50    }
51}
52
53impl EventToken for u32 {
54    fn as_raw_token(&self) -> u64 {
55        u64::from(*self)
56    }
57
58    fn from_raw_token(data: u64) -> Self {
59        data as Self
60    }
61}
62
63impl EventToken for u16 {
64    fn as_raw_token(&self) -> u64 {
65        u64::from(*self)
66    }
67
68    fn from_raw_token(data: u64) -> Self {
69        data as Self
70    }
71}
72
73impl EventToken for u8 {
74    fn as_raw_token(&self) -> u64 {
75        u64::from(*self)
76    }
77
78    fn from_raw_token(data: u64) -> Self {
79        data as Self
80    }
81}
82
83impl EventToken for () {
84    fn as_raw_token(&self) -> u64 {
85        0
86    }
87
88    fn from_raw_token(_data: u64) -> Self {}
89}
90
91/// Represents an event that has been signaled and waited for via a wait function.
92#[derive(Copy, Clone, Debug)]
93pub struct TriggeredEvent<T: EventToken> {
94    pub token: T,
95    pub is_readable: bool,
96    pub is_writable: bool,
97    pub is_hungup: bool,
98}
99
100/// Represents types of events to watch for.
101#[derive(Copy, Clone, Debug, PartialEq, Eq)]
102pub enum EventType {
103    // Used to to temporarily stop waiting for events without
104    // removing the associated descriptor from the WaitContext.
105    // In most cases if a descriptor no longer needs to be
106    // waited on, prefer removing it entirely with
107    // WaitContext#delete
108    None,
109    Read,
110    Write,
111    ReadWrite,
112}
113
114/// Used to wait for multiple objects which are eligible for waiting.
115///
116/// # Example
117///
118/// ```
119/// use base::{Event, EventToken, Result, WaitContext};
120///
121/// #[derive(EventToken, Copy, Clone, Debug, PartialEq, Eq)]
122/// enum ExampleToken {
123///    SomeEvent(u32),
124///    AnotherEvent,
125/// }
126///
127/// let evt1 = Event::new()?;
128/// let evt2 = Event::new()?;
129/// let another_evt = Event::new()?;
130///
131/// let ctx: WaitContext<ExampleToken> = WaitContext::build_with(&[
132///     (&evt1, ExampleToken::SomeEvent(1)),
133///     (&evt2, ExampleToken::SomeEvent(2)),
134///     (&another_evt, ExampleToken::AnotherEvent),
135/// ])?;
136///
137/// // Trigger one of the `SomeEvent` events.
138/// evt2.signal()?;
139///
140/// // Wait for an event to fire. `wait()` will return immediately in this example because `evt2`
141/// // has already been triggered, but in normal use, `wait()` will block until at least one event
142/// // is signaled by another thread or process.
143/// let events = ctx.wait()?;
144/// let tokens: Vec<ExampleToken> = events.iter().filter(|e| e.is_readable)
145///     .map(|e| e.token).collect();
146/// assert_eq!(tokens, [ExampleToken::SomeEvent(2)]);
147///
148/// // Reset evt2 so it doesn't trigger again in the next `wait()` call.
149/// let _ = evt2.reset()?;
150///
151/// // Trigger a different event.
152/// another_evt.signal()?;
153///
154/// let events = ctx.wait()?;
155/// let tokens: Vec<ExampleToken> = events.iter().filter(|e| e.is_readable)
156///     .map(|e| e.token).collect();
157/// assert_eq!(tokens, [ExampleToken::AnotherEvent]);
158///
159/// let _ = another_evt.reset()?;
160/// # Ok::<(), base::Error>(())
161/// ```
162pub struct WaitContext<T: EventToken>(pub(crate) EventContext<T>);
163
164impl<T: EventToken> WaitContext<T> {
165    /// Creates a new WaitContext.
166    pub fn new() -> Result<WaitContext<T>> {
167        EventContext::new().map(WaitContext)
168    }
169
170    /// Creates a new WaitContext with the the associated triggers.
171    pub fn build_with(triggers: &[(&dyn AsRawDescriptor, T)]) -> Result<WaitContext<T>> {
172        let ctx = WaitContext::new()?;
173        ctx.add_many(triggers)?;
174        Ok(ctx)
175    }
176
177    /// Adds a trigger to the WaitContext.
178    pub fn add(&self, descriptor: &dyn AsRawDescriptor, token: T) -> Result<()> {
179        self.add_for_event(descriptor, EventType::Read, token)
180    }
181
182    /// Adds a trigger to the WaitContext watching for a specific type of event
183    pub fn add_for_event(
184        &self,
185        descriptor: &dyn AsRawDescriptor,
186        event_type: EventType,
187        token: T,
188    ) -> Result<()> {
189        self.0.add_for_event(descriptor, event_type, token)
190    }
191
192    /// Adds multiple triggers to the WaitContext.
193    pub fn add_many(&self, triggers: &[(&dyn AsRawDescriptor, T)]) -> Result<()> {
194        for trigger in triggers {
195            self.add(trigger.0, T::from_raw_token(trigger.1.as_raw_token()))?
196        }
197        Ok(())
198    }
199
200    /// Modifies a trigger already added to the WaitContext. If the descriptor is
201    /// already registered, its associated token will be updated.
202    pub fn modify(
203        &self,
204        descriptor: &dyn AsRawDescriptor,
205        event_type: EventType,
206        token: T,
207    ) -> Result<()> {
208        self.0.modify(descriptor, event_type, token)
209    }
210
211    /// Removes the given handle from triggers registered in the WaitContext if
212    /// present.
213    pub fn delete(&self, descriptor: &dyn AsRawDescriptor) -> Result<()> {
214        self.0.delete(descriptor)
215    }
216
217    /// Waits for one or more of the registered triggers to become signaled.
218    pub fn wait(&self) -> Result<SmallVec<[TriggeredEvent<T>; 16]>> {
219        self.wait_timeout(Duration::new(i64::MAX as u64, 0))
220    }
221
222    /// Waits for one or more of the registered triggers to become signaled, failing if no triggers
223    /// are signaled before the designated timeout has elapsed.
224    pub fn wait_timeout(&self, timeout: Duration) -> Result<SmallVec<[TriggeredEvent<T>; 16]>> {
225        self.0.wait_timeout(timeout)
226    }
227}
228
229impl<T: EventToken> AsRawDescriptor for WaitContext<T> {
230    fn as_raw_descriptor(&self) -> RawDescriptor {
231        self.0.as_raw_descriptor()
232    }
233}
234
235#[cfg(test)]
236mod tests {
237    use base_event_token_derive::EventToken;
238
239    use super::*;
240
241    #[test]
242    #[allow(dead_code)]
243    fn event_token_derive() {
244        #[derive(EventToken)]
245        enum EmptyToken {}
246
247        #[derive(PartialEq, Debug, EventToken)]
248        enum Token {
249            Alpha,
250            Beta,
251            // comments
252            Gamma(u32),
253            Delta { index: usize },
254            Omega,
255        }
256
257        assert_eq!(
258            Token::from_raw_token(Token::Alpha.as_raw_token()),
259            Token::Alpha
260        );
261        assert_eq!(
262            Token::from_raw_token(Token::Beta.as_raw_token()),
263            Token::Beta
264        );
265        assert_eq!(
266            Token::from_raw_token(Token::Gamma(55).as_raw_token()),
267            Token::Gamma(55)
268        );
269        assert_eq!(
270            Token::from_raw_token(Token::Delta { index: 100 }.as_raw_token()),
271            Token::Delta { index: 100 }
272        );
273        assert_eq!(
274            Token::from_raw_token(Token::Omega.as_raw_token()),
275            Token::Omega
276        );
277    }
278}