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