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

google / alioth / 17016724345

17 Aug 2025 04:29AM UTC coverage: 10.467% (+0.05%) from 10.419%
17016724345

Pull #273

github

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

63 of 140 new or added lines in 9 files covered. (45.0%)

8 existing lines in 2 files now uncovered.

719 of 6869 relevant lines covered (10.47%)

16.19 hits per line

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

77.27
/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<'_> {
NEW
47
    pub fn id(&self) -> u16 {
×
NEW
48
        self.id
×
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
pub enum Status {
71
    Done { len: u32 },
72
    Deferred,
73
    Break,
74
}
75

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

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

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

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

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

159
    pub fn copy_from_reader(
17✔
160
        &mut self,
161
        q_index: u16,
162
        irq_sender: &impl IrqSender,
163
        mut reader: impl Read,
164
    ) -> Result<()> {
165
        self.handle_desc(q_index, irq_sender, |chain| {
78✔
166
            let ret = reader.read_vectored(&mut chain.writable);
49✔
167
            match ret {
6✔
168
                Ok(0) => {
×
169
                    let size: usize = chain.writable.iter().map(|s| s.len()).sum();
12✔
NEW
170
                    if size == 0 {
2✔
171
                        Ok(Status::Done { len: 0 })
3✔
172
                    } else {
173
                        Ok(Status::Break)
3✔
174
                    }
175
                }
176
                Ok(len) => Ok(Status::Done { len: len as u32 }),
9✔
177
                Err(e) if e.kind() == ErrorKind::WouldBlock => Ok(Status::Break),
13✔
178
                Err(e) => Err(e.into()),
4✔
179
            }
180
        })
181
    }
182

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