pub struct VirtqProducer<M, N, P> { /* private fields */ }Expand description
A high-level virtqueue producer (driver side).
The producer sends chains to the consumer (device), and receives used chains. This is used on the driver/guest side.
§Threading
The producer is intended for single-threaded, guest-side use. Reply payloads
are exposed as zero-copy Bytes via Bytes::from_owner,
which requires the owning pool to be Send. Do not move the producer
or its replies across threads, and do not instantiate it on the multi-threaded
host with those pools.
§Example
let mut producer = VirtqProducer::new(layout, mem, notifier, pool);
// Build and submit a chain
let mut chain = producer.chain().readable(64).writable(64).build()?;
chain.write_all(b"hello")?;
let token = producer.submit(chain)?;
// Later, poll for the used chain
if let Some(used) = producer.poll()? {
assert_eq!(used.token(), token);
match used {
UsedChain::Data(_, segments) => println!("Got used chain: {:?}", segments),
UsedChain::Ack(_) => println!("Got ack"),
}
}Implementations§
Source§impl<M, N, P> VirtqProducer<M, N, P>
impl<M, N, P> VirtqProducer<M, N, P>
Sourcepub fn new(layout: Layout, mem: M, notifier: N, pool: P) -> Self
pub fn new(layout: Layout, mem: M, notifier: N, pool: P) -> Self
Create a new virtqueue producer.
§Arguments
layout- Ring memory layout (descriptor table and event suppression addresses)mem- Memory operations implementation for reading/writing to shared memorynotifier- Callback for notifying the device (consumer) about new chainspool- Buffer allocator for chain payload and reply data
Sourcepub fn chain(&self) -> ChainBuilder<M, P>
pub fn chain(&self) -> ChainBuilder<M, P>
Begin building a descriptor chain for submission.
Returns a ChainBuilder that allocates buffers from the pool.
Sourcepub fn batch(&mut self) -> SubmitBatch<'_, M, N, P>
pub fn batch(&mut self) -> SubmitBatch<'_, M, N, P>
Begin a batch of submissions.
Chains submitted through the returned SubmitBatch are published to
the ring immediately, but the consumer is notified at most once when
SubmitBatch::finish is called. This mirrors the virtio pattern of
adding multiple buffers and then kicking the queue once.
Sourcepub fn submit(&mut self, chain: SendChain<M, P>) -> Result<Token, VirtqError>
pub fn submit(&mut self, chain: SendChain<M, P>) -> Result<Token, VirtqError>
Submit a SendChain to the ring.
Publishes the descriptor chain, stores the in-flight tracking state,
and notifies the consumer if event suppression allows. Notifications
are layout-neutral; use batch when a higher-level
protocol wants to publish multiple chains and kick once.
§Errors
VirtqError::PayloadTooLarge- written exceeds readable buffer capacityVirtqError::RingError- ring is fullVirtqError::InvalidState- descriptor ID collision
Sourcepub fn notify_backpressure(&self)
pub fn notify_backpressure(&self)
Signal backpressure to the consumer.
Bypasses event suppression. Call this when submit fails with a backpressure error and the consumer needs to drain.
Sourcepub fn used_cursor(&self) -> RingCursor
pub fn used_cursor(&self) -> RingCursor
Get the current used cursor position.
Useful for setting up descriptor-based event suppression.
Sourcepub fn set_used_suppression(
&mut self,
kind: SuppressionKind,
) -> Result<(), VirtqError>
pub fn set_used_suppression( &mut self, kind: SuppressionKind, ) -> Result<(), VirtqError>
Configure event suppression for used buffer notifications.
This controls when the device (consumer) signals us about completed buffers:
SuppressionKind::Enable: Always signal (default) - good for latencySuppressionKind::Disable: Never signal - caller must pollSuppressionKind::Descriptor: Signal only at specific cursor position
§Example: Used-chain batching
// Submit chains, then suppress notifications until all are used
let mut se = producer.chain().readable(64).writable(128).build()?;
se.write_all(b"entry1")?;
producer.submit(se)?;
let cursor = producer.used_cursor();
producer.set_used_suppression(SuppressionKind::Descriptor(cursor))?;
// Device will notify only after reaching that cursor positionSourcepub unsafe fn reset(&mut self)
pub unsafe fn reset(&mut self)
Reset ring, inflight, and pool state to initial values.
§Safety
No outstanding UsedChain::Data buffers, borrowed segment views, or
peer accesses to previously submitted descriptors may exist. Resetting
recycles the same backing addresses, so outstanding zero-copy buffers or
stale descriptor users could alias memory that is handed out again.
TODO(virtq): find a way to allow guest to keep used chains across resets.
Sourcepub unsafe fn reset_with_pool(&mut self, pool: P)
pub unsafe fn reset_with_pool(&mut self, pool: P)
Replace the pool and reset ring, inflight, and pending state.
§Safety
No outstanding UsedChain::Data buffers, borrowed segment views, or
peer accesses to previously submitted descriptors may exist. The new pool
may manage the same shared-memory addresses as the old pool, so old
zero-copy buffers must not outlive this transition.
Source§impl<M, N, P> VirtqProducer<M, N, P>
impl<M, N, P> VirtqProducer<M, N, P>
Sourcepub fn poll(&mut self) -> Result<Option<UsedChain>, VirtqError>
pub fn poll(&mut self) -> Result<Option<UsedChain>, VirtqError>
Poll for a single used chain from the device.
Returns buffered used chains from prior reclaim
calls first, then checks the ring for newly used chains.
Returns Ok(Some(used)) if a used chain is available, Ok(None) if no
used chains are ready (would block), or an error if the device misbehaved.
Data used chains contain zero-copy Bytes backed by the shared-memory
allocation via BufferOwner. The pool allocation is held alive as long
as any Bytes clone exists, and is returned to the pool when the last
clone is dropped.
§Errors
VirtqError::InvalidState- Device returned invalid descriptor ID or wrote more data than the writable buffer capacity
Sourcepub fn reclaim(&mut self) -> Result<usize, VirtqError>
pub fn reclaim(&mut self) -> Result<usize, VirtqError>
Reclaim ring slots and pool allocations from used descriptors.
Processes all available used chains from the ring: frees readable
buffer allocations immediately, and buffers writable data for
later retrieval via poll.
Read-only ack used chains are discarded immediately.
Use this to free resources under backpressure without losing writable data. Returns the number of chains reclaimed.
Sourcepub fn drain(&mut self, f: impl FnMut(UsedChain)) -> Result<(), VirtqError>
pub fn drain(&mut self, f: impl FnMut(UsedChain)) -> Result<(), VirtqError>
Drain all available used chains, calling the provided closure for each.
This is a convenience method that repeatedly calls poll
until no more used chains are available.
§Arguments
f- Closure called for each used chain
§Example
producer.drain(|used| {
println!("Got used chain for {:?}", used.token());
})?;