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

google / alioth / 17114743873

21 Aug 2025 01:40AM UTC coverage: 10.634% (+0.2%) from 10.411%
17114743873

Pull #273

github

web-flow
Merge 83b666330 into 7925c9625
Pull Request #273: feat: virtio packed queue

75 of 149 new or added lines in 10 files covered. (50.34%)

532 existing lines in 15 files now uncovered.

731 of 6874 relevant lines covered (10.63%)

16.43 hits per line

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

95.45
/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 split;
20

21
use std::collections::HashMap;
22
use std::io::{ErrorKind, IoSlice, IoSliceMut, Read, Write};
23
use std::sync::atomic::{AtomicBool, AtomicU16, AtomicU64, Ordering, fence};
24

25
use crate::virtio::{IrqSender, Result, error};
26

27
pub const QUEUE_SIZE_MAX: u16 = 256;
28

29
#[derive(Debug, Default)]
30
pub struct QueueReg {
31
    pub size: AtomicU16,
32
    pub desc: AtomicU64,
33
    pub driver: AtomicU64,
34
    pub device: AtomicU64,
35
    pub enabled: AtomicBool,
36
}
37

38
#[derive(Debug)]
39
pub struct DescChain<'m> {
40
    id: u16,
41
    index: u16,
42
    pub readable: Vec<IoSlice<'m>>,
43
    pub writable: Vec<IoSliceMut<'m>>,
44
}
45

46
impl DescChain<'_> {
47
    pub fn id(&self) -> u16 {
9✔
48
        self.id
9✔
49
    }
50
}
51

52
mod private {
53
    use crate::virtio::Result;
54
    use crate::virtio::queue::DescChain;
55

56
    pub trait VirtQueuePrivate<'m> {
57
        fn desc_avail(&self, index: u16) -> bool;
58
        fn get_desc_chain(&self, index: u16) -> Result<Option<DescChain<'m>>>;
59
        fn push_used(&mut self, chain: DescChain, len: u32);
60
        fn enable_notification(&self, enabled: bool);
61
        fn interrupt_enabled(&self) -> bool;
62
        fn next_index(&self, chain: &DescChain) -> u16;
63
    }
64
}
65

66
pub trait VirtQueue<'m>: private::VirtQueuePrivate<'m> {
67
    fn reg(&self) -> &QueueReg;
68
}
69

70
#[derive(Debug)]
71
pub enum Status {
72
    Done { len: u32 },
73
    Deferred,
74
    Break,
75
}
76

77
pub struct Queue<'m, Q> {
78
    q: Q,
79
    iter: u16,
80
    deferred: HashMap<u16, DescChain<'m>>,
81
}
82

83
impl<'m, Q> Queue<'m, Q>
84
where
85
    Q: VirtQueue<'m>,
86
{
87
    pub fn new(q: Q) -> Self {
7✔
88
        q.enable_notification(true);
13✔
89
        Self {
90
            q,
91
            iter: 0,
92
            deferred: HashMap::new(),
7✔
93
        }
94
    }
95

96
    pub fn reg(&self) -> &QueueReg {
3✔
97
        self.q.reg()
3✔
98
    }
99

100
    pub fn handle_deferred(
9✔
101
        &mut self,
102
        id: u16,
103
        q_index: u16,
104
        irq_sender: &impl IrqSender,
105
        mut op: impl FnMut(&mut DescChain) -> Result<u32>,
106
    ) -> Result<()> {
107
        let Some(mut chain) = self.deferred.remove(&id) else {
22✔
108
            return error::InvalidDescriptor { id }.fail();
5✔
109
        };
110
        let len = op(&mut chain)?;
8✔
NEW
111
        self.q.push_used(chain, len);
2✔
112
        if self.q.interrupt_enabled() {
6✔
113
            irq_sender.queue_irq(q_index);
10✔
114
        }
NEW
115
        Ok(())
2✔
116
    }
117

118
    pub fn handle_desc(
37✔
119
        &mut self,
120
        q_index: u16,
121
        irq_sender: &impl IrqSender,
122
        mut op: impl FnMut(&mut DescChain) -> Result<Status>,
123
    ) -> Result<()> {
124
        let mut send_irq = false;
71✔
125
        let mut ret = Ok(());
71✔
126
        'out: loop {
×
127
            if !self.q.desc_avail(self.iter) {
102✔
128
                break;
22✔
129
            }
130
            self.q.enable_notification(false);
55✔
131
            while let Some(mut chain) = self.q.get_desc_chain(self.iter)? {
160✔
NEW
132
                let next_iter = self.q.next_index(&chain);
6✔
NEW
133
                match op(&mut chain) {
6✔
134
                    Err(e) => {
6✔
135
                        ret = Err(e);
10✔
136
                        self.q.enable_notification(true);
10✔
137
                        break 'out;
4✔
138
                    }
139
                    Ok(Status::Break) => break 'out,
8✔
140
                    Ok(Status::Done { len }) => {
14✔
NEW
141
                        self.q.push_used(chain, len);
2✔
142
                        send_irq = send_irq || self.q.interrupt_enabled();
14✔
143
                    }
144
                    Ok(Status::Deferred) => {
4✔
145
                        self.deferred.insert(chain.id(), chain);
18✔
146
                    }
147
                }
148
                self.iter = next_iter;
19✔
149
            }
150
            self.q.enable_notification(true);
17✔
151
            fence(Ordering::SeqCst);
3✔
152
        }
153
        if send_irq {
49✔
154
            fence(Ordering::SeqCst);
38✔
155
            irq_sender.queue_irq(q_index);
26✔
156
        }
157
        ret
3✔
158
    }
159
}
160

161
pub fn copy_from_reader(mut reader: impl Read) -> impl FnMut(&mut DescChain) -> Result<Status> {
20✔
162
    move |chain| {
16✔
163
        let ret = reader.read_vectored(&mut chain.writable);
58✔
164
        match ret {
8✔
NEW
165
            Ok(0) => {
×
166
                let size: usize = chain.writable.iter().map(|s| s.len()).sum();
12✔
NEW
167
                if size == 0 {
2✔
168
                    Ok(Status::Done { len: 0 })
3✔
169
                } else {
170
                    Ok(Status::Break)
3✔
171
                }
172
            }
173
            Ok(len) => Ok(Status::Done { len: len as u32 }),
14✔
174
            Err(e) if e.kind() == ErrorKind::WouldBlock => Ok(Status::Break),
13✔
175
            Err(e) => Err(e.into()),
4✔
176
        }
177
    }
178
}
179

180
pub fn copy_to_writer(mut writer: impl Write) -> impl FnMut(&mut DescChain) -> Result<Status> {
20✔
181
    move |chain| {
16✔
182
        let ret = writer.write_vectored(&chain.readable);
58✔
183
        match ret {
8✔
NEW
184
            Ok(0) => {
×
185
                let size: usize = chain.readable.iter().map(|s| s.len()).sum();
12✔
NEW
186
                if size == 0 {
2✔
187
                    Ok(Status::Done { len: 0 })
3✔
188
                } else {
189
                    Ok(Status::Break)
3✔
190
                }
191
            }
192
            Ok(_) => Ok(Status::Done { len: 0 }),
8✔
193
            Err(e) if e.kind() == ErrorKind::WouldBlock => Ok(Status::Break),
13✔
194
            Err(e) => Err(e.into()),
4✔
195
        }
196
    }
197
}
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