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

google / alioth / 17016808243

17 Aug 2025 04:39AM UTC coverage: 11.971% (+1.6%) from 10.419%
17016808243

Pull #273

github

web-flow
Merge 722d5919d into 3c18ccbb6
Pull Request #273: feat: virtio packed queue

161 of 269 new or added lines in 11 files covered. (59.85%)

8 existing lines in 2 files now uncovered.

838 of 7000 relevant lines covered (11.97%)

17.36 hits per line

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

95.59
/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
#[cfg(test)]
16
#[path = "queue_test.rs"]
17
mod tests;
18

19
pub mod packed;
20
pub mod split;
21

22
use std::collections::HashMap;
23
use std::fmt::Debug;
24
use std::hash::Hash;
25
use std::io::{ErrorKind, IoSlice, IoSliceMut, Read, Write};
26
use std::sync::atomic::{AtomicBool, AtomicU16, AtomicU64, Ordering, fence};
27

28
use bitflags::bitflags;
29

30
use crate::virtio::{IrqSender, Result, error};
31

32
pub const QUEUE_SIZE_MAX: u16 = 256;
33

34
bitflags! {
10✔
35
    #[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)]
36
    pub struct DescFlag: u16 {
37
        const NEXT = 1;
38
        const WRITE = 2;
39
        const INDIRECT = 4;
40
        const AVAIL = 1 << 7;
41
        const USED = 1 << 15;
42
    }
43
}
44

45
#[derive(Debug, Default)]
46
pub struct QueueReg {
47
    pub size: AtomicU16,
48
    pub desc: AtomicU64,
49
    pub driver: AtomicU64,
50
    pub device: AtomicU64,
51
    pub enabled: AtomicBool,
52
}
53

54
#[derive(Debug)]
55
pub struct DescChain<'m> {
56
    id: u16,
57
    index: u16,
58
    count: u16,
59
    pub readable: Vec<IoSlice<'m>>,
60
    pub writable: Vec<IoSliceMut<'m>>,
61
}
62

63
impl DescChain<'_> {
64
    pub fn id(&self) -> u16 {
9✔
65
        self.id
9✔
66
    }
67
}
68

69
mod private {
70
    use crate::virtio::Result;
71
    use crate::virtio::queue::DescChain;
72

73
    pub trait VirtQueuePrivate<'m> {
74
        type Index: Clone + Copy;
75
        const INIT_INDEX: Self::Index;
76
        fn desc_avail(&self, index: Self::Index) -> bool;
77
        fn get_desc_chain(&self, index: Self::Index) -> Result<Option<DescChain<'m>>>;
78
        fn push_used(&mut self, chain: DescChain, len: u32);
79
        fn enable_notification(&self, enabled: bool);
80
        fn interrupt_enabled(&self, count: u16) -> bool;
81
        fn next_index(&self, chain: &DescChain) -> Self::Index;
82
    }
83
}
84

85
pub trait VirtQueue<'m>: private::VirtQueuePrivate<'m> {
86
    fn reg(&self) -> &QueueReg;
87
}
88

89
pub enum Status {
90
    Done { len: u32 },
91
    Deferred,
92
    Break,
93
}
94

95
pub struct Queue<'m, Q>
96
where
97
    Q: VirtQueue<'m>,
98
{
99
    q: Q,
100
    iter: Q::Index,
101
    deferred: HashMap<u16, DescChain<'m>>,
102
}
103

104
impl<'m, Q> Queue<'m, Q>
105
where
106
    Q: VirtQueue<'m>,
107
{
108
    pub fn new(q: Q) -> Self {
7✔
109
        Self {
110
            q,
111
            iter: Q::INIT_INDEX,
112
            deferred: HashMap::new(),
7✔
113
        }
114
    }
115

116
    pub fn reg(&self) -> &QueueReg {
3✔
117
        self.q.reg()
3✔
118
    }
119

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

139
    pub fn handle_desc(
37✔
140
        &mut self,
141
        q_index: u16,
142
        irq_sender: &impl IrqSender,
143
        mut op: impl FnMut(&mut DescChain) -> Result<Status>,
144
    ) -> Result<()> {
145
        let mut send_irq = false;
71✔
146
        let mut ret = Ok(());
71✔
147
        'out: loop {
×
148
            if !self.q.desc_avail(self.iter) {
102✔
149
                break;
22✔
150
            }
151
            self.q.enable_notification(false);
55✔
152
            while let Some(mut chain) = self.q.get_desc_chain(self.iter)? {
160✔
NEW
153
                let next_iter = self.q.next_index(&chain);
6✔
NEW
154
                let count = chain.count;
3✔
NEW
155
                match op(&mut chain) {
6✔
156
                    Err(e) => {
6✔
157
                        ret = Err(e);
10✔
158
                        self.q.enable_notification(true);
10✔
159
                        break 'out;
4✔
160
                    }
161
                    Ok(Status::Break) => break 'out,
8✔
162
                    Ok(Status::Done { len }) => {
14✔
NEW
163
                        self.q.push_used(chain, len);
2✔
164
                        send_irq = send_irq || self.q.interrupt_enabled(count);
14✔
165
                    }
166
                    Ok(Status::Deferred) => {
4✔
167
                        self.deferred.insert(chain.id(), chain);
18✔
168
                    }
169
                }
170
                self.iter = next_iter;
19✔
171
            }
172
            self.q.enable_notification(true);
17✔
173
            fence(Ordering::SeqCst);
3✔
174
        }
175
        if send_irq {
49✔
176
            fence(Ordering::SeqCst);
38✔
177
            irq_sender.queue_irq(q_index);
26✔
178
        }
179
        ret
3✔
180
    }
181

182
    pub fn copy_from_reader(
17✔
183
        &mut self,
184
        q_index: u16,
185
        irq_sender: &impl IrqSender,
186
        mut reader: impl Read,
187
    ) -> Result<()> {
188
        self.handle_desc(q_index, irq_sender, |chain| {
78✔
189
            let ret = reader.read_vectored(&mut chain.writable);
49✔
190
            match ret {
6✔
191
                Ok(0) => {
×
192
                    let size: usize = chain.writable.iter().map(|s| s.len()).sum();
12✔
NEW
193
                    if size == 0 {
2✔
194
                        Ok(Status::Done { len: 0 })
3✔
195
                    } else {
196
                        Ok(Status::Break)
3✔
197
                    }
198
                }
199
                Ok(len) => Ok(Status::Done { len: len as u32 }),
9✔
200
                Err(e) if e.kind() == ErrorKind::WouldBlock => Ok(Status::Break),
13✔
201
                Err(e) => Err(e.into()),
4✔
202
            }
203
        })
204
    }
205

206
    pub fn copy_to_writer(
17✔
207
        &mut self,
208
        q_index: u16,
209
        irq_sender: &impl IrqSender,
210
        mut writer: impl Write,
211
    ) -> Result<()> {
212
        self.handle_desc(q_index, irq_sender, |chain| {
78✔
213
            let ret = writer.write_vectored(&chain.readable);
49✔
214
            match ret {
6✔
215
                Ok(0) => {
×
216
                    let size: usize = chain.readable.iter().map(|s| s.len()).sum();
12✔
NEW
217
                    if size == 0 {
2✔
218
                        Ok(Status::Done { len: 0 })
3✔
219
                    } else {
220
                        Ok(Status::Break)
3✔
221
                    }
222
                }
223
                Ok(_) => Ok(Status::Done { len: 0 }),
5✔
224
                Err(e) if e.kind() == ErrorKind::WouldBlock => Ok(Status::Break),
13✔
225
                Err(e) => Err(e.into()),
4✔
226
            }
227
        })
228
    }
229
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc