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}