1use std::fmt::{Display, Formatter};
7use std::io::{self, Result};
8use std::marker::PhantomData;
9use std::os::unix::io::{AsRawFd, RawFd};
10
11use vmm_sys_util::epoll::{ControlOperation, Epoll, EpollEvent, EventSet};
12use vmm_sys_util::eventfd::EventFd;
13
14use super::backend::VhostUserBackend;
15use super::vring::VringT;
16
17#[derive(Debug)]
19pub enum VringEpollError {
20 EpollCreateFd(io::Error),
22 EpollWait(io::Error),
24 RegisterExitEvent(io::Error),
26 HandleEventReadKick(io::Error),
28 HandleEventBackendHandling(io::Error),
30}
31
32impl Display for VringEpollError {
33 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
34 match self {
35 VringEpollError::EpollCreateFd(e) => write!(f, "cannot create epoll fd: {}", e),
36 VringEpollError::EpollWait(e) => write!(f, "failed to wait for epoll event: {}", e),
37 VringEpollError::RegisterExitEvent(e) => write!(f, "cannot register exit event: {}", e),
38 VringEpollError::HandleEventReadKick(e) => {
39 write!(f, "cannot read vring kick event: {}", e)
40 }
41 VringEpollError::HandleEventBackendHandling(e) => {
42 write!(f, "failed to handle epoll event: {}", e)
43 }
44 }
45 }
46}
47
48impl std::error::Error for VringEpollError {}
49
50pub type VringEpollResult<T> = std::result::Result<T, VringEpollError>;
52
53pub struct VringEpollHandler<T: VhostUserBackend> {
60 epoll: Epoll,
61 backend: T,
62 vrings: Vec<T::Vring>,
63 thread_id: usize,
64 exit_event_fd: Option<EventFd>,
65 phantom: PhantomData<T::Bitmap>,
66}
67
68impl<T: VhostUserBackend> VringEpollHandler<T> {
69 pub fn send_exit_event(&self) {
71 if let Some(eventfd) = self.exit_event_fd.as_ref() {
72 let _ = eventfd.write(1);
73 }
74 }
75}
76
77impl<T> VringEpollHandler<T>
78where
79 T: VhostUserBackend,
80{
81 pub(crate) fn new(
83 backend: T,
84 vrings: Vec<T::Vring>,
85 thread_id: usize,
86 ) -> VringEpollResult<Self> {
87 let epoll = Epoll::new().map_err(VringEpollError::EpollCreateFd)?;
88 let exit_event_fd = backend.exit_event(thread_id);
89
90 if let Some(exit_event_fd) = &exit_event_fd {
91 let id = backend.num_queues();
92 epoll
93 .ctl(
94 ControlOperation::Add,
95 exit_event_fd.as_raw_fd(),
96 EpollEvent::new(EventSet::IN, id as u64),
97 )
98 .map_err(VringEpollError::RegisterExitEvent)?;
99 }
100
101 Ok(VringEpollHandler {
102 epoll,
103 backend,
104 vrings,
105 thread_id,
106 exit_event_fd,
107 phantom: PhantomData,
108 })
109 }
110
111 pub fn register_listener(&self, fd: RawFd, ev_type: EventSet, data: u64) -> Result<()> {
116 if data <= self.backend.num_queues() as u64 {
118 Err(io::Error::from_raw_os_error(libc::EINVAL))
119 } else {
120 self.register_event(fd, ev_type, data)
121 }
122 }
123
124 pub fn unregister_listener(&self, fd: RawFd, ev_type: EventSet, data: u64) -> Result<()> {
129 if data <= self.backend.num_queues() as u64 {
131 Err(io::Error::from_raw_os_error(libc::EINVAL))
132 } else {
133 self.unregister_event(fd, ev_type, data)
134 }
135 }
136
137 pub(crate) fn register_event(&self, fd: RawFd, ev_type: EventSet, data: u64) -> Result<()> {
138 self.epoll
139 .ctl(ControlOperation::Add, fd, EpollEvent::new(ev_type, data))
140 }
141
142 pub(crate) fn unregister_event(&self, fd: RawFd, ev_type: EventSet, data: u64) -> Result<()> {
143 self.epoll
144 .ctl(ControlOperation::Delete, fd, EpollEvent::new(ev_type, data))
145 }
146
147 pub(crate) fn run(&self) -> VringEpollResult<()> {
152 const EPOLL_EVENTS_LEN: usize = 100;
153 let mut events = vec![EpollEvent::new(EventSet::empty(), 0); EPOLL_EVENTS_LEN];
154
155 'epoll: loop {
156 let num_events = match self.epoll.wait(-1, &mut events[..]) {
157 Ok(res) => res,
158 Err(e) => {
159 if e.kind() == io::ErrorKind::Interrupted {
160 continue;
168 }
169 return Err(VringEpollError::EpollWait(e));
170 }
171 };
172
173 for event in events.iter().take(num_events) {
174 let evset = match EventSet::from_bits(event.events) {
175 Some(evset) => evset,
176 None => {
177 let evbits = event.events;
178 println!("epoll: ignoring unknown event set: 0x{:x}", evbits);
179 continue;
180 }
181 };
182
183 let ev_type = event.data() as u16;
184
185 if self.handle_event(ev_type, evset)? {
187 break 'epoll;
188 }
189 }
190 }
191
192 Ok(())
193 }
194
195 fn handle_event(&self, device_event: u16, evset: EventSet) -> VringEpollResult<bool> {
196 if self.exit_event_fd.is_some() && device_event as usize == self.backend.num_queues() {
197 return Ok(true);
198 }
199
200 if (device_event as usize) < self.vrings.len() {
201 let vring = &self.vrings[device_event as usize];
202 let enabled = vring
203 .read_kick()
204 .map_err(VringEpollError::HandleEventReadKick)?;
205
206 if !enabled {
208 return Ok(false);
209 }
210 }
211
212 self.backend
213 .handle_event(device_event, evset, &self.vrings, self.thread_id)
214 .map_err(VringEpollError::HandleEventBackendHandling)?;
215
216 Ok(false)
217 }
218}
219
220impl<T: VhostUserBackend> AsRawFd for VringEpollHandler<T> {
221 fn as_raw_fd(&self) -> RawFd {
222 self.epoll.as_raw_fd()
223 }
224}
225
226#[cfg(test)]
227mod tests {
228 use super::super::backend::tests::MockVhostBackend;
229 use super::super::vring::VringRwLock;
230 use super::*;
231 use std::sync::{Arc, Mutex};
232 use vm_memory::{GuestAddress, GuestMemoryAtomic, GuestMemoryMmap};
233 use vmm_sys_util::eventfd::EventFd;
234
235 #[test]
236 fn test_vring_epoll_handler() {
237 let mem = GuestMemoryAtomic::new(
238 GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0x100000), 0x10000)]).unwrap(),
239 );
240 let vring = VringRwLock::new(mem, 0x1000).unwrap();
241 let backend = Arc::new(Mutex::new(MockVhostBackend::new()));
242
243 let handler = VringEpollHandler::new(backend, vec![vring], 0x1).unwrap();
244
245 let eventfd = EventFd::new(0).unwrap();
246 handler
247 .register_listener(eventfd.as_raw_fd(), EventSet::IN, 3)
248 .unwrap();
249 handler
251 .register_listener(eventfd.as_raw_fd(), EventSet::IN, 3)
252 .unwrap_err();
253 handler
255 .register_listener(eventfd.as_raw_fd(), EventSet::IN, 1)
256 .unwrap_err();
257
258 handler
259 .unregister_listener(eventfd.as_raw_fd(), EventSet::IN, 3)
260 .unwrap();
261 handler
263 .unregister_listener(eventfd.as_raw_fd(), EventSet::IN, 3)
264 .unwrap_err();
265 handler
267 .unregister_listener(eventfd.as_raw_fd(), EventSet::IN, 1)
268 .unwrap_err();
269 assert_eq!(handler.as_raw_fd(), handler.epoll.as_raw_fd());
271 }
272}