• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 The Chromium OS Authors. All rights reserved.
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 use crate::descriptor::AsRawDescriptor;
8 use crate::{
9     platform::{PollContext, PollToken, WatchingEvents},
10     RawDescriptor, Result,
11 };
12 use smallvec::SmallVec;
13 
14 // Typedef PollToken as EventToken for better adherance to base naming.
15 // As actual typdefing is experimental, define a new trait with the mirrored
16 // attributes.
17 pub trait EventToken: PollToken {}
18 impl<T: PollToken> EventToken for T {}
19 
20 /// Represents an event that has been signaled and waited for via a wait function.
21 #[derive(Copy, Clone, Debug)]
22 pub struct TriggeredEvent<T: EventToken> {
23     pub token: T,
24     pub is_readable: bool,
25     pub is_writable: bool,
26     pub is_hungup: bool,
27 }
28 
29 /// Represents types of events to watch for.
30 pub enum EventType {
31     // Used to to temporarily stop waiting for events without
32     // removing the associated descriptor from the WaitContext.
33     // In most cases if a descriptor no longer needs to be
34     // waited on, prefer removing it entirely with
35     // WaitContext#delete
36     None,
37     Read,
38     Write,
39     ReadWrite,
40 }
41 
42 /// Used to wait for multiple objects which are eligible for waiting.
43 ///
44 /// # Example
45 ///
46 /// ```
47 /// # use base::{
48 ///     Result, Event, WaitContext,
49 /// };
50 /// # fn test() -> Result<()> {
51 ///     let evt1 = Event::new()?;
52 ///     let evt2 = Event::new()?;
53 ///     evt2.write(1)?;
54 ///
55 ///     let ctx: WaitContext<u32> = WaitContext::new()?;
56 ///     ctx.add(&evt1, 1)?;
57 ///     ctx.add(&evt2, 2)?;
58 ///
59 ///     let events = ctx.wait()?;
60 ///     let tokens: Vec<u32> = events.iter().filter(|e| e.is_readable)
61 ///         .map(|e| e.token).collect();
62 ///     assert_eq!(tokens, [2]);
63 /// #   Ok(())
64 /// # }
65 /// ```
66 pub struct WaitContext<T: EventToken>(PollContext<T>);
67 
68 impl<T: EventToken> WaitContext<T> {
69     /// Creates a new WaitContext.
new() -> Result<WaitContext<T>>70     pub fn new() -> Result<WaitContext<T>> {
71         PollContext::new().map(WaitContext)
72     }
73 
74     /// Creates a new WaitContext with the the associated triggers.
build_with(triggers: &[(&dyn AsRawDescriptor, T)]) -> Result<WaitContext<T>>75     pub fn build_with(triggers: &[(&dyn AsRawDescriptor, T)]) -> Result<WaitContext<T>> {
76         let ctx = WaitContext::new()?;
77         ctx.add_many(triggers)?;
78         Ok(ctx)
79     }
80 
81     /// Adds a trigger to the WaitContext.
add(&self, descriptor: &dyn AsRawDescriptor, token: T) -> Result<()>82     pub fn add(&self, descriptor: &dyn AsRawDescriptor, token: T) -> Result<()> {
83         self.add_for_event(descriptor, EventType::Read, token)
84     }
85 
86     /// 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<()>87     pub fn add_for_event(
88         &self,
89         descriptor: &dyn AsRawDescriptor,
90         event_type: EventType,
91         token: T,
92     ) -> Result<()> {
93         self.0
94             .add_fd_with_events(descriptor, convert_to_watching_events(event_type), token)
95     }
96 
97     /// Adds multiple triggers to the WaitContext.
add_many(&self, triggers: &[(&dyn AsRawDescriptor, T)]) -> Result<()>98     pub fn add_many(&self, triggers: &[(&dyn AsRawDescriptor, T)]) -> Result<()> {
99         for trigger in triggers {
100             self.add(trigger.0, T::from_raw_token(trigger.1.as_raw_token()))?
101         }
102         Ok(())
103     }
104 
105     /// Modifies a trigger already added to the WaitContext. If the descriptor is
106     /// already registered, its associated token will be updated.
modify( &self, descriptor: &dyn AsRawDescriptor, event_type: EventType, token: T, ) -> Result<()>107     pub fn modify(
108         &self,
109         descriptor: &dyn AsRawDescriptor,
110         event_type: EventType,
111         token: T,
112     ) -> Result<()> {
113         self.0
114             .modify(descriptor, convert_to_watching_events(event_type), token)
115     }
116 
117     /// Removes the given handle from triggers registered in the WaitContext if
118     /// present.
delete(&self, descriptor: &dyn AsRawDescriptor) -> Result<()>119     pub fn delete(&self, descriptor: &dyn AsRawDescriptor) -> Result<()> {
120         self.0.delete(descriptor)
121     }
122 
123     /// Waits for one or more of the registered triggers to become signaled.
wait(&self) -> Result<SmallVec<[TriggeredEvent<T>; 16]>>124     pub fn wait(&self) -> Result<SmallVec<[TriggeredEvent<T>; 16]>> {
125         self.wait_timeout(Duration::new(i64::MAX as u64, 0))
126     }
127     /// Waits for one or more of the registered triggers to become signaled, failing if no triggers
128     /// are signaled before the designated timeout has elapsed.
wait_timeout(&self, timeout: Duration) -> Result<SmallVec<[TriggeredEvent<T>; 16]>>129     pub fn wait_timeout(&self, timeout: Duration) -> Result<SmallVec<[TriggeredEvent<T>; 16]>> {
130         let events = self.0.wait_timeout(timeout)?;
131         Ok(events
132             .iter()
133             .map(|event| TriggeredEvent {
134                 token: event.token(),
135                 is_readable: event.readable(),
136                 is_writable: event.writable(),
137                 is_hungup: event.hungup(),
138             })
139             .collect())
140     }
141 }
142 
143 impl<T: PollToken> AsRawDescriptor for WaitContext<T> {
as_raw_descriptor(&self) -> RawDescriptor144     fn as_raw_descriptor(&self) -> RawDescriptor {
145         self.0.as_raw_descriptor()
146     }
147 }
148 
convert_to_watching_events(event_type: EventType) -> WatchingEvents149 fn convert_to_watching_events(event_type: EventType) -> WatchingEvents {
150     match event_type {
151         EventType::None => WatchingEvents::empty(),
152         EventType::Read => WatchingEvents::empty().set_read(),
153         EventType::Write => WatchingEvents::empty().set_write(),
154         EventType::ReadWrite => WatchingEvents::empty().set_read().set_write(),
155     }
156 }
157