• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

google / alioth / 30699250729

01 Aug 2026 12:13PM UTC coverage: 25.403% (-2.4%) from 27.814%
30699250729

Pull #475

github

web-flow
Merge cf002a11d into e32fad138
Pull Request #475: ci: Bump the actions group with 5 updates

481 of 1568 branches covered (30.68%)

Branch coverage included in aggregate %.

3943 of 15847 relevant lines covered (24.88%)

37.26 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

74.68
/alioth/src/virtio/queue/queue.rs
1
// Copyright 2024 Google LLC
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     https://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14

15
pub mod packed;
16
pub mod split;
17

18
use std::collections::HashMap;
19
use std::fmt::Debug;
20
use std::io::{ErrorKind, IoSlice, IoSliceMut, Read, Write};
21
use std::sync::atomic::{AtomicBool, AtomicU16, AtomicU64, Ordering, fence};
22

23
use crate::bitflags;
24
use crate::mem::mapped::Ram;
25
use crate::virtio::{IrqSender, Result, error};
26

27
pub const QUEUE_SIZE_MAX: u16 = 256;
28

29
bitflags! {
30
    pub struct DescFlag(u16) {
31
        NEXT = 1 << 0;
32
        WRITE = 1 << 1;
33
        INDIRECT = 1 << 2;
34
        AVAIL = 1 << 7;
35
        USED = 1 << 15;
36
    }
37
}
38

39
#[derive(Debug, Default)]
40
pub struct QueueReg {
41
    pub size: AtomicU16,
42
    pub desc: AtomicU64,
43
    pub driver: AtomicU64,
44
    pub device: AtomicU64,
45
    pub enabled: AtomicBool,
46
}
47

48
#[derive(Debug)]
49
pub struct DescChain<'m> {
50
    id: u16,
51
    delta: u16,
52
    pub readable: Vec<IoSlice<'m>>,
53
    pub writable: Vec<IoSliceMut<'m>>,
54
}
55

56
impl DescChain<'_> {
57
    pub fn id(&self) -> u16 {
10✔
58
        self.id
10✔
59
    }
10✔
60
}
61

62
pub trait VirtQueue<'m> {
63
    type Index: Clone + Copy;
64
    const INIT_INDEX: Self::Index;
65
    fn desc_avail(&self, index: Self::Index) -> bool;
66
    fn get_avail(&self, index: Self::Index, ram: &'m Ram) -> Result<Option<DescChain<'m>>>;
67
    fn set_used(&self, index: Self::Index, id: u16, len: u32);
68
    fn enable_notification(&self, enabled: bool);
69
    fn interrupt_enabled(&self, index: Self::Index, delta: u16) -> bool;
70
    fn index_add(&self, index: Self::Index, delta: u16) -> Self::Index;
71
}
72

73
#[derive(Debug)]
74
pub enum Status {
75
    Done { len: u32 },
76
    Deferred,
77
    Break,
78
}
79

80
pub struct Queue<'r, 'm, Q>
81
where
82
    Q: VirtQueue<'m>,
83
{
84
    q: Q,
85
    avail: Q::Index,
86
    used: Q::Index,
87
    reg: &'r QueueReg,
88
    ram: &'m Ram,
89
    deferred: HashMap<u16, DescChain<'m>>,
90
}
91

92
impl<'r, 'm, Q> Queue<'r, 'm, Q>
93
where
94
    Q: VirtQueue<'m>,
95
{
96
    pub fn new(q: Q, reg: &'r QueueReg, ram: &'m Ram) -> Self {
65✔
97
        Self {
65✔
98
            q,
65✔
99
            avail: Q::INIT_INDEX,
65✔
100
            used: Q::INIT_INDEX,
65✔
101
            reg,
65✔
102
            ram,
65✔
103
            deferred: HashMap::new(),
65✔
104
        }
65✔
105
    }
65✔
106

107
    pub fn reg(&self) -> &QueueReg {
5✔
108
        self.reg
5✔
109
    }
5✔
110

111
    pub fn desc_avail(&self) -> bool {
35✔
112
        self.q.desc_avail(self.avail)
35✔
113
    }
35✔
114

×
115
    fn push_used(&mut self, chain: DescChain, len: u32) {
130✔
116
        self.q.set_used(self.used, chain.id, len);
130✔
117
        self.used = self.q.index_add(self.used, chain.delta);
130✔
118
    }
130✔
119

×
120
    pub fn handle_deferred(
15✔
121
        &mut self,
15✔
122
        id: u16,
15✔
123
        q_index: u16,
15!
124
        irq_sender: &impl IrqSender,
15✔
125
        mut op: impl FnMut(&mut DescChain) -> Result<u32>,
15✔
126
    ) -> Result<()> {
15✔
127
        let Some(mut chain) = self.deferred.remove(&id) else {
15✔
128
            return error::InvalidDescriptor { id }.fail();
5✔
129
        };
×
130
        let len = op(&mut chain)?;
10✔
131
        let delta = chain.delta;
10✔
132
        self.push_used(chain, len);
10✔
133
        if self.q.interrupt_enabled(self.used, delta) {
10!
134
            irq_sender.queue_irq(q_index);
10✔
135
        }
10✔
136
        Ok(())
10✔
137
    }
15✔
138

×
139
    pub fn handle_desc(
224✔
140
        &mut self,
224✔
141
        q_index: u16,
224✔
142
        irq_sender: &impl IrqSender,
224✔
143
        mut op: impl FnMut(&mut DescChain) -> Result<Status>,
224✔
144
    ) -> Result<()> {
224!
145
        let mut send_irq = false;
224✔
146
        let mut ret = Ok(());
224✔
147
        'out: loop {
×
148
            if !self.q.desc_avail(self.avail) {
349!
149
                break;
180✔
150
            }
169✔
151
            self.q.enable_notification(false);
169✔
152
            while let Some(mut chain) = self.q.get_avail(self.avail, self.ram)? {
299✔
153
                let delta = chain.delta;
174✔
154
                match op(&mut chain) {
174✔
155
                    Err(e) => {
10✔
156
                        ret = Err(e);
10✔
157
                        self.q.enable_notification(true);
10✔
158
                        break 'out;
×
159
                    }
×
160
                    Ok(Status::Break) => break 'out,
34✔
161
                    Ok(Status::Done { len }) => {
120✔
162
                        self.push_used(chain, len);
120✔
163
                        send_irq = send_irq || self.q.interrupt_enabled(self.used, delta);
120!
164
                    }
165
                    Ok(Status::Deferred) => {
10✔
166
                        self.deferred.insert(chain.id, chain);
10✔
167
                    }
10✔
168
                }
×
169
                self.avail = self.q.index_add(self.avail, delta);
130✔
170
            }
×
171
            self.q.enable_notification(true);
125✔
172
            fence(Ordering::SeqCst);
125✔
173
        }
×
174
        if send_irq {
224✔
175
            fence(Ordering::SeqCst);
120✔
176
            irq_sender.queue_irq(q_index);
120✔
177
        }
120✔
178
        ret
224✔
179
    }
224✔
180
}
×
181

×
182
pub fn copy_from_reader(mut reader: impl Read) -> impl FnMut(&mut DescChain) -> Result<Status> {
60✔
183
    move |chain| {
45✔
184
        let ret = reader.read_vectored(&mut chain.writable);
45!
185
        match ret {
10✔
186
            Ok(0) => {
187
                let size: usize = chain.writable.iter().map(|s| s.len()).sum();
10✔
188
                if size == 0 {
10✔
189
                    Ok(Status::Done { len: 0 })
5✔
190
                } else {
×
191
                    Ok(Status::Break)
5!
192
                }
×
193
            }
194
            Ok(len) => Ok(Status::Done { len: len as u32 }),
25✔
195
            Err(e) if e.kind() == ErrorKind::WouldBlock => Ok(Status::Break),
10✔
196
            Err(e) => Err(e.into()),
5✔
197
        }
×
198
    }
45✔
199
}
60✔
200

×
201
pub fn copy_to_writer(mut writer: impl Write) -> impl FnMut(&mut DescChain) -> Result<Status> {
45✔
202
    move |chain| {
35✔
203
        let ret = writer.write_vectored(&chain.readable);
35!
204
        match ret {
10✔
205
            Ok(0) => {
206
                let size: usize = chain.readable.iter().map(|s| s.len()).sum();
10✔
207
                if size == 0 {
10✔
208
                    Ok(Status::Done { len: 0 })
5✔
209
                } else {
×
210
                    Ok(Status::Break)
5!
211
                }
×
212
            }
213
            Ok(_) => Ok(Status::Done { len: 0 }),
15✔
214
            Err(e) if e.kind() == ErrorKind::WouldBlock => Ok(Status::Break),
10✔
215
            Err(e) => Err(e.into()),
5✔
216
        }
217
    }
35✔
218
}
45✔
219

220
#[cfg(test)]
221
#[path = "queue_test.rs"]
222
pub(in crate::virtio) mod tests;
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc