1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2023 The ChromiumOS Authors 2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be 3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file. 4*bb4ee6a4SAndroid Build Coastguard Worker 5*bb4ee6a4SAndroid Build Coastguard Worker //! virtqueue interface 6*bb4ee6a4SAndroid Build Coastguard Worker 7*bb4ee6a4SAndroid Build Coastguard Worker #![deny(missing_docs)] 8*bb4ee6a4SAndroid Build Coastguard Worker 9*bb4ee6a4SAndroid Build Coastguard Worker use std::ops::Deref; 10*bb4ee6a4SAndroid Build Coastguard Worker use std::ops::DerefMut; 11*bb4ee6a4SAndroid Build Coastguard Worker 12*bb4ee6a4SAndroid Build Coastguard Worker pub mod packed_descriptor_chain; 13*bb4ee6a4SAndroid Build Coastguard Worker mod packed_queue; 14*bb4ee6a4SAndroid Build Coastguard Worker pub mod split_descriptor_chain; 15*bb4ee6a4SAndroid Build Coastguard Worker mod split_queue; 16*bb4ee6a4SAndroid Build Coastguard Worker 17*bb4ee6a4SAndroid Build Coastguard Worker use std::num::Wrapping; 18*bb4ee6a4SAndroid Build Coastguard Worker 19*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::bail; 20*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::Context; 21*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::Result; 22*bb4ee6a4SAndroid Build Coastguard Worker use base::warn; 23*bb4ee6a4SAndroid Build Coastguard Worker use base::Event; 24*bb4ee6a4SAndroid Build Coastguard Worker use cros_async::AsyncError; 25*bb4ee6a4SAndroid Build Coastguard Worker use cros_async::EventAsync; 26*bb4ee6a4SAndroid Build Coastguard Worker use futures::channel::oneshot; 27*bb4ee6a4SAndroid Build Coastguard Worker use futures::select_biased; 28*bb4ee6a4SAndroid Build Coastguard Worker use futures::FutureExt; 29*bb4ee6a4SAndroid Build Coastguard Worker use packed_queue::PackedQueue; 30*bb4ee6a4SAndroid Build Coastguard Worker use serde::Deserialize; 31*bb4ee6a4SAndroid Build Coastguard Worker use serde::Serialize; 32*bb4ee6a4SAndroid Build Coastguard Worker use split_queue::SplitQueue; 33*bb4ee6a4SAndroid Build Coastguard Worker use virtio_sys::virtio_config::VIRTIO_F_RING_PACKED; 34*bb4ee6a4SAndroid Build Coastguard Worker use vm_memory::GuestAddress; 35*bb4ee6a4SAndroid Build Coastguard Worker use vm_memory::GuestMemory; 36*bb4ee6a4SAndroid Build Coastguard Worker 37*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::DescriptorChain; 38*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::Interrupt; 39*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::VIRTIO_MSI_NO_VECTOR; 40*bb4ee6a4SAndroid Build Coastguard Worker 41*bb4ee6a4SAndroid Build Coastguard Worker /// A virtio queue's parameters. 42*bb4ee6a4SAndroid Build Coastguard Worker /// 43*bb4ee6a4SAndroid Build Coastguard Worker /// `QueueConfig` can be converted into a running `Queue` by calling [`QueueConfig::activate()`]. 44*bb4ee6a4SAndroid Build Coastguard Worker pub struct QueueConfig { 45*bb4ee6a4SAndroid Build Coastguard Worker /// Whether this queue has already been activated. 46*bb4ee6a4SAndroid Build Coastguard Worker activated: bool, 47*bb4ee6a4SAndroid Build Coastguard Worker 48*bb4ee6a4SAndroid Build Coastguard Worker /// The maximal size in elements offered by the device 49*bb4ee6a4SAndroid Build Coastguard Worker max_size: u16, 50*bb4ee6a4SAndroid Build Coastguard Worker 51*bb4ee6a4SAndroid Build Coastguard Worker /// The queue size in elements the driver selected. This is always guaranteed to be a power of 52*bb4ee6a4SAndroid Build Coastguard Worker /// two less than or equal to `max_size`, as required for split virtqueues. These invariants 53*bb4ee6a4SAndroid Build Coastguard Worker /// are enforced by `set_size()`. 54*bb4ee6a4SAndroid Build Coastguard Worker size: u16, 55*bb4ee6a4SAndroid Build Coastguard Worker 56*bb4ee6a4SAndroid Build Coastguard Worker /// Indicates if the queue is finished with configuration 57*bb4ee6a4SAndroid Build Coastguard Worker ready: bool, 58*bb4ee6a4SAndroid Build Coastguard Worker 59*bb4ee6a4SAndroid Build Coastguard Worker /// MSI-X vector for the queue. Don't care for INTx 60*bb4ee6a4SAndroid Build Coastguard Worker vector: u16, 61*bb4ee6a4SAndroid Build Coastguard Worker 62*bb4ee6a4SAndroid Build Coastguard Worker /// Ring features (e.g. `VIRTIO_RING_F_EVENT_IDX`, `VIRTIO_F_RING_PACKED`) offered by the 63*bb4ee6a4SAndroid Build Coastguard Worker /// device 64*bb4ee6a4SAndroid Build Coastguard Worker features: u64, 65*bb4ee6a4SAndroid Build Coastguard Worker 66*bb4ee6a4SAndroid Build Coastguard Worker // Device feature bits accepted by the driver 67*bb4ee6a4SAndroid Build Coastguard Worker acked_features: u64, 68*bb4ee6a4SAndroid Build Coastguard Worker 69*bb4ee6a4SAndroid Build Coastguard Worker /// Guest physical address of the descriptor table 70*bb4ee6a4SAndroid Build Coastguard Worker desc_table: GuestAddress, 71*bb4ee6a4SAndroid Build Coastguard Worker 72*bb4ee6a4SAndroid Build Coastguard Worker /// Guest physical address of the available ring (driver area) 73*bb4ee6a4SAndroid Build Coastguard Worker /// 74*bb4ee6a4SAndroid Build Coastguard Worker /// TODO(b/290657008): update field and accessor names to match the current virtio spec 75*bb4ee6a4SAndroid Build Coastguard Worker avail_ring: GuestAddress, 76*bb4ee6a4SAndroid Build Coastguard Worker 77*bb4ee6a4SAndroid Build Coastguard Worker /// Guest physical address of the used ring (device area) 78*bb4ee6a4SAndroid Build Coastguard Worker used_ring: GuestAddress, 79*bb4ee6a4SAndroid Build Coastguard Worker 80*bb4ee6a4SAndroid Build Coastguard Worker /// Initial available ring index when the queue is activated. 81*bb4ee6a4SAndroid Build Coastguard Worker next_avail: Wrapping<u16>, 82*bb4ee6a4SAndroid Build Coastguard Worker 83*bb4ee6a4SAndroid Build Coastguard Worker /// Initial used ring index when the queue is activated. 84*bb4ee6a4SAndroid Build Coastguard Worker next_used: Wrapping<u16>, 85*bb4ee6a4SAndroid Build Coastguard Worker } 86*bb4ee6a4SAndroid Build Coastguard Worker 87*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Serialize, Deserialize)] 88*bb4ee6a4SAndroid Build Coastguard Worker struct QueueConfigSnapshot { 89*bb4ee6a4SAndroid Build Coastguard Worker activated: bool, 90*bb4ee6a4SAndroid Build Coastguard Worker max_size: u16, 91*bb4ee6a4SAndroid Build Coastguard Worker size: u16, 92*bb4ee6a4SAndroid Build Coastguard Worker ready: bool, 93*bb4ee6a4SAndroid Build Coastguard Worker vector: u16, 94*bb4ee6a4SAndroid Build Coastguard Worker features: u64, 95*bb4ee6a4SAndroid Build Coastguard Worker acked_features: u64, 96*bb4ee6a4SAndroid Build Coastguard Worker desc_table: GuestAddress, 97*bb4ee6a4SAndroid Build Coastguard Worker avail_ring: GuestAddress, 98*bb4ee6a4SAndroid Build Coastguard Worker used_ring: GuestAddress, 99*bb4ee6a4SAndroid Build Coastguard Worker next_avail: Wrapping<u16>, 100*bb4ee6a4SAndroid Build Coastguard Worker next_used: Wrapping<u16>, 101*bb4ee6a4SAndroid Build Coastguard Worker } 102*bb4ee6a4SAndroid Build Coastguard Worker 103*bb4ee6a4SAndroid Build Coastguard Worker impl QueueConfig { 104*bb4ee6a4SAndroid Build Coastguard Worker /// Constructs a virtio queue configuration with the given `max_size`. new(max_size: u16, features: u64) -> Self105*bb4ee6a4SAndroid Build Coastguard Worker pub fn new(max_size: u16, features: u64) -> Self { 106*bb4ee6a4SAndroid Build Coastguard Worker assert!(max_size > 0); 107*bb4ee6a4SAndroid Build Coastguard Worker assert!(max_size <= Queue::MAX_SIZE); 108*bb4ee6a4SAndroid Build Coastguard Worker QueueConfig { 109*bb4ee6a4SAndroid Build Coastguard Worker activated: false, 110*bb4ee6a4SAndroid Build Coastguard Worker max_size, 111*bb4ee6a4SAndroid Build Coastguard Worker size: max_size, 112*bb4ee6a4SAndroid Build Coastguard Worker ready: false, 113*bb4ee6a4SAndroid Build Coastguard Worker vector: VIRTIO_MSI_NO_VECTOR, 114*bb4ee6a4SAndroid Build Coastguard Worker desc_table: GuestAddress(0), 115*bb4ee6a4SAndroid Build Coastguard Worker avail_ring: GuestAddress(0), 116*bb4ee6a4SAndroid Build Coastguard Worker used_ring: GuestAddress(0), 117*bb4ee6a4SAndroid Build Coastguard Worker features, 118*bb4ee6a4SAndroid Build Coastguard Worker acked_features: 0, 119*bb4ee6a4SAndroid Build Coastguard Worker next_used: Wrapping(0), 120*bb4ee6a4SAndroid Build Coastguard Worker next_avail: Wrapping(0), 121*bb4ee6a4SAndroid Build Coastguard Worker } 122*bb4ee6a4SAndroid Build Coastguard Worker } 123*bb4ee6a4SAndroid Build Coastguard Worker 124*bb4ee6a4SAndroid Build Coastguard Worker /// Returns the maximum size of this queue. max_size(&self) -> u16125*bb4ee6a4SAndroid Build Coastguard Worker pub fn max_size(&self) -> u16 { 126*bb4ee6a4SAndroid Build Coastguard Worker self.max_size 127*bb4ee6a4SAndroid Build Coastguard Worker } 128*bb4ee6a4SAndroid Build Coastguard Worker 129*bb4ee6a4SAndroid Build Coastguard Worker /// Returns the currently configured size of the queue. size(&self) -> u16130*bb4ee6a4SAndroid Build Coastguard Worker pub fn size(&self) -> u16 { 131*bb4ee6a4SAndroid Build Coastguard Worker self.size 132*bb4ee6a4SAndroid Build Coastguard Worker } 133*bb4ee6a4SAndroid Build Coastguard Worker 134*bb4ee6a4SAndroid Build Coastguard Worker /// Sets the queue size. set_size(&mut self, val: u16)135*bb4ee6a4SAndroid Build Coastguard Worker pub fn set_size(&mut self, val: u16) { 136*bb4ee6a4SAndroid Build Coastguard Worker if self.ready { 137*bb4ee6a4SAndroid Build Coastguard Worker warn!("ignoring write to size on ready queue"); 138*bb4ee6a4SAndroid Build Coastguard Worker return; 139*bb4ee6a4SAndroid Build Coastguard Worker } 140*bb4ee6a4SAndroid Build Coastguard Worker 141*bb4ee6a4SAndroid Build Coastguard Worker if val > self.max_size { 142*bb4ee6a4SAndroid Build Coastguard Worker warn!( 143*bb4ee6a4SAndroid Build Coastguard Worker "requested queue size {} is larger than max_size {}", 144*bb4ee6a4SAndroid Build Coastguard Worker val, self.max_size 145*bb4ee6a4SAndroid Build Coastguard Worker ); 146*bb4ee6a4SAndroid Build Coastguard Worker return; 147*bb4ee6a4SAndroid Build Coastguard Worker } 148*bb4ee6a4SAndroid Build Coastguard Worker 149*bb4ee6a4SAndroid Build Coastguard Worker self.size = val; 150*bb4ee6a4SAndroid Build Coastguard Worker } 151*bb4ee6a4SAndroid Build Coastguard Worker 152*bb4ee6a4SAndroid Build Coastguard Worker /// Returns the currently configured interrupt vector. vector(&self) -> u16153*bb4ee6a4SAndroid Build Coastguard Worker pub fn vector(&self) -> u16 { 154*bb4ee6a4SAndroid Build Coastguard Worker self.vector 155*bb4ee6a4SAndroid Build Coastguard Worker } 156*bb4ee6a4SAndroid Build Coastguard Worker 157*bb4ee6a4SAndroid Build Coastguard Worker /// Sets the interrupt vector for this queue. set_vector(&mut self, val: u16)158*bb4ee6a4SAndroid Build Coastguard Worker pub fn set_vector(&mut self, val: u16) { 159*bb4ee6a4SAndroid Build Coastguard Worker if self.ready { 160*bb4ee6a4SAndroid Build Coastguard Worker warn!("ignoring write to vector on ready queue"); 161*bb4ee6a4SAndroid Build Coastguard Worker return; 162*bb4ee6a4SAndroid Build Coastguard Worker } 163*bb4ee6a4SAndroid Build Coastguard Worker 164*bb4ee6a4SAndroid Build Coastguard Worker self.vector = val; 165*bb4ee6a4SAndroid Build Coastguard Worker } 166*bb4ee6a4SAndroid Build Coastguard Worker 167*bb4ee6a4SAndroid Build Coastguard Worker /// Getter for descriptor area desc_table(&self) -> GuestAddress168*bb4ee6a4SAndroid Build Coastguard Worker pub fn desc_table(&self) -> GuestAddress { 169*bb4ee6a4SAndroid Build Coastguard Worker self.desc_table 170*bb4ee6a4SAndroid Build Coastguard Worker } 171*bb4ee6a4SAndroid Build Coastguard Worker 172*bb4ee6a4SAndroid Build Coastguard Worker /// Setter for descriptor area set_desc_table(&mut self, val: GuestAddress)173*bb4ee6a4SAndroid Build Coastguard Worker pub fn set_desc_table(&mut self, val: GuestAddress) { 174*bb4ee6a4SAndroid Build Coastguard Worker if self.ready { 175*bb4ee6a4SAndroid Build Coastguard Worker warn!("ignoring write to desc_table on ready queue"); 176*bb4ee6a4SAndroid Build Coastguard Worker return; 177*bb4ee6a4SAndroid Build Coastguard Worker } 178*bb4ee6a4SAndroid Build Coastguard Worker 179*bb4ee6a4SAndroid Build Coastguard Worker self.desc_table = val; 180*bb4ee6a4SAndroid Build Coastguard Worker } 181*bb4ee6a4SAndroid Build Coastguard Worker 182*bb4ee6a4SAndroid Build Coastguard Worker /// Getter for driver area avail_ring(&self) -> GuestAddress183*bb4ee6a4SAndroid Build Coastguard Worker pub fn avail_ring(&self) -> GuestAddress { 184*bb4ee6a4SAndroid Build Coastguard Worker self.avail_ring 185*bb4ee6a4SAndroid Build Coastguard Worker } 186*bb4ee6a4SAndroid Build Coastguard Worker 187*bb4ee6a4SAndroid Build Coastguard Worker /// Setter for driver area set_avail_ring(&mut self, val: GuestAddress)188*bb4ee6a4SAndroid Build Coastguard Worker pub fn set_avail_ring(&mut self, val: GuestAddress) { 189*bb4ee6a4SAndroid Build Coastguard Worker if self.ready { 190*bb4ee6a4SAndroid Build Coastguard Worker warn!("ignoring write to avail_ring on ready queue"); 191*bb4ee6a4SAndroid Build Coastguard Worker return; 192*bb4ee6a4SAndroid Build Coastguard Worker } 193*bb4ee6a4SAndroid Build Coastguard Worker 194*bb4ee6a4SAndroid Build Coastguard Worker self.avail_ring = val; 195*bb4ee6a4SAndroid Build Coastguard Worker } 196*bb4ee6a4SAndroid Build Coastguard Worker 197*bb4ee6a4SAndroid Build Coastguard Worker /// Getter for device area used_ring(&self) -> GuestAddress198*bb4ee6a4SAndroid Build Coastguard Worker pub fn used_ring(&self) -> GuestAddress { 199*bb4ee6a4SAndroid Build Coastguard Worker self.used_ring 200*bb4ee6a4SAndroid Build Coastguard Worker } 201*bb4ee6a4SAndroid Build Coastguard Worker 202*bb4ee6a4SAndroid Build Coastguard Worker /// Setter for device area set_used_ring(&mut self, val: GuestAddress)203*bb4ee6a4SAndroid Build Coastguard Worker pub fn set_used_ring(&mut self, val: GuestAddress) { 204*bb4ee6a4SAndroid Build Coastguard Worker if self.ready { 205*bb4ee6a4SAndroid Build Coastguard Worker warn!("ignoring write to used_ring on ready queue"); 206*bb4ee6a4SAndroid Build Coastguard Worker return; 207*bb4ee6a4SAndroid Build Coastguard Worker } 208*bb4ee6a4SAndroid Build Coastguard Worker 209*bb4ee6a4SAndroid Build Coastguard Worker self.used_ring = val; 210*bb4ee6a4SAndroid Build Coastguard Worker } 211*bb4ee6a4SAndroid Build Coastguard Worker 212*bb4ee6a4SAndroid Build Coastguard Worker /// Getter for next_avail index next_avail(&self) -> Wrapping<u16>213*bb4ee6a4SAndroid Build Coastguard Worker pub fn next_avail(&self) -> Wrapping<u16> { 214*bb4ee6a4SAndroid Build Coastguard Worker self.next_avail 215*bb4ee6a4SAndroid Build Coastguard Worker } 216*bb4ee6a4SAndroid Build Coastguard Worker 217*bb4ee6a4SAndroid Build Coastguard Worker /// Setter for next_avail index set_next_avail(&mut self, val: Wrapping<u16>)218*bb4ee6a4SAndroid Build Coastguard Worker pub fn set_next_avail(&mut self, val: Wrapping<u16>) { 219*bb4ee6a4SAndroid Build Coastguard Worker if self.ready { 220*bb4ee6a4SAndroid Build Coastguard Worker warn!("ignoring write to next_avail on ready queue"); 221*bb4ee6a4SAndroid Build Coastguard Worker return; 222*bb4ee6a4SAndroid Build Coastguard Worker } 223*bb4ee6a4SAndroid Build Coastguard Worker 224*bb4ee6a4SAndroid Build Coastguard Worker self.next_avail = val; 225*bb4ee6a4SAndroid Build Coastguard Worker } 226*bb4ee6a4SAndroid Build Coastguard Worker 227*bb4ee6a4SAndroid Build Coastguard Worker /// Getter for next_used index next_used(&self) -> Wrapping<u16>228*bb4ee6a4SAndroid Build Coastguard Worker pub fn next_used(&self) -> Wrapping<u16> { 229*bb4ee6a4SAndroid Build Coastguard Worker self.next_used 230*bb4ee6a4SAndroid Build Coastguard Worker } 231*bb4ee6a4SAndroid Build Coastguard Worker 232*bb4ee6a4SAndroid Build Coastguard Worker /// Setter for next_used index set_next_used(&mut self, val: Wrapping<u16>)233*bb4ee6a4SAndroid Build Coastguard Worker pub fn set_next_used(&mut self, val: Wrapping<u16>) { 234*bb4ee6a4SAndroid Build Coastguard Worker if self.ready { 235*bb4ee6a4SAndroid Build Coastguard Worker warn!("ignoring write to next_used on ready queue"); 236*bb4ee6a4SAndroid Build Coastguard Worker return; 237*bb4ee6a4SAndroid Build Coastguard Worker } 238*bb4ee6a4SAndroid Build Coastguard Worker 239*bb4ee6a4SAndroid Build Coastguard Worker self.next_used = val; 240*bb4ee6a4SAndroid Build Coastguard Worker } 241*bb4ee6a4SAndroid Build Coastguard Worker 242*bb4ee6a4SAndroid Build Coastguard Worker /// Returns the features that have been acknowledged by the driver. acked_features(&self) -> u64243*bb4ee6a4SAndroid Build Coastguard Worker pub fn acked_features(&self) -> u64 { 244*bb4ee6a4SAndroid Build Coastguard Worker self.acked_features 245*bb4ee6a4SAndroid Build Coastguard Worker } 246*bb4ee6a4SAndroid Build Coastguard Worker 247*bb4ee6a4SAndroid Build Coastguard Worker /// Acknowledges that this set of features should be enabled on this queue. ack_features(&mut self, features: u64)248*bb4ee6a4SAndroid Build Coastguard Worker pub fn ack_features(&mut self, features: u64) { 249*bb4ee6a4SAndroid Build Coastguard Worker self.acked_features |= features & self.features; 250*bb4ee6a4SAndroid Build Coastguard Worker } 251*bb4ee6a4SAndroid Build Coastguard Worker 252*bb4ee6a4SAndroid Build Coastguard Worker /// Return whether the driver has enabled this queue. ready(&self) -> bool253*bb4ee6a4SAndroid Build Coastguard Worker pub fn ready(&self) -> bool { 254*bb4ee6a4SAndroid Build Coastguard Worker self.ready 255*bb4ee6a4SAndroid Build Coastguard Worker } 256*bb4ee6a4SAndroid Build Coastguard Worker 257*bb4ee6a4SAndroid Build Coastguard Worker /// Signal that the driver has completed queue configuration. set_ready(&mut self, enable: bool)258*bb4ee6a4SAndroid Build Coastguard Worker pub fn set_ready(&mut self, enable: bool) { 259*bb4ee6a4SAndroid Build Coastguard Worker self.ready = enable; 260*bb4ee6a4SAndroid Build Coastguard Worker } 261*bb4ee6a4SAndroid Build Coastguard Worker 262*bb4ee6a4SAndroid Build Coastguard Worker /// Convert the queue configuration into an active queue. activate( &mut self, mem: &GuestMemory, event: Event, interrupt: Interrupt, ) -> Result<Queue>263*bb4ee6a4SAndroid Build Coastguard Worker pub fn activate( 264*bb4ee6a4SAndroid Build Coastguard Worker &mut self, 265*bb4ee6a4SAndroid Build Coastguard Worker mem: &GuestMemory, 266*bb4ee6a4SAndroid Build Coastguard Worker event: Event, 267*bb4ee6a4SAndroid Build Coastguard Worker interrupt: Interrupt, 268*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<Queue> { 269*bb4ee6a4SAndroid Build Coastguard Worker if !self.ready { 270*bb4ee6a4SAndroid Build Coastguard Worker bail!("attempted to activate a non-ready queue"); 271*bb4ee6a4SAndroid Build Coastguard Worker } 272*bb4ee6a4SAndroid Build Coastguard Worker 273*bb4ee6a4SAndroid Build Coastguard Worker if self.activated { 274*bb4ee6a4SAndroid Build Coastguard Worker bail!("queue is already activated"); 275*bb4ee6a4SAndroid Build Coastguard Worker } 276*bb4ee6a4SAndroid Build Coastguard Worker // If VIRTIO_F_RING_PACKED feature bit is set, create a packed queue, otherwise create a 277*bb4ee6a4SAndroid Build Coastguard Worker // split queue 278*bb4ee6a4SAndroid Build Coastguard Worker let queue: Queue = if ((self.acked_features >> VIRTIO_F_RING_PACKED) & 1) != 0 { 279*bb4ee6a4SAndroid Build Coastguard Worker let pq = PackedQueue::new(self, mem, event, interrupt) 280*bb4ee6a4SAndroid Build Coastguard Worker .context("Failed to create a packed queue.")?; 281*bb4ee6a4SAndroid Build Coastguard Worker Queue::PackedVirtQueue(pq) 282*bb4ee6a4SAndroid Build Coastguard Worker } else { 283*bb4ee6a4SAndroid Build Coastguard Worker let sq = SplitQueue::new(self, mem, event, interrupt) 284*bb4ee6a4SAndroid Build Coastguard Worker .context("Failed to create a split queue.")?; 285*bb4ee6a4SAndroid Build Coastguard Worker Queue::SplitVirtQueue(sq) 286*bb4ee6a4SAndroid Build Coastguard Worker }; 287*bb4ee6a4SAndroid Build Coastguard Worker 288*bb4ee6a4SAndroid Build Coastguard Worker self.activated = true; 289*bb4ee6a4SAndroid Build Coastguard Worker Ok(queue) 290*bb4ee6a4SAndroid Build Coastguard Worker } 291*bb4ee6a4SAndroid Build Coastguard Worker 292*bb4ee6a4SAndroid Build Coastguard Worker /// Reset queue to a clean state reset(&mut self)293*bb4ee6a4SAndroid Build Coastguard Worker pub fn reset(&mut self) { 294*bb4ee6a4SAndroid Build Coastguard Worker self.activated = false; 295*bb4ee6a4SAndroid Build Coastguard Worker self.ready = false; 296*bb4ee6a4SAndroid Build Coastguard Worker self.size = self.max_size; 297*bb4ee6a4SAndroid Build Coastguard Worker self.vector = VIRTIO_MSI_NO_VECTOR; 298*bb4ee6a4SAndroid Build Coastguard Worker self.desc_table = GuestAddress(0); 299*bb4ee6a4SAndroid Build Coastguard Worker self.avail_ring = GuestAddress(0); 300*bb4ee6a4SAndroid Build Coastguard Worker self.used_ring = GuestAddress(0); 301*bb4ee6a4SAndroid Build Coastguard Worker self.next_avail = Wrapping(0); 302*bb4ee6a4SAndroid Build Coastguard Worker self.next_used = Wrapping(0); 303*bb4ee6a4SAndroid Build Coastguard Worker self.acked_features = 0; 304*bb4ee6a4SAndroid Build Coastguard Worker } 305*bb4ee6a4SAndroid Build Coastguard Worker 306*bb4ee6a4SAndroid Build Coastguard Worker /// Take snapshot of queue configuration snapshot(&self) -> Result<serde_json::Value>307*bb4ee6a4SAndroid Build Coastguard Worker pub fn snapshot(&self) -> Result<serde_json::Value> { 308*bb4ee6a4SAndroid Build Coastguard Worker serde_json::to_value(QueueConfigSnapshot { 309*bb4ee6a4SAndroid Build Coastguard Worker activated: self.activated, 310*bb4ee6a4SAndroid Build Coastguard Worker max_size: self.max_size, 311*bb4ee6a4SAndroid Build Coastguard Worker size: self.size, 312*bb4ee6a4SAndroid Build Coastguard Worker ready: self.ready, 313*bb4ee6a4SAndroid Build Coastguard Worker vector: self.vector, 314*bb4ee6a4SAndroid Build Coastguard Worker features: self.features, 315*bb4ee6a4SAndroid Build Coastguard Worker acked_features: self.acked_features, 316*bb4ee6a4SAndroid Build Coastguard Worker desc_table: self.desc_table, 317*bb4ee6a4SAndroid Build Coastguard Worker avail_ring: self.avail_ring, 318*bb4ee6a4SAndroid Build Coastguard Worker used_ring: self.used_ring, 319*bb4ee6a4SAndroid Build Coastguard Worker next_avail: self.next_avail, 320*bb4ee6a4SAndroid Build Coastguard Worker next_used: self.next_used, 321*bb4ee6a4SAndroid Build Coastguard Worker }) 322*bb4ee6a4SAndroid Build Coastguard Worker .context("error serializing") 323*bb4ee6a4SAndroid Build Coastguard Worker } 324*bb4ee6a4SAndroid Build Coastguard Worker 325*bb4ee6a4SAndroid Build Coastguard Worker /// Restore queue configuration from snapshot restore(&mut self, data: serde_json::Value) -> Result<()>326*bb4ee6a4SAndroid Build Coastguard Worker pub fn restore(&mut self, data: serde_json::Value) -> Result<()> { 327*bb4ee6a4SAndroid Build Coastguard Worker let snap: QueueConfigSnapshot = 328*bb4ee6a4SAndroid Build Coastguard Worker serde_json::from_value(data).context("error deserializing")?; 329*bb4ee6a4SAndroid Build Coastguard Worker self.activated = snap.activated; 330*bb4ee6a4SAndroid Build Coastguard Worker self.max_size = snap.max_size; 331*bb4ee6a4SAndroid Build Coastguard Worker self.size = snap.size; 332*bb4ee6a4SAndroid Build Coastguard Worker self.ready = snap.ready; 333*bb4ee6a4SAndroid Build Coastguard Worker self.vector = snap.vector; 334*bb4ee6a4SAndroid Build Coastguard Worker self.features = snap.features; 335*bb4ee6a4SAndroid Build Coastguard Worker self.acked_features = snap.acked_features; 336*bb4ee6a4SAndroid Build Coastguard Worker self.desc_table = snap.desc_table; 337*bb4ee6a4SAndroid Build Coastguard Worker self.avail_ring = snap.avail_ring; 338*bb4ee6a4SAndroid Build Coastguard Worker self.used_ring = snap.used_ring; 339*bb4ee6a4SAndroid Build Coastguard Worker self.next_avail = snap.next_avail; 340*bb4ee6a4SAndroid Build Coastguard Worker self.next_used = snap.next_used; 341*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) 342*bb4ee6a4SAndroid Build Coastguard Worker } 343*bb4ee6a4SAndroid Build Coastguard Worker } 344*bb4ee6a4SAndroid Build Coastguard Worker 345*bb4ee6a4SAndroid Build Coastguard Worker /// Usage: define_queue_method!(method_name, return_type[, mut][, arg1: arg1_type, arg2: arg2_type, 346*bb4ee6a4SAndroid Build Coastguard Worker /// ...]) 347*bb4ee6a4SAndroid Build Coastguard Worker /// 348*bb4ee6a4SAndroid Build Coastguard Worker /// - `method_name`: The name of the method to be defined (as an identifier). 349*bb4ee6a4SAndroid Build Coastguard Worker /// - `return_type`: The return type of the method. 350*bb4ee6a4SAndroid Build Coastguard Worker /// - `mut` (optional): Include this keyword if the method requires a mutable reference to `self` 351*bb4ee6a4SAndroid Build Coastguard Worker /// (`&mut self`). 352*bb4ee6a4SAndroid Build Coastguard Worker /// - `arg1: arg1_type, arg2: arg2_type, ...` (optional): Include method parameters as a 353*bb4ee6a4SAndroid Build Coastguard Worker /// comma-separated list of `name: type` pairs, if the method takes any arguments. 354*bb4ee6a4SAndroid Build Coastguard Worker macro_rules! define_queue_method { 355*bb4ee6a4SAndroid Build Coastguard Worker ( 356*bb4ee6a4SAndroid Build Coastguard Worker $(#[$doc:meta])* 357*bb4ee6a4SAndroid Build Coastguard Worker $method:ident, $return_type:ty, $( $var:ident : $vartype:ty ),* 358*bb4ee6a4SAndroid Build Coastguard Worker ) => { 359*bb4ee6a4SAndroid Build Coastguard Worker $(#[$doc])* 360*bb4ee6a4SAndroid Build Coastguard Worker pub fn $method(&self, $($var: $vartype),*) -> $return_type { 361*bb4ee6a4SAndroid Build Coastguard Worker match self { 362*bb4ee6a4SAndroid Build Coastguard Worker Queue::SplitVirtQueue(sq) => sq.$method($($var),*), 363*bb4ee6a4SAndroid Build Coastguard Worker Queue::PackedVirtQueue(pq) => pq.$method($($var),*), 364*bb4ee6a4SAndroid Build Coastguard Worker } 365*bb4ee6a4SAndroid Build Coastguard Worker } 366*bb4ee6a4SAndroid Build Coastguard Worker }; 367*bb4ee6a4SAndroid Build Coastguard Worker ( 368*bb4ee6a4SAndroid Build Coastguard Worker $(#[$doc:meta])* 369*bb4ee6a4SAndroid Build Coastguard Worker $method:ident, $return_type:ty, mut, $( $var:ident : $vartype:ty ),* 370*bb4ee6a4SAndroid Build Coastguard Worker ) => { 371*bb4ee6a4SAndroid Build Coastguard Worker $(#[$doc])* 372*bb4ee6a4SAndroid Build Coastguard Worker pub fn $method(&mut self, $($var: $vartype),*) -> $return_type { 373*bb4ee6a4SAndroid Build Coastguard Worker match self { 374*bb4ee6a4SAndroid Build Coastguard Worker Queue::SplitVirtQueue(sq) => sq.$method($($var),*), 375*bb4ee6a4SAndroid Build Coastguard Worker Queue::PackedVirtQueue(pq) => pq.$method($($var),*), 376*bb4ee6a4SAndroid Build Coastguard Worker } 377*bb4ee6a4SAndroid Build Coastguard Worker } 378*bb4ee6a4SAndroid Build Coastguard Worker }; 379*bb4ee6a4SAndroid Build Coastguard Worker } 380*bb4ee6a4SAndroid Build Coastguard Worker 381*bb4ee6a4SAndroid Build Coastguard Worker /// Virtqueue interface representing different types of virtqueues 382*bb4ee6a4SAndroid Build Coastguard Worker /// The struct of each queue type is wrapped in the enum variants 383*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug)] 384*bb4ee6a4SAndroid Build Coastguard Worker pub enum Queue { 385*bb4ee6a4SAndroid Build Coastguard Worker /// Split virtqueue type in virtio v1.2 spec: <https://docs.oasis-open.org/virtio/virtio/v1.2/csd01/virtio-v1.2-csd01.html#x1-350007> 386*bb4ee6a4SAndroid Build Coastguard Worker SplitVirtQueue(SplitQueue), 387*bb4ee6a4SAndroid Build Coastguard Worker /// Packed virtqueue type in virtio v1.2 spec: <https://docs.oasis-open.org/virtio/virtio/v1.2/csd01/virtio-v1.2-csd01.html#x1-720008> 388*bb4ee6a4SAndroid Build Coastguard Worker PackedVirtQueue(PackedQueue), 389*bb4ee6a4SAndroid Build Coastguard Worker } 390*bb4ee6a4SAndroid Build Coastguard Worker 391*bb4ee6a4SAndroid Build Coastguard Worker impl Queue { 392*bb4ee6a4SAndroid Build Coastguard Worker /// Largest valid number of entries in a virtqueue. 393*bb4ee6a4SAndroid Build Coastguard Worker pub const MAX_SIZE: u16 = 32768; 394*bb4ee6a4SAndroid Build Coastguard Worker 395*bb4ee6a4SAndroid Build Coastguard Worker /// Asynchronously read the next descriptor chain from the queue. 396*bb4ee6a4SAndroid Build Coastguard Worker /// Returns a `DescriptorChain` when it is `await`ed. next_async( &mut self, eventfd: &mut EventAsync, ) -> std::result::Result<DescriptorChain, AsyncError>397*bb4ee6a4SAndroid Build Coastguard Worker pub async fn next_async( 398*bb4ee6a4SAndroid Build Coastguard Worker &mut self, 399*bb4ee6a4SAndroid Build Coastguard Worker eventfd: &mut EventAsync, 400*bb4ee6a4SAndroid Build Coastguard Worker ) -> std::result::Result<DescriptorChain, AsyncError> { 401*bb4ee6a4SAndroid Build Coastguard Worker loop { 402*bb4ee6a4SAndroid Build Coastguard Worker // Check if there are more descriptors available. 403*bb4ee6a4SAndroid Build Coastguard Worker if let Some(chain) = self.pop() { 404*bb4ee6a4SAndroid Build Coastguard Worker return Ok(chain); 405*bb4ee6a4SAndroid Build Coastguard Worker } 406*bb4ee6a4SAndroid Build Coastguard Worker eventfd.next_val().await?; 407*bb4ee6a4SAndroid Build Coastguard Worker } 408*bb4ee6a4SAndroid Build Coastguard Worker } 409*bb4ee6a4SAndroid Build Coastguard Worker 410*bb4ee6a4SAndroid Build Coastguard Worker /// Get the first available descriptor chain without removing it from the queue. 411*bb4ee6a4SAndroid Build Coastguard Worker /// Call `pop()` on the returned [`PeekedDescriptorChain`] to remove it from the queue. peek(&mut self) -> Option<PeekedDescriptorChain>412*bb4ee6a4SAndroid Build Coastguard Worker pub fn peek(&mut self) -> Option<PeekedDescriptorChain> { 413*bb4ee6a4SAndroid Build Coastguard Worker let desc_chain = match self { 414*bb4ee6a4SAndroid Build Coastguard Worker Queue::SplitVirtQueue(q) => q.peek(), 415*bb4ee6a4SAndroid Build Coastguard Worker Queue::PackedVirtQueue(q) => q.peek(), 416*bb4ee6a4SAndroid Build Coastguard Worker }?; 417*bb4ee6a4SAndroid Build Coastguard Worker 418*bb4ee6a4SAndroid Build Coastguard Worker Some(PeekedDescriptorChain::new(self, desc_chain)) 419*bb4ee6a4SAndroid Build Coastguard Worker } 420*bb4ee6a4SAndroid Build Coastguard Worker 421*bb4ee6a4SAndroid Build Coastguard Worker /// If a new DescriptorChain is available, returns one and removes it from the queue. pop(&mut self) -> Option<DescriptorChain>422*bb4ee6a4SAndroid Build Coastguard Worker pub fn pop(&mut self) -> Option<DescriptorChain> { 423*bb4ee6a4SAndroid Build Coastguard Worker self.peek().map(PeekedDescriptorChain::pop) 424*bb4ee6a4SAndroid Build Coastguard Worker } 425*bb4ee6a4SAndroid Build Coastguard Worker 426*bb4ee6a4SAndroid Build Coastguard Worker /// Returns `None` if stop_rx receives a value; otherwise returns the result 427*bb4ee6a4SAndroid Build Coastguard Worker /// of waiting for the next descriptor. next_async_interruptable( &mut self, queue_event: &mut EventAsync, mut stop_rx: &mut oneshot::Receiver<()>, ) -> std::result::Result<Option<DescriptorChain>, AsyncError>428*bb4ee6a4SAndroid Build Coastguard Worker pub async fn next_async_interruptable( 429*bb4ee6a4SAndroid Build Coastguard Worker &mut self, 430*bb4ee6a4SAndroid Build Coastguard Worker queue_event: &mut EventAsync, 431*bb4ee6a4SAndroid Build Coastguard Worker mut stop_rx: &mut oneshot::Receiver<()>, 432*bb4ee6a4SAndroid Build Coastguard Worker ) -> std::result::Result<Option<DescriptorChain>, AsyncError> { 433*bb4ee6a4SAndroid Build Coastguard Worker select_biased! { 434*bb4ee6a4SAndroid Build Coastguard Worker avail_desc_res = self.next_async(queue_event).fuse() => { 435*bb4ee6a4SAndroid Build Coastguard Worker Ok(Some(avail_desc_res?)) 436*bb4ee6a4SAndroid Build Coastguard Worker } 437*bb4ee6a4SAndroid Build Coastguard Worker _ = stop_rx => Ok(None), 438*bb4ee6a4SAndroid Build Coastguard Worker } 439*bb4ee6a4SAndroid Build Coastguard Worker } 440*bb4ee6a4SAndroid Build Coastguard Worker 441*bb4ee6a4SAndroid Build Coastguard Worker /// inject interrupt into guest on this queue 442*bb4ee6a4SAndroid Build Coastguard Worker /// return true: interrupt is injected into guest for this queue 443*bb4ee6a4SAndroid Build Coastguard Worker /// false: interrupt isn't injected trigger_interrupt(&mut self) -> bool444*bb4ee6a4SAndroid Build Coastguard Worker pub fn trigger_interrupt(&mut self) -> bool { 445*bb4ee6a4SAndroid Build Coastguard Worker match self { 446*bb4ee6a4SAndroid Build Coastguard Worker Queue::SplitVirtQueue(sq) => sq.trigger_interrupt(), 447*bb4ee6a4SAndroid Build Coastguard Worker Queue::PackedVirtQueue(pq) => pq.trigger_interrupt(), 448*bb4ee6a4SAndroid Build Coastguard Worker } 449*bb4ee6a4SAndroid Build Coastguard Worker } 450*bb4ee6a4SAndroid Build Coastguard Worker 451*bb4ee6a4SAndroid Build Coastguard Worker /// Restore queue from snapshot restore( queue_config: &QueueConfig, queue_value: serde_json::Value, mem: &GuestMemory, event: Event, interrupt: Interrupt, ) -> anyhow::Result<Queue>452*bb4ee6a4SAndroid Build Coastguard Worker pub fn restore( 453*bb4ee6a4SAndroid Build Coastguard Worker queue_config: &QueueConfig, 454*bb4ee6a4SAndroid Build Coastguard Worker queue_value: serde_json::Value, 455*bb4ee6a4SAndroid Build Coastguard Worker mem: &GuestMemory, 456*bb4ee6a4SAndroid Build Coastguard Worker event: Event, 457*bb4ee6a4SAndroid Build Coastguard Worker interrupt: Interrupt, 458*bb4ee6a4SAndroid Build Coastguard Worker ) -> anyhow::Result<Queue> { 459*bb4ee6a4SAndroid Build Coastguard Worker if queue_config.acked_features & 1 << VIRTIO_F_RING_PACKED != 0 { 460*bb4ee6a4SAndroid Build Coastguard Worker PackedQueue::restore(queue_value, mem, event, interrupt).map(Queue::PackedVirtQueue) 461*bb4ee6a4SAndroid Build Coastguard Worker } else { 462*bb4ee6a4SAndroid Build Coastguard Worker SplitQueue::restore(queue_value, mem, event, interrupt).map(Queue::SplitVirtQueue) 463*bb4ee6a4SAndroid Build Coastguard Worker } 464*bb4ee6a4SAndroid Build Coastguard Worker } 465*bb4ee6a4SAndroid Build Coastguard Worker 466*bb4ee6a4SAndroid Build Coastguard Worker /// "Reclaim" a queue that was given to a vhost-user backend and is now being taken back using 467*bb4ee6a4SAndroid Build Coastguard Worker /// VHOST_USER_GET_VRING_BASE. 468*bb4ee6a4SAndroid Build Coastguard Worker /// 469*bb4ee6a4SAndroid Build Coastguard Worker /// The `Queue` will have stale fields if the vhost-user backend fulfilled any virtqueue 470*bb4ee6a4SAndroid Build Coastguard Worker /// requests. This function updates the `Queue` to pick up where the backend left off. vhost_user_reclaim(&mut self, vring_base: u16)471*bb4ee6a4SAndroid Build Coastguard Worker pub fn vhost_user_reclaim(&mut self, vring_base: u16) { 472*bb4ee6a4SAndroid Build Coastguard Worker match self { 473*bb4ee6a4SAndroid Build Coastguard Worker Queue::SplitVirtQueue(q) => q.vhost_user_reclaim(vring_base), 474*bb4ee6a4SAndroid Build Coastguard Worker Queue::PackedVirtQueue(q) => q.vhost_user_reclaim(vring_base), 475*bb4ee6a4SAndroid Build Coastguard Worker } 476*bb4ee6a4SAndroid Build Coastguard Worker } 477*bb4ee6a4SAndroid Build Coastguard Worker 478*bb4ee6a4SAndroid Build Coastguard Worker /// Getter for the next index of the available ring that device will process. 479*bb4ee6a4SAndroid Build Coastguard Worker /// 480*bb4ee6a4SAndroid Build Coastguard Worker /// Not to be confused with the available ring's index field, which is the next index for the 481*bb4ee6a4SAndroid Build Coastguard Worker /// driver to fill. next_avail_to_process(&self) -> u16482*bb4ee6a4SAndroid Build Coastguard Worker pub fn next_avail_to_process(&self) -> u16 { 483*bb4ee6a4SAndroid Build Coastguard Worker match self { 484*bb4ee6a4SAndroid Build Coastguard Worker Queue::SplitVirtQueue(q) => q.next_avail_to_process(), 485*bb4ee6a4SAndroid Build Coastguard Worker Queue::PackedVirtQueue(q) => q.next_avail_to_process(), 486*bb4ee6a4SAndroid Build Coastguard Worker } 487*bb4ee6a4SAndroid Build Coastguard Worker } 488*bb4ee6a4SAndroid Build Coastguard Worker 489*bb4ee6a4SAndroid Build Coastguard Worker define_queue_method!( 490*bb4ee6a4SAndroid Build Coastguard Worker /// Getter for vector field 491*bb4ee6a4SAndroid Build Coastguard Worker vector, 492*bb4ee6a4SAndroid Build Coastguard Worker u16, 493*bb4ee6a4SAndroid Build Coastguard Worker ); 494*bb4ee6a4SAndroid Build Coastguard Worker 495*bb4ee6a4SAndroid Build Coastguard Worker define_queue_method!( 496*bb4ee6a4SAndroid Build Coastguard Worker /// Getter for descriptor area 497*bb4ee6a4SAndroid Build Coastguard Worker desc_table, 498*bb4ee6a4SAndroid Build Coastguard Worker GuestAddress, 499*bb4ee6a4SAndroid Build Coastguard Worker ); 500*bb4ee6a4SAndroid Build Coastguard Worker 501*bb4ee6a4SAndroid Build Coastguard Worker define_queue_method!( 502*bb4ee6a4SAndroid Build Coastguard Worker /// Getter for driver area 503*bb4ee6a4SAndroid Build Coastguard Worker avail_ring, 504*bb4ee6a4SAndroid Build Coastguard Worker GuestAddress, 505*bb4ee6a4SAndroid Build Coastguard Worker ); 506*bb4ee6a4SAndroid Build Coastguard Worker 507*bb4ee6a4SAndroid Build Coastguard Worker define_queue_method!( 508*bb4ee6a4SAndroid Build Coastguard Worker /// Getter for device area 509*bb4ee6a4SAndroid Build Coastguard Worker used_ring, 510*bb4ee6a4SAndroid Build Coastguard Worker GuestAddress, 511*bb4ee6a4SAndroid Build Coastguard Worker ); 512*bb4ee6a4SAndroid Build Coastguard Worker 513*bb4ee6a4SAndroid Build Coastguard Worker define_queue_method!( 514*bb4ee6a4SAndroid Build Coastguard Worker /// Return the actual size of the queue, as the driver may not set up a 515*bb4ee6a4SAndroid Build Coastguard Worker /// queue as big as the device allows. 516*bb4ee6a4SAndroid Build Coastguard Worker size, 517*bb4ee6a4SAndroid Build Coastguard Worker u16, 518*bb4ee6a4SAndroid Build Coastguard Worker ); 519*bb4ee6a4SAndroid Build Coastguard Worker 520*bb4ee6a4SAndroid Build Coastguard Worker define_queue_method!( 521*bb4ee6a4SAndroid Build Coastguard Worker /// Get a reference to the queue's event. 522*bb4ee6a4SAndroid Build Coastguard Worker event, 523*bb4ee6a4SAndroid Build Coastguard Worker &Event, 524*bb4ee6a4SAndroid Build Coastguard Worker ); 525*bb4ee6a4SAndroid Build Coastguard Worker 526*bb4ee6a4SAndroid Build Coastguard Worker define_queue_method!( 527*bb4ee6a4SAndroid Build Coastguard Worker /// Get a reference to the queue's interrupt. 528*bb4ee6a4SAndroid Build Coastguard Worker interrupt, 529*bb4ee6a4SAndroid Build Coastguard Worker &Interrupt, 530*bb4ee6a4SAndroid Build Coastguard Worker ); 531*bb4ee6a4SAndroid Build Coastguard Worker 532*bb4ee6a4SAndroid Build Coastguard Worker define_queue_method!( 533*bb4ee6a4SAndroid Build Coastguard Worker /// Puts an available descriptor head into the used ring for use by the guest. 534*bb4ee6a4SAndroid Build Coastguard Worker add_used, 535*bb4ee6a4SAndroid Build Coastguard Worker (), 536*bb4ee6a4SAndroid Build Coastguard Worker mut, 537*bb4ee6a4SAndroid Build Coastguard Worker desc_chain: DescriptorChain, 538*bb4ee6a4SAndroid Build Coastguard Worker len: u32 539*bb4ee6a4SAndroid Build Coastguard Worker ); 540*bb4ee6a4SAndroid Build Coastguard Worker 541*bb4ee6a4SAndroid Build Coastguard Worker define_queue_method!( 542*bb4ee6a4SAndroid Build Coastguard Worker /// Take snapshot of queue's current status 543*bb4ee6a4SAndroid Build Coastguard Worker snapshot, 544*bb4ee6a4SAndroid Build Coastguard Worker Result<serde_json::Value>, 545*bb4ee6a4SAndroid Build Coastguard Worker ); 546*bb4ee6a4SAndroid Build Coastguard Worker } 547*bb4ee6a4SAndroid Build Coastguard Worker 548*bb4ee6a4SAndroid Build Coastguard Worker /// A `DescriptorChain` that has been peeked from a `Queue` but not popped yet. 549*bb4ee6a4SAndroid Build Coastguard Worker /// 550*bb4ee6a4SAndroid Build Coastguard Worker /// Call [`pop()`](Self::pop) to pop this descriptor chain from the `Queue` and receive the 551*bb4ee6a4SAndroid Build Coastguard Worker /// contained `DescriptorChain` object. 552*bb4ee6a4SAndroid Build Coastguard Worker /// 553*bb4ee6a4SAndroid Build Coastguard Worker /// This object holds a mutable reference to the `Queue` to ensure it is not possible to pop or peek 554*bb4ee6a4SAndroid Build Coastguard Worker /// another descriptor while a peek is already active. Either `pop()` or drop this object before 555*bb4ee6a4SAndroid Build Coastguard Worker /// attempting to manipulate the `Queue` again. 556*bb4ee6a4SAndroid Build Coastguard Worker pub struct PeekedDescriptorChain<'q> { 557*bb4ee6a4SAndroid Build Coastguard Worker queue: &'q mut Queue, 558*bb4ee6a4SAndroid Build Coastguard Worker desc_chain: DescriptorChain, 559*bb4ee6a4SAndroid Build Coastguard Worker } 560*bb4ee6a4SAndroid Build Coastguard Worker 561*bb4ee6a4SAndroid Build Coastguard Worker impl<'q> PeekedDescriptorChain<'q> { 562*bb4ee6a4SAndroid Build Coastguard Worker /// Create a `PeekedDescriptorChain` that holds a mutable reference to its `Queue`. 563*bb4ee6a4SAndroid Build Coastguard Worker /// Use [`Queue::peek()`] rather than calling this function. new(queue: &'q mut Queue, desc_chain: DescriptorChain) -> Self564*bb4ee6a4SAndroid Build Coastguard Worker fn new(queue: &'q mut Queue, desc_chain: DescriptorChain) -> Self { 565*bb4ee6a4SAndroid Build Coastguard Worker PeekedDescriptorChain { queue, desc_chain } 566*bb4ee6a4SAndroid Build Coastguard Worker } 567*bb4ee6a4SAndroid Build Coastguard Worker 568*bb4ee6a4SAndroid Build Coastguard Worker /// Pop this descriptor chain from the queue. pop(self) -> DescriptorChain569*bb4ee6a4SAndroid Build Coastguard Worker pub fn pop(self) -> DescriptorChain { 570*bb4ee6a4SAndroid Build Coastguard Worker match self.queue { 571*bb4ee6a4SAndroid Build Coastguard Worker Queue::SplitVirtQueue(q) => q.pop_peeked(&self.desc_chain), 572*bb4ee6a4SAndroid Build Coastguard Worker Queue::PackedVirtQueue(q) => q.pop_peeked(&self.desc_chain), 573*bb4ee6a4SAndroid Build Coastguard Worker } 574*bb4ee6a4SAndroid Build Coastguard Worker self.desc_chain 575*bb4ee6a4SAndroid Build Coastguard Worker } 576*bb4ee6a4SAndroid Build Coastguard Worker } 577*bb4ee6a4SAndroid Build Coastguard Worker 578*bb4ee6a4SAndroid Build Coastguard Worker impl Deref for PeekedDescriptorChain<'_> { 579*bb4ee6a4SAndroid Build Coastguard Worker type Target = DescriptorChain; 580*bb4ee6a4SAndroid Build Coastguard Worker deref(&self) -> &Self::Target581*bb4ee6a4SAndroid Build Coastguard Worker fn deref(&self) -> &Self::Target { 582*bb4ee6a4SAndroid Build Coastguard Worker &self.desc_chain 583*bb4ee6a4SAndroid Build Coastguard Worker } 584*bb4ee6a4SAndroid Build Coastguard Worker } 585*bb4ee6a4SAndroid Build Coastguard Worker 586*bb4ee6a4SAndroid Build Coastguard Worker impl DerefMut for PeekedDescriptorChain<'_> { deref_mut(&mut self) -> &mut Self::Target587*bb4ee6a4SAndroid Build Coastguard Worker fn deref_mut(&mut self) -> &mut Self::Target { 588*bb4ee6a4SAndroid Build Coastguard Worker &mut self.desc_chain 589*bb4ee6a4SAndroid Build Coastguard Worker } 590*bb4ee6a4SAndroid Build Coastguard Worker } 591