Skip to content

Commit bc7569d

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 10306e5 commit bc7569d

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,
@@ -167,3 +168,32 @@ impl<M: GuestAddressSpace> QueueT<M> for Queue<M> {
167168
f(self.acquire())
168169
}
169170
}
171+
172+
impl<'g, M: GuestAddressSpace> QueueStateGuard<'g> for QueueSync<M> {
173+
type Out = MutexGuard<'g, QueueState>;
174+
}
175+
176+
impl<M: GuestAddressSpace> QueueT<M> for QueueSync<M> {
177+
type Guard = Self;
178+
179+
fn construct(mem: M, state: QueueState) -> Self {
180+
QueueSync {
181+
mem,
182+
state: Arc::new(Mutex::new(state)),
183+
}
184+
}
185+
fn with<
186+
'a,
187+
'g,
188+
U,
189+
F: FnOnce(QueueGuard<M::T, <Self::Guard as QueueStateGuard<'g>>::Out>) -> U,
190+
>(
191+
&'a mut self,
192+
f: F,
193+
) -> U
194+
where
195+
'a: 'g,
196+
{
197+
f(self.lock())
198+
}
199+
}

crates/virtio-queue/src/lib.rs

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

3233
use log::error;
3334
use vm_memory::{
@@ -1030,6 +1031,33 @@ impl<M: GuestAddressSpace> Queue<M> {
10301031
}
10311032
}
10321033

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

0 commit comments

Comments
 (0)