Skip to content

Commit 26bb4ce

Browse files
committed
introduce QueueSync
Similar to Queue, QueueSync associates a GuestAddressSpace to a QueueState. The QueueState however is wrapped with reference counting and with a mutex. All access to the QueueSync object has to go through a QueueGuard, which takes care of locking the mutex. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
1 parent 639e289 commit 26bb4ce

File tree

2 files changed

+59
-1
lines changed

2 files changed

+59
-1
lines changed

crates/virtio-queue/src/generic.rs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@
55
use std::num::Wrapping;
66
use std::ops::DerefMut;
77

8-
use crate::{Error, Queue, QueueGuard, QueueState};
8+
use crate::{Error, Queue, QueueGuard, QueueState, QueueSync};
99
use std::sync::atomic::Ordering;
10+
use std::sync::{Arc, Mutex, MutexGuard};
1011
use vm_memory::GuestAddressSpace;
1112

1213
/// Lifetime-generic guard associated to a QueueStateT. In practice,
@@ -174,3 +175,32 @@ impl<M: GuestAddressSpace> QueueT<M> for Queue<M> {
174175
f(self.acquire())
175176
}
176177
}
178+
179+
impl<'g, M: GuestAddressSpace> QueueStateGuard<'g> for QueueSync<M> {
180+
type Out = MutexGuard<'g, QueueState>;
181+
}
182+
183+
impl<M: GuestAddressSpace> QueueT<M> for QueueSync<M> {
184+
type Guard = Self;
185+
186+
fn construct(mem: M, state: QueueState) -> Self {
187+
QueueSync {
188+
mem,
189+
state: Arc::new(Mutex::new(state)),
190+
}
191+
}
192+
fn with<
193+
'a,
194+
'g,
195+
U,
196+
F: FnOnce(QueueGuard<M::T, <Self::Guard as QueueStateGuard<'g>>::Out>) -> U,
197+
>(
198+
&'a mut self,
199+
f: F,
200+
) -> U
201+
where
202+
'a: 'g,
203+
{
204+
f(self.lock())
205+
}
206+
}

crates/virtio-queue/src/lib.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ use std::mem::size_of;
2929
use std::num::Wrapping;
3030
use std::ops::{Deref, DerefMut};
3131
use std::sync::atomic::{fence, Ordering};
32+
use std::sync::{Arc, Mutex, MutexGuard};
3233

3334
use log::error;
3435
use vm_memory::{
@@ -1028,6 +1029,33 @@ impl<M: GuestAddressSpace> Queue<M> {
10281029
}
10291030
}
10301031

1032+
/// A convenient wrapper struct for a thread-safe virtio queue, with associated GuestMemory object.
1033+
#[derive(Clone, Debug)]
1034+
pub struct QueueSync<M: GuestAddressSpace> {
1035+
/// Guest memory object associated with the queue.
1036+
pub mem: M,
1037+
/// Virtio queue state.
1038+
pub state: Arc<Mutex<QueueState>>,
1039+
}
1040+
1041+
impl<M: GuestAddressSpace> QueueSync<M> {
1042+
/// Construct an empty virtio queue with the given `max_size`.
1043+
pub fn new(mem: M, max_size: u16) -> Self {
1044+
QueueSync {
1045+
mem,
1046+
state: Arc::new(Mutex::new(QueueState::new(max_size))),
1047+
}
1048+
}
1049+
1050+
/// Get an exclusive reference to the underlying `QueueState` object.
1051+
///
1052+
/// Logically this method will acquire the underlying lock protecting the `QueueState`
1053+
/// object. The lock will be released when the returned object gets dropped.
1054+
pub fn lock(&self) -> QueueGuard<M::T, MutexGuard<QueueState>> {
1055+
QueueGuard::new(self.mem.memory(), self.state.lock().unwrap())
1056+
}
1057+
}
1058+
10311059
#[cfg(test)]
10321060
mod tests {
10331061
use super::*;

0 commit comments

Comments
 (0)