@@ -22,9 +22,10 @@ pub mod mock;
2222use std:: cmp:: min;
2323use std:: convert:: TryFrom ;
2424use std:: fmt:: { self , Debug , Display } ;
25+ use std:: marker:: PhantomData ;
2526use std:: mem:: size_of;
2627use std:: num:: Wrapping ;
27- use std:: ops:: Deref ;
28+ use std:: ops:: { Deref , DerefMut } ;
2829use std:: sync:: atomic:: { fence, Ordering } ;
2930
3031use log:: error;
@@ -785,6 +786,103 @@ impl QueueState {
785786}
786787
787788/// A convenient wrapper struct for a virtio queue, with associated GuestMemory object.
789+ pub struct QueueGuard < ' a , M : ' a + Clone + Deref , S : ' a + DerefMut < Target = QueueState > >
790+ where
791+ M :: Target : GuestMemory + Sized ,
792+ {
793+ /// Guest memory object associated with the queue.
794+ pub mem : M ,
795+
796+ /// Virtio queue state.
797+ pub state : S ,
798+
799+ _marker : PhantomData < & ' a S :: Target > ,
800+ }
801+
802+ impl < ' a , M : ' a + Clone + Deref , S : ' a + DerefMut < Target = QueueState > > QueueGuard < ' a , M , S >
803+ where
804+ M :: Target : GuestMemory + Sized ,
805+ {
806+ fn new ( mem : M , state : S ) -> QueueGuard < ' a , M , S > {
807+ QueueGuard {
808+ mem,
809+ state,
810+ _marker : PhantomData ,
811+ }
812+ }
813+
814+ /// Check whether the queue configuration is valid.
815+ pub fn is_valid ( & self ) -> bool {
816+ self . state . is_valid ( self . mem . deref ( ) )
817+ }
818+
819+ /// Read the `idx` field from the available ring.
820+ pub fn avail_idx ( & self , order : Ordering ) -> Result < Wrapping < u16 > , Error > {
821+ self . state . avail_idx ( self . mem . deref ( ) , order)
822+ }
823+
824+ /// Put a used descriptor head into the used ring.
825+ pub fn add_used ( & mut self , head_index : u16 , len : u32 ) -> Result < ( ) , Error > {
826+ self . state . add_used ( self . mem . deref ( ) , head_index, len)
827+ }
828+
829+ /// Enable notification events from the guest driver.
830+ ///
831+ /// Return true if one or more descriptors can be consumed from the available ring after
832+ /// notifications were enabled (and thus it's possible there will be no corresponding
833+ /// notification).
834+ pub fn enable_notification ( & mut self ) -> Result < bool , Error > {
835+ self . state . enable_notification ( self . mem . deref ( ) )
836+ }
837+
838+ /// Disable notification events from the guest driver.
839+ pub fn disable_notification ( & mut self ) -> Result < ( ) , Error > {
840+ self . state . disable_notification ( self . mem . deref ( ) )
841+ }
842+
843+ /// Check whether a notification to the guest is needed.
844+ ///
845+ /// Please note this method has side effects: once it returns `true`, it considers the
846+ /// driver will actually be notified, remember the associated index in the used ring, and
847+ /// won't return `true` again until the driver updates `used_event` and/or the notification
848+ /// conditions hold once more.
849+ pub fn needs_notification ( & mut self ) -> Result < bool , Error > {
850+ self . state . needs_notification ( self . mem . deref ( ) )
851+ }
852+
853+ /// A consuming iterator over all available descriptor chain heads offered by the driver.
854+ pub fn iter ( & mut self ) -> Result < AvailIter < ' _ , M > , Error > {
855+ // FIXME: this is inefficient
856+ self . state . iter ( self . mem . clone ( ) )
857+ }
858+ }
859+
860+ impl < ' a , M : ' a + Clone + Deref , S : ' a + DerefMut < Target = QueueState > > Deref
861+ for QueueGuard < ' a , M , S >
862+ where
863+ M :: Target : GuestMemory + Sized ,
864+ {
865+ type Target = QueueState ;
866+
867+ /// Reset the queue to the initial state.
868+ fn deref ( & self ) -> & QueueState {
869+ & self . state
870+ }
871+ }
872+
873+ impl < ' a , M : ' a + Clone + Deref , S : ' a + DerefMut < Target = QueueState > > DerefMut
874+ for QueueGuard < ' a , M , S >
875+ where
876+ M :: Target : GuestMemory + Sized ,
877+ {
878+ /// Reset the queue to the initial state.
879+ fn deref_mut ( & mut self ) -> & mut QueueState {
880+ & mut self . state
881+ }
882+ }
883+
884+ /// A convenient wrapper struct for a virtio queue, with associated GuestAddressSpace
885+ /// object.
788886#[ derive( Clone , Debug ) ]
789887pub struct Queue < M : GuestAddressSpace > {
790888 /// Guest memory object associated with the queue.
@@ -802,6 +900,12 @@ impl<M: GuestAddressSpace> Queue<M> {
802900 }
803901 }
804902
903+ /// Return a QueueGuard that allows to do multiple QueueState operations
904+ /// using the same GuestMemory.
905+ pub fn acquire ( & mut self ) -> QueueGuard < M :: T , & mut QueueState > {
906+ QueueGuard :: new ( self . mem . memory ( ) , & mut self . state )
907+ }
908+
805909 /// Check whether the queue configuration is valid.
806910 pub fn is_valid ( & self ) -> bool {
807911 self . state . is_valid ( self . mem . memory ( ) . deref ( ) )
@@ -1275,6 +1379,20 @@ mod tests {
12751379 assert_eq ! ( x. len, 0x1000 ) ;
12761380 }
12771381
1382+ #[ test]
1383+ fn test_queue_guard ( ) {
1384+ let m = & GuestMemoryMmap :: < ( ) > :: from_ranges ( & [ ( GuestAddress ( 0 ) , 0x10000 ) ] ) . unwrap ( ) ;
1385+ let vq = MockSplitQueue :: new ( m, 16 ) ;
1386+
1387+ let mut q = vq. create_queue ( m) ;
1388+ let mut qstate = q. acquire ( ) ;
1389+ qstate. ready = true ;
1390+ qstate. reset ( ) ;
1391+ assert_eq ! ( qstate. ready, false ) ;
1392+ let mut iter = qstate. iter ( ) . unwrap ( ) ;
1393+ assert ! ( iter. next( ) . is_none( ) ) ;
1394+ }
1395+
12781396 #[ test]
12791397 fn test_reset_queue ( ) {
12801398 let m = & GuestMemoryMmap :: < ( ) > :: from_ranges ( & [ ( GuestAddress ( 0 ) , 0x10000 ) ] ) . unwrap ( ) ;
0 commit comments