Skip to content

Commit 57ca35b

Browse files
committed
replace QueueStateGuard enum with generic associated lifetime
Use the same trick that is used in vm-memory for iterators, so that QueueStateT::lock's returned guard type has a generic associate lifetime. This makes the QueueStateT trait independent of the QueueState struct that implements it. Signed-off-by: Paolo Bonzini <[email protected]>
1 parent 95e3cd9 commit 57ca35b

File tree

1 file changed

+28
-32
lines changed

1 file changed

+28
-32
lines changed

crates/virtio-queue/src/lib.rs

Lines changed: 28 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -419,39 +419,23 @@ impl VirtqUsedElem {
419419

420420
unsafe impl ByteValued for VirtqUsedElem {}
421421

422-
/// Struct to hold an exclusive reference to the underlying `QueueState` object.
423-
pub enum QueueStateGuard<'a> {
424-
/// A reference to a `QueueState` object.
425-
StateObject(&'a mut QueueState),
426-
/// A `MutexGuard` for a `QueueState` object.
427-
MutexGuard(MutexGuard<'a, QueueState>),
428-
}
429-
430-
impl<'a> Deref for QueueStateGuard<'a> {
431-
type Target = QueueState;
432-
433-
fn deref(&self) -> &Self::Target {
434-
match self {
435-
QueueStateGuard::StateObject(v) => v,
436-
QueueStateGuard::MutexGuard(v) => v.deref(),
437-
}
438-
}
439-
}
440-
441-
impl<'a> DerefMut for QueueStateGuard<'a> {
442-
fn deref_mut(&mut self) -> &mut Self::Target {
443-
match self {
444-
QueueStateGuard::StateObject(v) => v,
445-
QueueStateGuard::MutexGuard(v) => v.deref_mut(),
446-
}
447-
}
422+
/// Lifetime-generic guard associated to a QueueStateT. In practice,
423+
/// instead of having a `QueueStateT::Guard<'a>` generic associated type,
424+
/// you have to write `<QueueStateT::Guard as QueueStateGuard<'a>>::Out`.
425+
pub trait QueueStateGuard<'a> {
426+
/// Type of the guard returned by the `lock` method.
427+
type Out: DerefMut<Target = QueueState>;
448428
}
449429

450430
/// Trait to access and manipulate a virtio queue.
451431
///
452432
/// To optimize for performance, different implementations of the `QueueStateT` trait may be
453433
/// provided for single-threaded context and multi-threaded context.
454434
pub trait QueueStateT {
435+
/// Lifetime-generic guard. Usually this is just `Self`, and implementors
436+
/// of `QueueStateT` also implement `QueueStateGuard`.
437+
type Guard: for<'a> QueueStateGuard<'a>;
438+
455439
/// Construct an empty virtio queue state object with the given `max_size`.
456440
fn new(max_size: u16) -> Self;
457441

@@ -465,7 +449,7 @@ pub trait QueueStateT {
465449
///
466450
/// Logically this method will acquire the underlying lock protecting the `QueueState` Object.
467451
/// The lock will be released when the returned object gets dropped.
468-
fn lock(&mut self) -> QueueStateGuard;
452+
fn lock(&mut self) -> <Self::Guard as QueueStateGuard>::Out;
469453

470454
/// Get the maximum size of the virtio queue.
471455
fn max_size(&self) -> u16;
@@ -664,7 +648,13 @@ impl QueueState {
664648
}
665649
}
666650

651+
impl<'a> QueueStateGuard<'a> for QueueState {
652+
type Out = &'a mut QueueState;
653+
}
654+
667655
impl QueueStateT for QueueState {
656+
type Guard = Self;
657+
668658
fn new(max_size: u16) -> Self {
669659
QueueState {
670660
max_size,
@@ -751,8 +741,8 @@ impl QueueStateT for QueueState {
751741
self.event_idx_enabled = false;
752742
}
753743

754-
fn lock(&mut self) -> QueueStateGuard {
755-
QueueStateGuard::StateObject(self)
744+
fn lock(&mut self) -> &mut Self {
745+
self
756746
}
757747

758748
fn max_size(&self) -> u16 {
@@ -919,7 +909,13 @@ pub struct QueueStateSync {
919909
state: Arc<Mutex<QueueState>>,
920910
}
921911

912+
impl<'a> QueueStateGuard<'a> for QueueStateSync {
913+
type Out = MutexGuard<'a, QueueState>;
914+
}
915+
922916
impl QueueStateT for QueueStateSync {
917+
type Guard = Self;
918+
923919
fn new(max_size: u16) -> Self {
924920
QueueStateSync {
925921
state: Arc::new(Mutex::new(QueueState::new(max_size))),
@@ -934,8 +930,8 @@ impl QueueStateT for QueueStateSync {
934930
self.state.lock().unwrap().reset();
935931
}
936932

937-
fn lock(&mut self) -> QueueStateGuard {
938-
QueueStateGuard::MutexGuard(self.state.lock().unwrap())
933+
fn lock(&mut self) -> MutexGuard<QueueState> {
934+
self.state.lock().unwrap()
939935
}
940936

941937
fn max_size(&self) -> u16 {
@@ -1040,7 +1036,7 @@ impl<M: GuestAddressSpace, S: QueueStateT> Queue<M, S> {
10401036
///
10411037
/// Logically this method will acquire the underlying lock protecting the `QueueState` Object.
10421038
/// The lock will be released when the returned object gets dropped.
1043-
pub fn lock(&mut self) -> QueueStateGuard {
1039+
pub fn lock(&mut self) -> <S::Guard as QueueStateGuard>::Out {
10441040
self.state.lock()
10451041
}
10461042

0 commit comments

Comments
 (0)