Skip to content

Commit 18bf2a5

Browse files
uran0sHstefano-garzarella
authored andcommitted
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 e869735 commit 18bf2a5

File tree

6 files changed

+70
-59
lines changed

6 files changed

+70
-59
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: 21 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,8 @@ 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+
// TODO: Refine this API to return only EventNotifier.
280+
fn exit_event(&self, _thread_index: usize) -> Option<(EventConsumer, EventNotifier)> {
279281
None
280282
}
281283

@@ -382,7 +384,7 @@ impl<T: VhostUserBackend> VhostUserBackend for Arc<T> {
382384
self.deref().queues_per_thread()
383385
}
384386

385-
fn exit_event(&self, thread_index: usize) -> Option<EventFd> {
387+
fn exit_event(&self, thread_index: usize) -> Option<(EventConsumer, EventNotifier)> {
386388
self.deref().exit_event(thread_index)
387389
}
388390

@@ -471,7 +473,7 @@ impl<T: VhostUserBackendMut> VhostUserBackend for Mutex<T> {
471473
self.lock().unwrap().queues_per_thread()
472474
}
473475

474-
fn exit_event(&self, thread_index: usize) -> Option<EventFd> {
476+
fn exit_event(&self, thread_index: usize) -> Option<(EventConsumer, EventNotifier)> {
475477
self.lock().unwrap().exit_event(thread_index)
476478
}
477479

@@ -563,7 +565,7 @@ impl<T: VhostUserBackendMut> VhostUserBackend for RwLock<T> {
563565
self.read().unwrap().queues_per_thread()
564566
}
565567

566-
fn exit_event(&self, thread_index: usize) -> Option<EventFd> {
568+
fn exit_event(&self, thread_index: usize) -> Option<(EventConsumer, EventNotifier)> {
567569
self.read().unwrap().exit_event(thread_index)
568570
}
569571

@@ -599,16 +601,16 @@ impl<T: VhostUserBackendMut> VhostUserBackend for RwLock<T> {
599601
pub mod tests {
600602
use super::*;
601603
use crate::VringRwLock;
602-
use libc::EFD_NONBLOCK;
603604
use std::sync::Mutex;
604605
use uuid::Uuid;
605606
use vm_memory::{GuestAddress, GuestMemoryAtomic, GuestMemoryMmap};
607+
use vmm_sys_util::event::{new_event_consumer_and_notifier, EventFlag};
606608

607609
pub struct MockVhostBackend {
608610
events: u64,
609611
event_idx: bool,
610612
acked_features: u64,
611-
exit_event_fds: Vec<EventFd>,
613+
exit_event_fds: Vec<(EventConsumer, EventNotifier)>,
612614
}
613615

614616
impl MockVhostBackend {
@@ -624,7 +626,10 @@ pub mod tests {
624626
// order to allow tests maximum flexibility in checking whether
625627
// signals arrived or not.
626628
backend.exit_event_fds = (0..backend.queues_per_thread().len())
627-
.map(|_| EventFd::new(EFD_NONBLOCK).unwrap())
629+
.map(|_| {
630+
new_event_consumer_and_notifier(EventFlag::NONBLOCK)
631+
.expect("Failed to new EventNotifier and EventConsumer")
632+
})
628633
.collect();
629634

630635
backend
@@ -695,13 +700,13 @@ pub mod tests {
695700
vec![1, 1]
696701
}
697702

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-
)
703+
fn exit_event(&self, thread_index: usize) -> Option<(EventConsumer, EventNotifier)> {
704+
self.exit_event_fds.get(thread_index).map(|(s, r)| {
705+
(
706+
s.try_clone().expect("Failed to clone EventConsumer"),
707+
r.try_clone().expect("Failed to clone EventNotifier"),
708+
)
709+
})
705710
}
706711

707712
fn handle_event(

vhost-user-backend/src/event_loop.rs

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@
66
use std::fmt::{Display, Formatter};
77
use std::io::{self, Result};
88
use std::marker::PhantomData;
9+
use std::os::fd::IntoRawFd;
910
use std::os::unix::io::{AsRawFd, RawFd};
1011

1112
use vmm_sys_util::epoll::{ControlOperation, Epoll, EpollEvent, EventSet};
12-
use vmm_sys_util::eventfd::EventFd;
13+
use vmm_sys_util::event::EventNotifier;
1314

1415
use super::backend::VhostUserBackend;
1516
use super::vring::VringT;
@@ -61,15 +62,15 @@ pub struct VringEpollHandler<T: VhostUserBackend> {
6162
backend: T,
6263
vrings: Vec<T::Vring>,
6364
thread_id: usize,
64-
exit_event_fd: Option<EventFd>,
65+
exit_event_fd: Option<EventNotifier>,
6566
phantom: PhantomData<T::Bitmap>,
6667
}
6768

6869
impl<T: VhostUserBackend> VringEpollHandler<T> {
6970
/// Send `exit event` to break the event loop.
7071
pub fn send_exit_event(&self) {
7172
if let Some(eventfd) = self.exit_event_fd.as_ref() {
72-
let _ = eventfd.write(1);
73+
let _ = eventfd.notify();
7374
}
7475
}
7576
}
@@ -87,16 +88,19 @@ where
8788
let epoll = Epoll::new().map_err(VringEpollError::EpollCreateFd)?;
8889
let exit_event_fd = backend.exit_event(thread_id);
8990

90-
if let Some(exit_event_fd) = &exit_event_fd {
91+
let exit_event_fd = if let Some((consumer, notifier)) = exit_event_fd {
9192
let id = backend.num_queues();
9293
epoll
9394
.ctl(
9495
ControlOperation::Add,
95-
exit_event_fd.as_raw_fd(),
96+
consumer.into_raw_fd(),
9697
EpollEvent::new(EventSet::IN, id as u64),
9798
)
9899
.map_err(VringEpollError::RegisterExitEvent)?;
99-
}
100+
Some(notifier)
101+
} else {
102+
None
103+
};
100104

101105
Ok(VringEpollHandler {
102106
epoll,
@@ -230,7 +234,7 @@ mod tests {
230234
use super::*;
231235
use std::sync::{Arc, Mutex};
232236
use vm_memory::{GuestAddress, GuestMemoryAtomic, GuestMemoryMmap};
233-
use vmm_sys_util::eventfd::EventFd;
237+
use vmm_sys_util::event::{new_event_consumer_and_notifier, EventFlag};
234238

235239
#[test]
236240
fn test_vring_epoll_handler() {
@@ -242,29 +246,29 @@ mod tests {
242246

243247
let handler = VringEpollHandler::new(backend, vec![vring], 0x1).unwrap();
244248

245-
let eventfd = EventFd::new(0).unwrap();
249+
let (consumer, _notifier) = new_event_consumer_and_notifier(EventFlag::empty()).unwrap();
246250
handler
247-
.register_listener(eventfd.as_raw_fd(), EventSet::IN, 3)
251+
.register_listener(consumer.as_raw_fd(), EventSet::IN, 3)
248252
.unwrap();
249253
// Register an already registered fd.
250254
handler
251-
.register_listener(eventfd.as_raw_fd(), EventSet::IN, 3)
255+
.register_listener(consumer.as_raw_fd(), EventSet::IN, 3)
252256
.unwrap_err();
253257
// Register an invalid data.
254258
handler
255-
.register_listener(eventfd.as_raw_fd(), EventSet::IN, 1)
259+
.register_listener(consumer.as_raw_fd(), EventSet::IN, 1)
256260
.unwrap_err();
257261

258262
handler
259-
.unregister_listener(eventfd.as_raw_fd(), EventSet::IN, 3)
263+
.unregister_listener(consumer.as_raw_fd(), EventSet::IN, 3)
260264
.unwrap();
261265
// unregister an already unregistered fd.
262266
handler
263-
.unregister_listener(eventfd.as_raw_fd(), EventSet::IN, 3)
267+
.unregister_listener(consumer.as_raw_fd(), EventSet::IN, 3)
264268
.unwrap_err();
265269
// unregister an invalid data.
266270
handler
267-
.unregister_listener(eventfd.as_raw_fd(), EventSet::IN, 1)
271+
.unregister_listener(consumer.as_raw_fd(), EventSet::IN, 1)
268272
.unwrap_err();
269273
// Check we retrieve the correct file descriptor
270274
assert_eq!(handler.as_raw_fd(), handler.epoll.as_raw_fd());

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: 19 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ 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};
1919

2020
/// Trait for objects returned by `VringT::get_ref()`.
2121
pub trait VringStateGuard<'a, M: GuestAddressSpace> {
@@ -109,9 +109,9 @@ pub trait VringT<M: GuestAddressSpace>:
109109
/// object for single-threaded context.
110110
pub struct VringState<M: GuestAddressSpace = GuestMemoryAtomic<GuestMemoryMmap>> {
111111
queue: Queue,
112-
kick: Option<EventFd>,
113-
call: Option<EventFd>,
114-
err: Option<EventFd>,
112+
kick: Option<EventConsumer>,
113+
call: Option<EventNotifier>,
114+
err: Option<EventConsumer>,
115115
enabled: bool,
116116
mem: M,
117117
}
@@ -148,7 +148,7 @@ impl<M: GuestAddressSpace> VringState<M> {
148148
/// Notify the vhost-user frontend that used descriptors have been put into the used queue.
149149
pub fn signal_used_queue(&self) -> io::Result<()> {
150150
if let Some(call) = self.call.as_ref() {
151-
call.write(1)
151+
call.notify()
152152
} else {
153153
Ok(())
154154
}
@@ -227,7 +227,7 @@ impl<M: GuestAddressSpace> VringState<M> {
227227
}
228228

229229
/// Get the `EventFd` for kick.
230-
pub fn get_kick(&self) -> &Option<EventFd> {
230+
pub fn get_kick(&self) -> &Option<EventConsumer> {
231231
&self.kick
232232
}
233233

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

243243
/// Read event from the kick `EventFd`.
244244
fn read_kick(&self) -> io::Result<bool> {
245245
if let Some(kick) = &self.kick {
246-
kick.read()?;
246+
kick.consume()?;
247247
}
248248

249249
Ok(self.enabled)
@@ -252,18 +252,18 @@ impl<M: GuestAddressSpace> VringState<M> {
252252
/// Set `EventFd` for call.
253253
fn set_call(&mut self, file: Option<File>) {
254254
// SAFETY: see comment in set_kick()
255-
self.call = file.map(|f| unsafe { EventFd::from_raw_fd(f.into_raw_fd()) });
255+
self.call = file.map(|f| unsafe { EventNotifier::from_raw_fd(f.into_raw_fd()) });
256256
}
257257

258258
/// Get the `EventFd` for call.
259-
pub fn get_call(&self) -> &Option<EventFd> {
259+
pub fn get_call(&self) -> &Option<EventNotifier> {
260260
&self.call
261261
}
262262

263263
/// Set `EventFd` for err.
264264
fn set_err(&mut self, file: Option<File>) {
265265
// SAFETY: see comment in set_kick()
266-
self.err = file.map(|f| unsafe { EventFd::from_raw_fd(f.into_raw_fd()) });
266+
self.err = file.map(|f| unsafe { EventConsumer::from_raw_fd(f.into_raw_fd()) });
267267
}
268268
}
269269

@@ -500,9 +500,8 @@ impl<M: 'static + GuestAddressSpace> VringT<M> for VringRwLock<M> {
500500
#[cfg(test)]
501501
mod tests {
502502
use super::*;
503-
use std::os::unix::io::AsRawFd;
504503
use vm_memory::bitmap::AtomicBitmap;
505-
use vmm_sys_util::eventfd::EventFd;
504+
use vmm_sys_util::event::{new_event_consumer_and_notifier, EventFlag};
506505

507506
#[test]
508507
fn test_new_vring() {
@@ -549,37 +548,34 @@ mod tests {
549548
vring.set_enabled(true);
550549
assert!(vring.get_ref().enabled);
551550

552-
let eventfd = EventFd::new(0).unwrap();
551+
let (consumer, notifier) = new_event_consumer_and_notifier(EventFlag::empty()).unwrap();
553552
// SAFETY: Safe because we panic before if eventfd is not valid.
554-
let file = unsafe { File::from_raw_fd(eventfd.as_raw_fd()) };
553+
let file = unsafe { File::from_raw_fd(consumer.into_raw_fd()) };
555554
assert!(vring.get_mut().kick.is_none());
556555
assert!(vring.read_kick().unwrap());
557556
vring.set_kick(Some(file));
558-
eventfd.write(1).unwrap();
557+
notifier.notify().unwrap();
559558
assert!(vring.read_kick().unwrap());
560559
assert!(vring.get_ref().kick.is_some());
561560
vring.set_kick(None);
562561
assert!(vring.get_ref().kick.is_none());
563-
std::mem::forget(eventfd);
564562

565-
let eventfd = EventFd::new(0).unwrap();
563+
let (_consumer, notifier) = new_event_consumer_and_notifier(EventFlag::empty()).unwrap();
566564
// SAFETY: Safe because we panic before if eventfd is not valid.
567-
let file = unsafe { File::from_raw_fd(eventfd.as_raw_fd()) };
565+
let file = unsafe { File::from_raw_fd(notifier.into_raw_fd()) };
568566
assert!(vring.get_ref().call.is_none());
569567
vring.set_call(Some(file));
570568
assert!(vring.get_ref().call.is_some());
571569
vring.set_call(None);
572570
assert!(vring.get_ref().call.is_none());
573-
std::mem::forget(eventfd);
574571

575-
let eventfd = EventFd::new(0).unwrap();
572+
let (consumer, _notifier) = new_event_consumer_and_notifier(EventFlag::empty()).unwrap();
576573
// SAFETY: Safe because we panic before if eventfd is not valid.
577-
let file = unsafe { File::from_raw_fd(eventfd.as_raw_fd()) };
574+
let file = unsafe { File::from_raw_fd(consumer.into_raw_fd()) };
578575
assert!(vring.get_ref().err.is_none());
579576
vring.set_err(Some(file));
580577
assert!(vring.get_ref().err.is_some());
581578
vring.set_err(None);
582579
assert!(vring.get_ref().err.is_none());
583-
std::mem::forget(eventfd);
584580
}
585581
}

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

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ use vm_memory::{
1818
FileOffset, GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryAtomic, GuestMemoryMmap,
1919
};
2020
use vmm_sys_util::epoll::EventSet;
21+
use vmm_sys_util::event::{
22+
new_event_consumer_and_notifier, EventConsumer, EventFlag, EventNotifier,
23+
};
2124
use vmm_sys_util::eventfd::EventFd;
2225

2326
struct MockVhostBackend {
@@ -105,10 +108,11 @@ impl VhostUserBackendMut for MockVhostBackend {
105108
vec![1, 1]
106109
}
107110

108-
fn exit_event(&self, _thread_index: usize) -> Option<EventFd> {
109-
let event_fd = EventFd::new(0).unwrap();
110-
111-
Some(event_fd)
111+
fn exit_event(&self, _thread_index: usize) -> Option<(EventConsumer, EventNotifier)> {
112+
Some(
113+
new_event_consumer_and_notifier(EventFlag::empty())
114+
.expect("Failed to create EventConsumer and EventNotifier"),
115+
)
112116
}
113117

114118
fn handle_event(

0 commit comments

Comments
 (0)