Skip to content

Commit e117afb

Browse files
Erik Schillingstefano-garzarella
authored andcommitted
vhost-user-backend: simplify the use of generics
In order to allow zero-cost exchanging of the concrete bitmap and vring types, a lot of the generic code required using a tuple of `<VringType, BitmapType>` for parameterizing the impl's. Once code is also oblivious of the concrete backend (and a lot of code is), this tuple turns into a triplet. Juggling these three single letter generic parameters while making sure that all the type constraints (that are also changing depending on the abstraction layer) does not feel very ergonomic. While one can argue that within this crate, this would be fine since people probably know the internals, the design choice is leaking out into every consumer of vhost-user-backend. Instead of just being able to reference "some backend" one needs to copy a lot of boilerplate code for also passing the other type parameters (again, while making sure that all the constraints are met). Instead, this commit changes things to utilize associated types [1]. This makes the Bitmap and Vring types part of the backend trait and requires the implementations to spell them out. Code that just wants to use the backend without needing to know the details can now just use the trait without needing to specify the Bitmap and Vring types again. Where needed, restricting Bitmap and Vring further is still possible (though one no longer needs to copy all the existing restrictions and can keep the code more maintainable by only listing new ones). Overall, my main target was to improve the ergonomics of the consumers of the crate. But I think the change also improves the readability and maintainability within this crate. Combined, this hopefully justifies the small code breakage in consumers. No functional changes intended. No change in type flexibility intended. BREAKING CHANGE, consumers of the lib will need to adjust their code (but it should improve the general readability). Signed-off-by: Erik Schilling <[email protected]> [1] https://doc.rust-lang.org/book/ch19-03-advanced-traits.html#specifying-placeholder-types-in-trait-definitions-with-associated-types
1 parent 1ab08b7 commit e117afb

File tree

6 files changed

+85
-88
lines changed

6 files changed

+85
-88
lines changed

crates/vhost-user-backend/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
### Changed
88
- Change uses of master/slave for frontend/backend in the codebase.
99
- [[#192]](https://github.com/rust-vmm/vhost/pull/192) vhost-user-backend: remove return value from handle_event
10+
- [[#155]](https://github.com/rust-vmm/vhost/pull/155) Converted generic type
11+
parameters of VhostUserBackend into associated types.
1012

1113
### Fixed
1214

crates/vhost-user-backend/src/backend.rs

Lines changed: 34 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,10 @@ use super::GM;
3434
/// Trait with interior mutability for vhost user backend servers to implement concrete services.
3535
///
3636
/// To support multi-threading and asynchronous IO, we enforce `Send + Sync` bound.
37-
pub trait VhostUserBackend<V, B = ()>: Send + Sync
38-
where
39-
V: VringT<GM<B>>,
40-
B: Bitmap + 'static,
41-
{
37+
pub trait VhostUserBackend: Send + Sync {
38+
type Bitmap: Bitmap + 'static;
39+
type Vring: VringT<GM<Self::Bitmap>>;
40+
4241
/// Get number of queues supported.
4342
fn num_queues(&self) -> usize;
4443

@@ -74,7 +73,7 @@ where
7473
}
7574

7675
/// Update guest memory regions.
77-
fn update_memory(&self, mem: GM<B>) -> Result<()>;
76+
fn update_memory(&self, mem: GM<Self::Bitmap>) -> Result<()>;
7877

7978
/// Set handler for communicating with the frontend by the backend communication channel.
8079
///
@@ -108,17 +107,16 @@ where
108107
&self,
109108
device_event: u16,
110109
evset: EventSet,
111-
vrings: &[V],
110+
vrings: &[Self::Vring],
112111
thread_id: usize,
113112
) -> Result<()>;
114113
}
115114

116115
/// Trait without interior mutability for vhost user backend servers to implement concrete services.
117-
pub trait VhostUserBackendMut<V, B = ()>: Send + Sync
118-
where
119-
V: VringT<GM<B>>,
120-
B: Bitmap + 'static,
121-
{
116+
pub trait VhostUserBackendMut: Send + Sync {
117+
type Bitmap: Bitmap + 'static;
118+
type Vring: VringT<GM<Self::Bitmap>>;
119+
122120
/// Get number of queues supported.
123121
fn num_queues(&self) -> usize;
124122

@@ -154,7 +152,7 @@ where
154152
}
155153

156154
/// Update guest memory regions.
157-
fn update_memory(&mut self, mem: GM<B>) -> Result<()>;
155+
fn update_memory(&mut self, mem: GM<Self::Bitmap>) -> Result<()>;
158156

159157
/// Set handler for communicating with the frontend by the backend communication channel.
160158
///
@@ -189,16 +187,15 @@ where
189187
&mut self,
190188
device_event: u16,
191189
evset: EventSet,
192-
vrings: &[V],
190+
vrings: &[Self::Vring],
193191
thread_id: usize,
194192
) -> Result<()>;
195193
}
196194

197-
impl<T: VhostUserBackend<V, B>, V, B> VhostUserBackend<V, B> for Arc<T>
198-
where
199-
V: VringT<GM<B>>,
200-
B: Bitmap + 'static,
201-
{
195+
impl<T: VhostUserBackend> VhostUserBackend for Arc<T> {
196+
type Bitmap = T::Bitmap;
197+
type Vring = T::Vring;
198+
202199
fn num_queues(&self) -> usize {
203200
self.deref().num_queues()
204201
}
@@ -231,7 +228,7 @@ where
231228
self.deref().set_config(offset, buf)
232229
}
233230

234-
fn update_memory(&self, mem: GM<B>) -> Result<()> {
231+
fn update_memory(&self, mem: GM<Self::Bitmap>) -> Result<()> {
235232
self.deref().update_memory(mem)
236233
}
237234

@@ -251,19 +248,18 @@ where
251248
&self,
252249
device_event: u16,
253250
evset: EventSet,
254-
vrings: &[V],
251+
vrings: &[Self::Vring],
255252
thread_id: usize,
256253
) -> Result<()> {
257254
self.deref()
258255
.handle_event(device_event, evset, vrings, thread_id)
259256
}
260257
}
261258

262-
impl<T: VhostUserBackendMut<V, B>, V, B> VhostUserBackend<V, B> for Mutex<T>
263-
where
264-
V: VringT<GM<B>>,
265-
B: Bitmap + 'static,
266-
{
259+
impl<T: VhostUserBackendMut> VhostUserBackend for Mutex<T> {
260+
type Bitmap = T::Bitmap;
261+
type Vring = T::Vring;
262+
267263
fn num_queues(&self) -> usize {
268264
self.lock().unwrap().num_queues()
269265
}
@@ -296,7 +292,7 @@ where
296292
self.lock().unwrap().set_config(offset, buf)
297293
}
298294

299-
fn update_memory(&self, mem: GM<B>) -> Result<()> {
295+
fn update_memory(&self, mem: GM<Self::Bitmap>) -> Result<()> {
300296
self.lock().unwrap().update_memory(mem)
301297
}
302298

@@ -316,7 +312,7 @@ where
316312
&self,
317313
device_event: u16,
318314
evset: EventSet,
319-
vrings: &[V],
315+
vrings: &[Self::Vring],
320316
thread_id: usize,
321317
) -> Result<()> {
322318
self.lock()
@@ -325,11 +321,10 @@ where
325321
}
326322
}
327323

328-
impl<T: VhostUserBackendMut<V, B>, V, B> VhostUserBackend<V, B> for RwLock<T>
329-
where
330-
V: VringT<GM<B>>,
331-
B: Bitmap + 'static,
332-
{
324+
impl<T: VhostUserBackendMut> VhostUserBackend for RwLock<T> {
325+
type Bitmap = T::Bitmap;
326+
type Vring = T::Vring;
327+
333328
fn num_queues(&self) -> usize {
334329
self.read().unwrap().num_queues()
335330
}
@@ -362,7 +357,7 @@ where
362357
self.write().unwrap().set_config(offset, buf)
363358
}
364359

365-
fn update_memory(&self, mem: GM<B>) -> Result<()> {
360+
fn update_memory(&self, mem: GM<Self::Bitmap>) -> Result<()> {
366361
self.write().unwrap().update_memory(mem)
367362
}
368363

@@ -382,7 +377,7 @@ where
382377
&self,
383378
device_event: u16,
384379
evset: EventSet,
385-
vrings: &[V],
380+
vrings: &[Self::Vring],
386381
thread_id: usize,
387382
) -> Result<()> {
388383
self.write()
@@ -426,7 +421,10 @@ pub mod tests {
426421
}
427422
}
428423

429-
impl VhostUserBackendMut<VringRwLock, ()> for MockVhostBackend {
424+
impl VhostUserBackendMut for MockVhostBackend {
425+
type Bitmap = ();
426+
type Vring = VringRwLock;
427+
430428
fn num_queues(&self) -> usize {
431429
2
432430
}

crates/vhost-user-backend/src/event_loop.rs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,11 @@ use std::io::{self, Result};
88
use std::marker::PhantomData;
99
use std::os::unix::io::{AsRawFd, RawFd};
1010

11-
use vm_memory::bitmap::Bitmap;
1211
use vmm_sys_util::epoll::{ControlOperation, Epoll, EpollEvent, EventSet};
1312
use vmm_sys_util::eventfd::EventFd;
1413

1514
use super::backend::VhostUserBackend;
1615
use super::vring::VringT;
17-
use super::GM;
1816

1917
/// Errors related to vring epoll event handling.
2018
#[derive(Debug)]
@@ -58,16 +56,16 @@ pub type VringEpollResult<T> = std::result::Result<T, VringEpollError>;
5856
/// - add file descriptors to be monitored by the epoll fd
5957
/// - remove registered file descriptors from the epoll fd
6058
/// - run the event loop to handle pending events on the epoll fd
61-
pub struct VringEpollHandler<S, V, B> {
59+
pub struct VringEpollHandler<T: VhostUserBackend> {
6260
epoll: Epoll,
63-
backend: S,
64-
vrings: Vec<V>,
61+
backend: T,
62+
vrings: Vec<T::Vring>,
6563
thread_id: usize,
6664
exit_event_fd: Option<EventFd>,
67-
phantom: PhantomData<B>,
65+
phantom: PhantomData<T::Bitmap>,
6866
}
6967

70-
impl<S, V, B> VringEpollHandler<S, V, B> {
68+
impl<T: VhostUserBackend> VringEpollHandler<T> {
7169
/// Send `exit event` to break the event loop.
7270
pub fn send_exit_event(&self) {
7371
if let Some(eventfd) = self.exit_event_fd.as_ref() {
@@ -76,14 +74,16 @@ impl<S, V, B> VringEpollHandler<S, V, B> {
7674
}
7775
}
7876

79-
impl<S, V, B> VringEpollHandler<S, V, B>
77+
impl<T> VringEpollHandler<T>
8078
where
81-
S: VhostUserBackend<V, B>,
82-
V: VringT<GM<B>>,
83-
B: Bitmap + 'static,
79+
T: VhostUserBackend,
8480
{
8581
/// Create a `VringEpollHandler` instance.
86-
pub(crate) fn new(backend: S, vrings: Vec<V>, thread_id: usize) -> VringEpollResult<Self> {
82+
pub(crate) fn new(
83+
backend: T,
84+
vrings: Vec<T::Vring>,
85+
thread_id: usize,
86+
) -> VringEpollResult<Self> {
8787
let epoll = Epoll::new().map_err(VringEpollError::EpollCreateFd)?;
8888
let exit_event_fd = backend.exit_event(thread_id);
8989

@@ -217,7 +217,7 @@ where
217217
}
218218
}
219219

220-
impl<S, V, B> AsRawFd for VringEpollHandler<S, V, B> {
220+
impl<T: VhostUserBackend> AsRawFd for VringEpollHandler<T> {
221221
fn as_raw_fd(&self) -> RawFd {
222222
self.epoll.as_raw_fd()
223223
}

crates/vhost-user-backend/src/handler.rs

Lines changed: 20 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ use vhost::vhost_user::{
2020
};
2121
use virtio_bindings::bindings::virtio_ring::VIRTIO_RING_F_EVENT_IDX;
2222
use virtio_queue::{Error as VirtQueError, QueueT};
23-
use vm_memory::bitmap::Bitmap;
2423
use vm_memory::mmap::NewBitmap;
2524
use vm_memory::{GuestAddress, GuestAddressSpace, GuestMemoryMmap, GuestRegionMmap};
2625
use vmm_sys_util::epoll::EventSet;
@@ -74,9 +73,9 @@ struct AddrMapping {
7473
gpa_base: u64,
7574
}
7675

77-
pub struct VhostUserHandler<S, V, B: Bitmap + 'static> {
78-
backend: S,
79-
handlers: Vec<Arc<VringEpollHandler<S, V, B>>>,
76+
pub struct VhostUserHandler<T: VhostUserBackend> {
77+
backend: T,
78+
handlers: Vec<Arc<VringEpollHandler<T>>>,
8079
owned: bool,
8180
features_acked: bool,
8281
acked_features: u64,
@@ -85,26 +84,26 @@ pub struct VhostUserHandler<S, V, B: Bitmap + 'static> {
8584
max_queue_size: usize,
8685
queues_per_thread: Vec<u64>,
8786
mappings: Vec<AddrMapping>,
88-
atomic_mem: GM<B>,
89-
vrings: Vec<V>,
87+
atomic_mem: GM<T::Bitmap>,
88+
vrings: Vec<T::Vring>,
9089
worker_threads: Vec<thread::JoinHandle<VringEpollResult<()>>>,
9190
}
9291

9392
// Ensure VhostUserHandler: Clone + Send + Sync + 'static.
94-
impl<S, V, B> VhostUserHandler<S, V, B>
93+
impl<T> VhostUserHandler<T>
9594
where
96-
S: VhostUserBackend<V, B> + Clone + 'static,
97-
V: VringT<GM<B>> + Clone + Send + Sync + 'static,
98-
B: Bitmap + Clone + Send + Sync + 'static,
95+
T: VhostUserBackend + Clone + 'static,
96+
T::Vring: Clone + Send + Sync + 'static,
97+
T::Bitmap: Clone + Send + Sync + 'static,
9998
{
100-
pub(crate) fn new(backend: S, atomic_mem: GM<B>) -> VhostUserHandlerResult<Self> {
99+
pub(crate) fn new(backend: T, atomic_mem: GM<T::Bitmap>) -> VhostUserHandlerResult<Self> {
101100
let num_queues = backend.num_queues();
102101
let max_queue_size = backend.max_queue_size();
103102
let queues_per_thread = backend.queues_per_thread();
104103

105104
let mut vrings = Vec::new();
106105
for _ in 0..num_queues {
107-
let vring = V::new(atomic_mem.clone(), max_queue_size as u16)
106+
let vring = T::Vring::new(atomic_mem.clone(), max_queue_size as u16)
108107
.map_err(VhostUserHandlerError::CreateVring)?;
109108
vrings.push(vring);
110109
}
@@ -151,7 +150,7 @@ where
151150
}
152151
}
153152

154-
impl<S, V, B: Bitmap> VhostUserHandler<S, V, B> {
153+
impl<T: VhostUserBackend> VhostUserHandler<T> {
155154
pub(crate) fn send_exit_event(&self) {
156155
for handler in self.handlers.iter() {
157156
handler.send_exit_event();
@@ -169,25 +168,23 @@ impl<S, V, B: Bitmap> VhostUserHandler<S, V, B> {
169168
}
170169
}
171170

172-
impl<S, V, B> VhostUserHandler<S, V, B>
171+
impl<T> VhostUserHandler<T>
173172
where
174-
S: VhostUserBackend<V, B>,
175-
V: VringT<GM<B>>,
176-
B: Bitmap,
173+
T: VhostUserBackend,
177174
{
178-
pub(crate) fn get_epoll_handlers(&self) -> Vec<Arc<VringEpollHandler<S, V, B>>> {
175+
pub(crate) fn get_epoll_handlers(&self) -> Vec<Arc<VringEpollHandler<T>>> {
179176
self.handlers.clone()
180177
}
181178

182-
fn vring_needs_init(&self, vring: &V) -> bool {
179+
fn vring_needs_init(&self, vring: &T::Vring) -> bool {
183180
let vring_state = vring.get_ref();
184181

185182
// If the vring wasn't initialized and we already have an EventFd for
186183
// VRING_KICK, initialize it now.
187184
!vring_state.get_queue().ready() && vring_state.get_kick().is_some()
188185
}
189186

190-
fn initialize_vring(&self, vring: &V, index: u8) -> VhostUserResult<()> {
187+
fn initialize_vring(&self, vring: &T::Vring, index: u8) -> VhostUserResult<()> {
191188
assert!(vring.get_ref().get_kick().is_some());
192189

193190
if let Some(fd) = vring.get_ref().get_kick() {
@@ -218,11 +215,9 @@ where
218215
}
219216
}
220217

221-
impl<S, V, B> VhostUserBackendReqHandlerMut for VhostUserHandler<S, V, B>
218+
impl<T: VhostUserBackend> VhostUserBackendReqHandlerMut for VhostUserHandler<T>
222219
where
223-
S: VhostUserBackend<V, B>,
224-
V: VringT<GM<B>>,
225-
B: NewBitmap + Clone,
220+
T::Bitmap: NewBitmap + Clone,
226221
{
227222
fn set_owner(&mut self) -> VhostUserResult<()> {
228223
if self.owned {
@@ -604,7 +599,7 @@ where
604599
}
605600
}
606601

607-
impl<S, V, B: Bitmap> Drop for VhostUserHandler<S, V, B> {
602+
impl<T: VhostUserBackend> Drop for VhostUserHandler<T> {
608603
fn drop(&mut self) {
609604
// Signal all working threads to exit.
610605
self.send_exit_event();

0 commit comments

Comments
 (0)