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`. as_raw_token(&self) -> u6423 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`. from_raw_token(data: u64) -> Self30 fn from_raw_token(data: u64) -> Self; 31 } 32 33 impl EventToken for usize { as_raw_token(&self) -> u6434 fn as_raw_token(&self) -> u64 { 35 *self as u64 36 } 37 from_raw_token(data: u64) -> Self38 fn from_raw_token(data: u64) -> Self { 39 data as Self 40 } 41 } 42 43 impl EventToken for u64 { as_raw_token(&self) -> u6444 fn as_raw_token(&self) -> u64 { 45 *self 46 } 47 from_raw_token(data: u64) -> Self48 fn from_raw_token(data: u64) -> Self { 49 data as Self 50 } 51 } 52 53 impl EventToken for u32 { as_raw_token(&self) -> u6454 fn as_raw_token(&self) -> u64 { 55 u64::from(*self) 56 } 57 from_raw_token(data: u64) -> Self58 fn from_raw_token(data: u64) -> Self { 59 data as Self 60 } 61 } 62 63 impl EventToken for u16 { as_raw_token(&self) -> u6464 fn as_raw_token(&self) -> u64 { 65 u64::from(*self) 66 } 67 from_raw_token(data: u64) -> Self68 fn from_raw_token(data: u64) -> Self { 69 data as Self 70 } 71 } 72 73 impl EventToken for u8 { as_raw_token(&self) -> u6474 fn as_raw_token(&self) -> u64 { 75 u64::from(*self) 76 } 77 from_raw_token(data: u64) -> Self78 fn from_raw_token(data: u64) -> Self { 79 data as Self 80 } 81 } 82 83 impl EventToken for () { as_raw_token(&self) -> u6484 fn as_raw_token(&self) -> u64 { 85 0 86 } 87 from_raw_token(_data: u64) -> Self88 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. new() -> Result<WaitContext<T>>166 pub fn new() -> Result<WaitContext<T>> { 167 EventContext::new().map(WaitContext) 168 } 169 170 /// Creates a new WaitContext with the the associated triggers. build_with(triggers: &[(&dyn AsRawDescriptor, T)]) -> Result<WaitContext<T>>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. add(&self, descriptor: &dyn AsRawDescriptor, token: T) -> Result<()>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 add_for_event( &self, descriptor: &dyn AsRawDescriptor, event_type: EventType, token: T, ) -> Result<()>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. add_many(&self, triggers: &[(&dyn AsRawDescriptor, T)]) -> Result<()>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. modify( &self, descriptor: &dyn AsRawDescriptor, event_type: EventType, token: T, ) -> Result<()>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. delete(&self, descriptor: &dyn AsRawDescriptor) -> Result<()>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. wait(&self) -> Result<SmallVec<[TriggeredEvent<T>; 16]>>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. wait_timeout(&self, timeout: Duration) -> Result<SmallVec<[TriggeredEvent<T>; 16]>>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> { as_raw_descriptor(&self) -> RawDescriptor230 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)] event_token_derive()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