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}