Skip to content

Commit 6cad55f

Browse files
committed
Replace Eventfd with EventNotifier/EventConsumer
Eventfd is Linux-specific. To support more platforms, we replace it with the EventNotifier/EventConsumer abstractions. EventSender and EventReceiver are wrappers that encapsulate eventfd functionality Use pipefd to replace eventfd in the test. Signed-off-by: Wenyu Huang <[email protected]>
1 parent 9e07a95 commit 6cad55f

File tree

6 files changed

+66
-38
lines changed

6 files changed

+66
-38
lines changed

vhost-user-backend/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
### Added
66
### Changed
7+
- [[#308](https://github.com/rust-vmm/vhost/pull/308)] Replace Eventfd with EventNotifier/EventConsumer.
8+
79
### Deprecated
810
### Fixed
911

vhost-user-backend/src/backend.rs

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use vhost::vhost_user::message::{
3030
use vhost::vhost_user::Backend;
3131
use vm_memory::bitmap::Bitmap;
3232
use vmm_sys_util::epoll::EventSet;
33-
use vmm_sys_util::eventfd::EventFd;
33+
use vmm_sys_util::event::{EventConsumer, EventNotifier};
3434

3535
use vhost::vhost_user::GpuBackend;
3636

@@ -132,7 +132,8 @@ pub trait VhostUserBackend: Send + Sync {
132132
///
133133
/// The returned `EventFd` will be monitored for IO events. When the
134134
/// returned EventFd is written to, the worker thread will exit.
135-
fn exit_event(&self, _thread_index: usize) -> Option<EventFd> {
135+
/// TODO: Refine this API to return only EventNotifier.
136+
fn exit_event(&self, _thread_index: usize) -> Option<(EventConsumer, EventNotifier)> {
136137
None
137138
}
138139

@@ -275,7 +276,7 @@ pub trait VhostUserBackendMut: Send + Sync {
275276
/// If an (`EventFd`, `token`) pair is returned, the returned `EventFd` will be monitored for IO
276277
/// events by using epoll with the specified `token`. When the returned EventFd is written to,
277278
/// the worker thread will exit.
278-
fn exit_event(&self, _thread_index: usize) -> Option<EventFd> {
279+
fn exit_event(&self, _thread_index: usize) -> Option<(EventConsumer, EventNotifier)> {
279280
None
280281
}
281282

@@ -382,7 +383,7 @@ impl<T: VhostUserBackend> VhostUserBackend for Arc<T> {
382383
self.deref().queues_per_thread()
383384
}
384385

385-
fn exit_event(&self, thread_index: usize) -> Option<EventFd> {
386+
fn exit_event(&self, thread_index: usize) -> Option<(EventConsumer, EventNotifier)> {
386387
self.deref().exit_event(thread_index)
387388
}
388389

@@ -471,7 +472,7 @@ impl<T: VhostUserBackendMut> VhostUserBackend for Mutex<T> {
471472
self.lock().unwrap().queues_per_thread()
472473
}
473474

474-
fn exit_event(&self, thread_index: usize) -> Option<EventFd> {
475+
fn exit_event(&self, thread_index: usize) -> Option<(EventConsumer, EventNotifier)> {
475476
self.lock().unwrap().exit_event(thread_index)
476477
}
477478

@@ -563,7 +564,7 @@ impl<T: VhostUserBackendMut> VhostUserBackend for RwLock<T> {
563564
self.read().unwrap().queues_per_thread()
564565
}
565566

566-
fn exit_event(&self, thread_index: usize) -> Option<EventFd> {
567+
fn exit_event(&self, thread_index: usize) -> Option<(EventConsumer, EventNotifier)> {
567568
self.read().unwrap().exit_event(thread_index)
568569
}
569570

@@ -600,15 +601,18 @@ pub mod tests {
600601
use super::*;
601602
use crate::VringRwLock;
602603
use libc::EFD_NONBLOCK;
603-
use std::sync::Mutex;
604+
use std::{
605+
os::fd::{AsRawFd, FromRawFd, IntoRawFd},
606+
sync::Mutex,
607+
};
604608
use uuid::Uuid;
605609
use vm_memory::{GuestAddress, GuestMemoryAtomic, GuestMemoryMmap};
606610

607611
pub struct MockVhostBackend {
608612
events: u64,
609613
event_idx: bool,
610614
acked_features: u64,
611-
exit_event_fds: Vec<EventFd>,
615+
exit_event_fds: Vec<(EventConsumer, EventNotifier)>,
612616
}
613617

614618
impl MockVhostBackend {
@@ -624,7 +628,21 @@ pub mod tests {
624628
// order to allow tests maximum flexibility in checking whether
625629
// signals arrived or not.
626630
backend.exit_event_fds = (0..backend.queues_per_thread().len())
627-
.map(|_| EventFd::new(EFD_NONBLOCK).unwrap())
631+
.map(|_| unsafe {
632+
let (reader, writer) = std::io::pipe().expect("Failed to create pipe");
633+
let flags = libc::fcntl(reader.as_raw_fd(), libc::F_GETFL);
634+
let ret = libc::fcntl(reader.as_raw_fd(), libc::F_SETFL, flags | EFD_NONBLOCK);
635+
if ret < 0 {
636+
panic!(
637+
"Failed to set pipe to non-blocking: {}",
638+
std::io::Error::last_os_error()
639+
);
640+
}
641+
(
642+
EventConsumer::from_raw_fd(reader.into_raw_fd()),
643+
EventNotifier::from_raw_fd(writer.into_raw_fd()),
644+
)
645+
})
628646
.collect();
629647

630648
backend
@@ -695,13 +713,13 @@ pub mod tests {
695713
vec![1, 1]
696714
}
697715

698-
fn exit_event(&self, thread_index: usize) -> Option<EventFd> {
699-
Some(
700-
self.exit_event_fds
701-
.get(thread_index)?
702-
.try_clone()
703-
.expect("Could not clone exit eventfd"),
704-
)
716+
fn exit_event(&self, thread_index: usize) -> Option<(EventConsumer, EventNotifier)> {
717+
self.exit_event_fds.get(thread_index).map(|(s, r)| {
718+
(
719+
s.try_clone().expect("Failed to clone EventConsumer"),
720+
r.try_clone().expect("Failed to clone EventNotifier"),
721+
)
722+
})
705723
}
706724

707725
fn handle_event(

vhost-user-backend/src/event_loop.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use std::marker::PhantomData;
99
use std::os::unix::io::{AsRawFd, RawFd};
1010

1111
use vmm_sys_util::epoll::{ControlOperation, Epoll, EpollEvent, EventSet};
12-
use vmm_sys_util::eventfd::EventFd;
12+
use vmm_sys_util::event::EventNotifier;
1313

1414
use super::backend::VhostUserBackend;
1515
use super::vring::VringT;
@@ -61,15 +61,15 @@ pub struct VringEpollHandler<T: VhostUserBackend> {
6161
backend: T,
6262
vrings: Vec<T::Vring>,
6363
thread_id: usize,
64-
exit_event_fd: Option<EventFd>,
64+
exit_event_fd: Option<EventNotifier>,
6565
phantom: PhantomData<T::Bitmap>,
6666
}
6767

6868
impl<T: VhostUserBackend> VringEpollHandler<T> {
6969
/// Send `exit event` to break the event loop.
7070
pub fn send_exit_event(&self) {
7171
if let Some(eventfd) = self.exit_event_fd.as_ref() {
72-
let _ = eventfd.write(1);
72+
let _ = eventfd.notify();
7373
}
7474
}
7575
}
@@ -87,12 +87,12 @@ where
8787
let epoll = Epoll::new().map_err(VringEpollError::EpollCreateFd)?;
8888
let exit_event_fd = backend.exit_event(thread_id);
8989

90-
if let Some(exit_event_fd) = &exit_event_fd {
90+
if let Some((consumer, _)) = &exit_event_fd {
9191
let id = backend.num_queues();
9292
epoll
9393
.ctl(
9494
ControlOperation::Add,
95-
exit_event_fd.as_raw_fd(),
95+
consumer.as_raw_fd(),
9696
EpollEvent::new(EventSet::IN, id as u64),
9797
)
9898
.map_err(VringEpollError::RegisterExitEvent)?;
@@ -103,7 +103,7 @@ where
103103
backend,
104104
vrings,
105105
thread_id,
106-
exit_event_fd,
106+
exit_event_fd: exit_event_fd.map(|(_, notifier)| notifier),
107107
phantom: PhantomData,
108108
})
109109
}

vhost-user-backend/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,7 @@ mod tests {
350350
let fd = backend.exit_event(thread_id).unwrap();
351351
// Reading from exit fd should fail since nothing was written yet
352352
assert_eq!(
353-
fd.read().unwrap_err().raw_os_error().unwrap(),
353+
fd.0.consume().unwrap_err().raw_os_error().unwrap(),
354354
EAGAIN,
355355
"exit event should not have been raised yet!"
356356
);
@@ -365,7 +365,7 @@ mod tests {
365365
let backend = backend.lock().unwrap();
366366
for thread_id in 0..backend.queues_per_thread().len() {
367367
let fd = backend.exit_event(thread_id).unwrap();
368-
assert!(fd.read().is_ok(), "No exit event was raised!");
368+
assert!(fd.0.consume().is_ok(), "No exit event was raised!");
369369
}
370370
}
371371
}

vhost-user-backend/src/vring.rs

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ use std::sync::{Arc, Mutex, MutexGuard, RwLock, RwLockReadGuard, RwLockWriteGuar
1515

1616
use virtio_queue::{Error as VirtQueError, Queue, QueueT};
1717
use vm_memory::{GuestAddress, GuestAddressSpace, GuestMemoryAtomic, GuestMemoryMmap};
18-
use vmm_sys_util::eventfd::EventFd;
18+
use vmm_sys_util::event::{EventConsumer, EventNotifier};
19+
// use vmm_sys_util::eventfd::EventFd;
1920

2021
/// Trait for objects returned by `VringT::get_ref()`.
2122
pub trait VringStateGuard<'a, M: GuestAddressSpace> {
@@ -109,9 +110,9 @@ pub trait VringT<M: GuestAddressSpace>:
109110
/// object for single-threaded context.
110111
pub struct VringState<M: GuestAddressSpace = GuestMemoryAtomic<GuestMemoryMmap>> {
111112
queue: Queue,
112-
kick: Option<EventFd>,
113-
call: Option<EventFd>,
114-
err: Option<EventFd>,
113+
kick: Option<EventConsumer>,
114+
call: Option<EventNotifier>,
115+
err: Option<EventConsumer>,
115116
enabled: bool,
116117
mem: M,
117118
}
@@ -148,7 +149,7 @@ impl<M: GuestAddressSpace> VringState<M> {
148149
/// Notify the vhost-user frontend that used descriptors have been put into the used queue.
149150
pub fn signal_used_queue(&self) -> io::Result<()> {
150151
if let Some(call) = self.call.as_ref() {
151-
call.write(1)
152+
call.notify()
152153
} else {
153154
Ok(())
154155
}
@@ -227,7 +228,7 @@ impl<M: GuestAddressSpace> VringState<M> {
227228
}
228229

229230
/// Get the `EventFd` for kick.
230-
pub fn get_kick(&self) -> &Option<EventFd> {
231+
pub fn get_kick(&self) -> &Option<EventConsumer> {
231232
&self.kick
232233
}
233234

@@ -237,13 +238,13 @@ impl<M: GuestAddressSpace> VringState<M> {
237238
// EventFd requires that it has sole ownership of its fd. So does File, so this is safe.
238239
// Ideally, we'd have a generic way to refer to a uniquely-owned fd, such as that proposed
239240
// by Rust RFC #3128.
240-
self.kick = file.map(|f| unsafe { EventFd::from_raw_fd(f.into_raw_fd()) });
241+
self.kick = file.map(|f| unsafe { EventConsumer::from_raw_fd(f.into_raw_fd()) });
241242
}
242243

243244
/// Read event from the kick `EventFd`.
244245
fn read_kick(&self) -> io::Result<bool> {
245246
if let Some(kick) = &self.kick {
246-
kick.read()?;
247+
kick.consume()?;
247248
}
248249

249250
Ok(self.enabled)
@@ -252,18 +253,18 @@ impl<M: GuestAddressSpace> VringState<M> {
252253
/// Set `EventFd` for call.
253254
fn set_call(&mut self, file: Option<File>) {
254255
// SAFETY: see comment in set_kick()
255-
self.call = file.map(|f| unsafe { EventFd::from_raw_fd(f.into_raw_fd()) });
256+
self.call = file.map(|f| unsafe { EventNotifier::from_raw_fd(f.into_raw_fd()) });
256257
}
257258

258259
/// Get the `EventFd` for call.
259-
pub fn get_call(&self) -> &Option<EventFd> {
260+
pub fn get_call(&self) -> &Option<EventNotifier> {
260261
&self.call
261262
}
262263

263264
/// Set `EventFd` for err.
264265
fn set_err(&mut self, file: Option<File>) {
265266
// SAFETY: see comment in set_kick()
266-
self.err = file.map(|f| unsafe { EventFd::from_raw_fd(f.into_raw_fd()) });
267+
self.err = file.map(|f| unsafe { EventConsumer::from_raw_fd(f.into_raw_fd()) });
267268
}
268269
}
269270

vhost-user-backend/tests/vhost-user-server.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::fs::File;
22
use std::io::Result;
3+
use std::os::fd::{FromRawFd, IntoRawFd};
34
use std::os::unix::io::AsRawFd;
45
use std::os::unix::net::UnixStream;
56
use std::path::Path;
@@ -18,6 +19,7 @@ use vm_memory::{
1819
FileOffset, GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryAtomic, GuestMemoryMmap,
1920
};
2021
use vmm_sys_util::epoll::EventSet;
22+
use vmm_sys_util::event::{EventConsumer, EventNotifier};
2123
use vmm_sys_util::eventfd::EventFd;
2224

2325
struct MockVhostBackend {
@@ -105,10 +107,15 @@ impl VhostUserBackendMut for MockVhostBackend {
105107
vec![1, 1]
106108
}
107109

108-
fn exit_event(&self, _thread_index: usize) -> Option<EventFd> {
109-
let event_fd = EventFd::new(0).unwrap();
110+
fn exit_event(&self, _thread_index: usize) -> Option<(EventConsumer, EventNotifier)> {
111+
let (reader, writer) = std::io::pipe().expect("Failed to create pipe");
110112

111-
Some(event_fd)
113+
Some(unsafe {
114+
(
115+
EventConsumer::from_raw_fd(reader.into_raw_fd()),
116+
EventNotifier::from_raw_fd(writer.into_raw_fd()),
117+
)
118+
})
112119
}
113120

114121
fn handle_event(

0 commit comments

Comments
 (0)