event_manager/events.rs
1// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
3
4use std::os::unix::io::{AsRawFd, RawFd};
5
6use super::{Errno, Error, Result, SubscriberId};
7use crate::epoll::EpollWrapper;
8use vmm_sys_util::epoll::{ControlOperation, EpollEvent, EventSet};
9
10/// Wrapper over an `epoll::EpollEvent` object.
11///
12/// When working directly with epoll related methods, the user associates an `u64` wide
13/// epoll_data_t object with every event. We want to use fds as identifiers, but at the same time
14/// keep the ability to associate opaque data with an event. An `Events` object always contains an
15/// fd and an `u32` data member that can be supplied by the user. When registering events with the
16/// inner epoll event set, the fd and data members of `Events` are used together to generate the
17/// underlying `u64` member of the epoll_data union.
18#[derive(Clone, Copy, Debug)]
19pub struct Events {
20 inner: EpollEvent,
21}
22
23impl PartialEq for Events {
24 fn eq(&self, other: &Events) -> bool {
25 self.fd() == other.fd()
26 && self.data() == other.data()
27 && self.event_set() == other.event_set()
28 }
29}
30
31impl Events {
32 pub(crate) fn with_inner(inner: EpollEvent) -> Self {
33 Self { inner }
34 }
35
36 /// Create an empty event set associated with `source`.
37 ///
38 /// No explicit events are monitored for the associated file descriptor.
39 /// Nevertheless, [`EventSet::ERROR`](struct.EventSet.html#associatedconstant.ERROR) and
40 /// [`EventSet::HANG_UP`](struct.EventSet.html#associatedconstant.HANG_UP) are implicitly
41 /// monitored.
42 ///
43 /// # Arguments
44 ///
45 /// * source: object that wraps a file descriptor to be associated with `events`
46 ///
47 /// # Example
48 ///
49 /// ```rust
50 /// # use event_manager::Events;
51 /// # use vmm_sys_util::eventfd::EventFd;
52 /// let eventfd = EventFd::new(0).unwrap();
53 /// let ev_set = Events::empty(&eventfd);
54 /// ```
55 pub fn empty<T: AsRawFd>(source: &T) -> Self {
56 Self::empty_raw(source.as_raw_fd())
57 }
58
59 /// Create an empty event set associated with the supplied `RawFd` value.
60 ///
61 /// No explicit events are monitored for the associated file descriptor.
62 /// Nevertheless, [`EventSet::ERROR`](struct.EventSet.html#associatedconstant.ERROR) and
63 /// [`EventSet::HANG_UP`](struct.EventSet.html#associatedconstant.HANG_UP) are implicitly
64 /// monitored.
65 ///
66 /// # Example
67 ///
68 /// ```rust
69 /// # use event_manager::Events;
70 /// # use std::os::unix::io::AsRawFd;
71 /// # use vmm_sys_util::eventfd::EventFd;
72 /// let eventfd = EventFd::new(0).unwrap();
73 /// let ev_set = Events::empty_raw(eventfd.as_raw_fd());
74 /// ```
75 pub fn empty_raw(fd: RawFd) -> Self {
76 Self::new_raw(fd, EventSet::empty())
77 }
78
79 /// Create an event with `source` and the associated `events` for monitoring.
80 ///
81 /// # Arguments
82 ///
83 /// * source: object that wraps a file descriptor to be associated with `events`
84 /// * events: events to monitor on the provided `source`;
85 /// [`EventSet::ERROR`](struct.EventSet.html#associatedconstant.ERROR) and
86 /// [`EventSet::HANG_UP`](struct.EventSet.html#associatedconstant.HANG_UP) are
87 /// always monitored and don't need to be explicitly added to the list.
88 ///
89 /// # Example
90 ///
91 /// ```rust
92 /// # use event_manager::{Events, EventSet};
93 /// # use vmm_sys_util::eventfd::EventFd;
94 /// let eventfd = EventFd::new(0).unwrap();
95 /// let event_set = EventSet::IN;
96 /// let ev_set = Events::new(&eventfd, event_set);
97 /// ```
98 pub fn new<T: AsRawFd>(source: &T, events: EventSet) -> Self {
99 Self::new_raw(source.as_raw_fd(), events)
100 }
101
102 /// Create an event with the supplied `RawFd` value and `events` for monitoring.
103 ///
104 /// # Arguments
105 ///
106 /// * source: file descriptor on which to monitor the `events`
107 /// * events: events to monitor on the provided `source`;
108 /// [`EventSet::ERROR`](struct.EventSet.html#associatedconstant.ERROR) and
109 /// [`EventSet::HANG_UP`](struct.EventSet.html#associatedconstant.HANG_UP) are
110 /// always monitored and don't need to be explicitly added to the list.
111 /// # Example
112 ///
113 /// ```rust
114 /// # use event_manager::{Events, EventSet};
115 /// # use vmm_sys_util::eventfd::EventFd;
116 /// # use std::os::unix::io::AsRawFd;
117 /// let eventfd = EventFd::new(0).unwrap();
118 /// let event_set = EventSet::IN;
119 /// let ev_set = Events::new_raw(eventfd.as_raw_fd(), event_set);
120 /// ```
121 pub fn new_raw(source: RawFd, events: EventSet) -> Self {
122 Self::with_data_raw(source, 0, events)
123 }
124
125 /// Create an event set associated with the underlying file descriptor of the source, active
126 /// events, and data.
127 ///
128 /// # Arguments
129 /// * source: object that wraps a file descriptor to be associated with `events`
130 /// * data: custom user data associated with the file descriptor; the data can be used for
131 /// uniquely identify monitored events instead of using the file descriptor.
132 /// * events: events to monitor on the provided `source`;
133 /// [`EventSet::ERROR`](struct.EventSet.html#associatedconstant.ERROR) and
134 /// [`EventSet::HANG_UP`](struct.EventSet.html#associatedconstant.HANG_UP) are
135 /// always monitored and don't need to be explicitly added to the list.
136 ///
137 /// # Examples
138 ///
139 /// ```rust
140 /// # use event_manager::{Events, EventSet};
141 /// # use vmm_sys_util::eventfd::EventFd;
142 /// let eventfd = EventFd::new(0).unwrap();
143 /// let event_set = EventSet::IN;
144 /// let custom_data = 42;
145 /// let ev_set = Events::with_data(&eventfd, custom_data, event_set);
146 /// ```
147 pub fn with_data<T: AsRawFd>(source: &T, data: u32, events: EventSet) -> Self {
148 Self::with_data_raw(source.as_raw_fd(), data, events)
149 }
150
151 /// Create an event set associated with the supplied `RawFd` value, active events, and data.
152 ///
153 /// # Arguments
154 /// * source: file descriptor to be associated with `events`
155 /// * data: custom user data associated with the file descriptor; the data can be used for
156 /// uniquely identify monitored events instead of using the file descriptor.
157 /// * events: events to monitor on the provided `source`;
158 /// [`EventSet::ERROR`](struct.EventSet.html#associatedconstant.ERROR) and
159 /// [`EventSet::HANG_UP`](struct.EventSet.html#associatedconstant.HANG_UP) are
160 /// always monitored and don't need to be explicitly added to the list.
161 ///
162 /// # Examples
163 ///
164 /// ```rust
165 /// # use event_manager::{Events, EventSet};
166 /// # use std::os::unix::io::AsRawFd;
167 /// # use vmm_sys_util::eventfd::EventFd;
168 /// let eventfd = EventFd::new(0).unwrap();
169 /// let event_set = EventSet::IN;
170 /// let custom_data = 42;
171 /// let ev_set = Events::with_data_raw(eventfd.as_raw_fd(), custom_data, event_set);
172 /// ```
173 pub fn with_data_raw(source: RawFd, data: u32, events: EventSet) -> Self {
174 let inner_data = ((data as u64) << 32) + (source as u64);
175 Events {
176 inner: EpollEvent::new(events, inner_data),
177 }
178 }
179
180 /// Return the inner fd value.
181 pub fn fd(&self) -> RawFd {
182 self.inner.data() as RawFd
183 }
184
185 /// Return the inner data value.
186 pub fn data(&self) -> u32 {
187 (self.inner.data() >> 32) as u32
188 }
189
190 /// Return the active event set.
191 pub fn event_set(&self) -> EventSet {
192 self.inner.event_set()
193 }
194
195 /// Return the inner `EpollEvent`.
196 pub fn epoll_event(&self) -> EpollEvent {
197 self.inner
198 }
199}
200
201/// Opaque object associated with an `EventSubscriber` that allows the addition, modification, and
202/// removal of events in the watchlist.
203// Right now this is a concrete object, but going further it can be turned into a trait and
204// passed around as a trait object.
205#[derive(Debug)]
206pub struct EventOps<'a> {
207 // Mutable reference to the EpollContext of an EventManager.
208 epoll_wrapper: &'a mut EpollWrapper,
209 // The id of the event subscriber this object stands for.
210 subscriber_id: SubscriberId,
211}
212
213impl<'a> EventOps<'a> {
214 pub(crate) fn new(epoll_wrapper: &'a mut EpollWrapper, subscriber_id: SubscriberId) -> Self {
215 EventOps {
216 epoll_wrapper,
217 subscriber_id,
218 }
219 }
220
221 // Apply the provided control operation for the given events on the inner epoll wrapper.
222 fn ctl(&self, op: ControlOperation, events: Events) -> Result<()> {
223 self.epoll_wrapper
224 .epoll
225 .ctl(op, events.fd(), events.epoll_event())
226 .map_err(|e| Error::Epoll(Errno::from(e)))
227 }
228
229 /// Add the provided events to the inner epoll event set.
230 pub fn add(&mut self, events: Events) -> Result<()> {
231 let fd = events.fd();
232 if self.epoll_wrapper.fd_dispatch.contains_key(&fd) {
233 return Err(Error::FdAlreadyRegistered);
234 }
235
236 self.ctl(ControlOperation::Add, events)?;
237
238 self.epoll_wrapper
239 .fd_dispatch
240 .insert(fd, self.subscriber_id);
241
242 self.epoll_wrapper
243 .subscriber_watch_list
244 .entry(self.subscriber_id)
245 .or_default()
246 .push(fd);
247
248 Ok(())
249 }
250
251 /// Submit the provided changes to the inner epoll event set.
252 pub fn modify(&self, events: Events) -> Result<()> {
253 self.ctl(ControlOperation::Modify, events)
254 }
255
256 /// Remove the specified events from the inner epoll event set.
257 pub fn remove(&mut self, events: Events) -> Result<()> {
258 // TODO: Add some more checks here?
259 self.ctl(ControlOperation::Delete, events)?;
260 self.epoll_wrapper.remove_event(events.fd());
261
262 if let Some(watch_list) = self
263 .epoll_wrapper
264 .subscriber_watch_list
265 .get_mut(&self.subscriber_id)
266 {
267 if let Some(index) = watch_list.iter().position(|&x| x == events.fd()) {
268 watch_list.remove(index);
269 }
270 }
271 Ok(())
272 }
273}
274
275#[cfg(test)]
276mod tests {
277 use super::*;
278
279 use vmm_sys_util::eventfd::EventFd;
280
281 #[test]
282 fn test_empty_events() {
283 let event_fd = EventFd::new(0).unwrap();
284
285 let events_raw = Events::empty_raw(event_fd.as_raw_fd());
286 let events = Events::empty(&event_fd);
287
288 assert_eq!(events, events_raw);
289
290 assert_eq!(events.event_set(), EventSet::empty());
291 assert_eq!(events.data(), 0);
292 assert_eq!(events.fd(), event_fd.as_raw_fd());
293 }
294
295 #[test]
296 fn test_events_no_data() {
297 let event_fd = EventFd::new(0).unwrap();
298 let event_set = EventSet::IN;
299
300 let events_raw = Events::new_raw(event_fd.as_raw_fd(), event_set);
301 let events = Events::new(&event_fd, event_set);
302
303 assert_eq!(events_raw, events);
304
305 assert_eq!(events.data(), 0);
306 assert_eq!(events.fd(), event_fd.as_raw_fd());
307 assert_eq!(events.event_set(), event_set);
308 }
309
310 #[test]
311 fn test_events_data() {
312 let event_fd = EventFd::new(0).unwrap();
313 let event_set = EventSet::IN;
314
315 let events_raw = Events::with_data_raw(event_fd.as_raw_fd(), 42, event_set);
316 let events = Events::with_data(&event_fd, 43, event_set);
317
318 assert_ne!(events_raw, events);
319
320 assert_eq!(events.data(), 43);
321 assert_eq!(events_raw.data(), 42);
322 }
323}