pub struct Device<'a, N> { /* private fields */ }
Expand description
State for managing a virtio device and its queues using futures.
Provides a wrapper around one or more [Queue
]s along with helpers to send and receive queue
notifications to the guest driver. These wrappers focus on presenting a asynchronous futures
interface on top of the underlying objects.
Primary this provides a wrapper around a [DescChainStream
] for processing
descriptor chains. The guest signals that there are descriptors available either using a
GuestBellTrap
or via a VirtioDeviceRequest::NotifyQueue
message. Connecting these two
sources of notifications to the underlying waker from the [DescChainStream
] can be done in a
most easily using [run_device_notify
]. It will run forever processing messages from a
VirtioDeviceRequestStream
, and from any GuestBellTrap
, performing [notify_queue
] as
needed.
If the the device needs to run its own message loop on the stream, and therefore cannot give it
to [run_device_notify
], it can also just [take_bell_traps
] and use
GuestBellTrap::complete
or GuestBellTrap::complete_or_pending
to process them. In this
case the device message loop should use [notify_queue
] for any
VirtioDeviceRequest::NotifyQueue
it receives.
The [DriverNotify
] object that was configured in the [DeviceBuilder]
can be retrieved using
[get_notify
]. The notify object might be needed by a device to:
- Signal a configuration change
- Flush pending queue notifications if something like [
virtio_device::util::BufferedNotify
] is being used.
Implementations§
Source§impl<'a, N> Device<'a, N>
impl<'a, N> Device<'a, N>
Sourcepub fn take_stream<'b>(
&'b self,
idx: u16,
) -> Result<WrappedDescChainStream<'a, 'b, N>, DeviceError>
pub fn take_stream<'b>( &'b self, idx: u16, ) -> Result<WrappedDescChainStream<'a, 'b, N>, DeviceError>
Take a [Stream
] that yields [DescChain
] for the requested queue
This returns an error if the specified queue either was not configured in the
DeviceBuilder
, or has already been taken and not returned. The
WrappedDescChainStream
that this returns will automatically return itself when dropped.
Note that the [Stream
] needs to have its waker signalled to work correctly, see [struct]
(Device) level comment for details.
Sourcepub fn get_notify(&self) -> &N
pub fn get_notify(&self) -> &N
Retrieve underlying driver notification object
Sourcepub fn configured_queues<'b>(&'b self) -> impl Iterator<Item = u16> + 'bwhere
'b: 'a,
pub fn configured_queues<'b>(&'b self) -> impl Iterator<Item = u16> + 'bwhere
'b: 'a,
Query the configured queues.
Returns an iterator of the queue numbers that were configured.
Sourcepub fn notify_queue(&self, idx: u16) -> Result<(), DeviceError>
pub fn notify_queue(&self, idx: u16) -> Result<(), DeviceError>
Notify a queue in response to a notification from the driver.
This signals the waker for the given queue and is required to have the streams returned from
[take_stream
] yield items.
See struct level documentation for more details.
Sourcepub fn take_bell_traps(&self) -> Option<GuestBellTrap>
pub fn take_bell_traps(&self) -> Option<GuestBellTrap>
Take any [GuestBellTraps
] that might have been configured.
If bell traps were provided in the DeviceBuilder
this returns them. This completely
removes them from the Device
and the caller is now responsible for them and forwarding
any notifications from the driver to [notify_queue
].
Internally [run_device_notify
] uses this to get the bell traps and so once you call it
this will always return a None
. Similarly if you call this [run_device_notify
] will
not be able to process bell traps, since you are responsible for them.
The normal reason to use this is if you need to run your own message loop and cannot use
[run_device_notify
], in which case you almost always want to
GuestBellTrap::complete_or_pending(device.take_bell_traps(), &device)
Sourcepub fn get_features(&self) -> u32
pub fn get_features(&self) -> u32
Return the negotiated features from [DeviceBuilder::give_ready
]
Sourcepub async fn run_device_notify(
&self,
stream: VirtioDeviceRequestStream,
) -> Result<(), DeviceError>
pub async fn run_device_notify( &self, stream: VirtioDeviceRequestStream, ) -> Result<(), DeviceError>
Run any notifications from the driver till completion.
Consumes both a [VirtioDeviceStream
] as well as any bell traps to
receive any notifications from the driver, for the device, and calls [notify_queue
] with
them. Will never yield a success and only ever yields an error should either source of
notifications close unexpectedly, or indicate an invalidate queue.
This method is ideal if you do not need to process device specific messages from the FIDL channel.
Sourcepub async fn run_device_notify_stream(
&self,
stream: VirtioDeviceRequestStream,
) -> Result<(), DeviceError>
pub async fn run_device_notify_stream( &self, stream: VirtioDeviceRequestStream, ) -> Result<(), DeviceError>
Process all queue notifications on a VirtioDeviceRequestStream
Unlike [run_device_notify
] this does not [take_bell_trap
] and process those messages.
This will also yield an Ok(())
should the stream end, leaving the caller to determine if
that is an error condition or not.