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

google / alioth / 17185180867

24 Aug 2025 06:16AM UTC coverage: 13.911% (+0.02%) from 13.887%
17185180867

Pull #277

github

web-flow
Merge 15d9ad867 into 861f19073
Pull Request #277: feat: Unix domain socket based vsock device

50 of 86 new or added lines in 9 files covered. (58.14%)

69 existing lines in 6 files now uncovered.

977 of 7023 relevant lines covered (13.91%)

17.72 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
    delta: 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, delta: 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
#[derive(Debug)]
90
pub enum Status {
91
    Done { len: u32 },
92
    Deferred,
93
    Break,
94
}
95

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

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

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

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

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

184
pub fn copy_from_reader(mut reader: impl Read) -> impl FnMut(&mut DescChain) -> Result<Status> {
27✔
185
    move |chain| {
21✔
186
        let ret = reader.read_vectored(&mut chain.writable);
75✔
187
        match ret {
10✔
UNCOV
188
            Ok(0) => {
×
189
                let size: usize = chain.writable.iter().map(|s| s.len()).sum();
12✔
UNCOV
190
                if size == 0 {
2✔
191
                    Ok(Status::Done { len: 0 })
3✔
192
                } else {
193
                    Ok(Status::Break)
3✔
194
                }
195
            }
196
            Ok(len) => Ok(Status::Done { len: len as u32 }),
23✔
197
            Err(e) if e.kind() == ErrorKind::WouldBlock => Ok(Status::Break),
13✔
198
            Err(e) => Err(e.into()),
4✔
199
        }
200
    }
201
}
202

203
pub fn copy_to_writer(mut writer: impl Write) -> impl FnMut(&mut DescChain) -> Result<Status> {
20✔
204
    move |chain| {
16✔
205
        let ret = writer.write_vectored(&chain.readable);
58✔
206
        match ret {
8✔
UNCOV
207
            Ok(0) => {
×
208
                let size: usize = chain.readable.iter().map(|s| s.len()).sum();
12✔
UNCOV
209
                if size == 0 {
2✔
210
                    Ok(Status::Done { len: 0 })
3✔
211
                } else {
212
                    Ok(Status::Break)
3✔
213
                }
214
            }
215
            Ok(_) => Ok(Status::Done { len: 0 }),
8✔
216
            Err(e) if e.kind() == ErrorKind::WouldBlock => Ok(Status::Break),
13✔
217
            Err(e) => Err(e.into()),
4✔
218
        }
219
    }
220
}
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