Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/base/src/wait_context.rs
5394 views
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
5
use std::time::Duration;
6
7
pub use base_event_token_derive::*;
8
use smallvec::SmallVec;
9
10
use crate::descriptor::AsRawDescriptor;
11
use crate::platform::EventContext;
12
use crate::RawDescriptor;
13
use 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.
21
pub 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
33
impl 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
43
impl 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
53
impl 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
63
impl 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
73
impl 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
83
impl 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)]
93
pub 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)]
102
pub 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
/// ```
162
pub struct WaitContext<T: EventToken>(pub(crate) EventContext<T>);
163
164
impl<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
229
impl<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)]
236
mod 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
}
279
280