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

google / alioth / 17186132660

24 Aug 2025 07:45AM UTC coverage: 17.88% (+4.0%) from 13.887%
17186132660

push

github

Lencerf
test: replace tempdir with tempfile

Signed-off-by: Changyuan Lyu <changyuanl@google.com>

1336 of 7472 relevant lines covered (17.88%)

19.0 hits per line

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

95.71
/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
pub(in crate::virtio) 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::mem::mapped::Ram;
31
use crate::virtio::{IrqSender, Result, error};
32

33
pub const QUEUE_SIZE_MAX: u16 = 256;
34

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

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

55
#[derive(Debug)]
56
pub struct DescChain<'m> {
57
    id: 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 {
5✔
65
        self.id
5✔
66
    }
67
}
68

69
pub trait VirtQueue<'m> {
70
    type Index: Clone + Copy;
71
    const INIT_INDEX: Self::Index;
72
    fn desc_avail(&self, index: Self::Index) -> bool;
73
    fn get_avail(&self, index: Self::Index, ram: &'m Ram) -> Result<Option<DescChain<'m>>>;
74
    fn set_used(&self, index: Self::Index, id: u16, len: u32);
75
    fn enable_notification(&self, enabled: bool);
76
    fn interrupt_enabled(&self, index: Self::Index, delta: u16) -> bool;
77
    fn index_add(&self, index: Self::Index, delta: u16) -> Self::Index;
78
}
79

80
#[derive(Debug)]
81
pub enum Status {
82
    Done { len: u32 },
83
    Deferred,
84
    Break,
85
}
86

87
pub struct Queue<'r, 'm, Q>
88
where
89
    Q: VirtQueue<'m>,
90
{
91
    q: Q,
92
    avail: Q::Index,
93
    used: Q::Index,
94
    reg: &'r QueueReg,
95
    ram: &'m Ram,
96
    deferred: HashMap<u16, DescChain<'m>>,
97
}
98

99
impl<'r, 'm, Q> Queue<'r, 'm, Q>
100
where
101
    Q: VirtQueue<'m>,
102
{
103
    pub fn new(q: Q, reg: &'r QueueReg, ram: &'m Ram) -> Self {
15✔
104
        Self {
105
            q,
106
            avail: Q::INIT_INDEX,
107
            used: Q::INIT_INDEX,
108
            reg,
109
            ram,
110
            deferred: HashMap::new(),
15✔
111
        }
112
    }
113

114
    pub fn reg(&self) -> &QueueReg {
3✔
115
        self.reg
3✔
116
    }
117

118
    fn push_used(&mut self, chain: DescChain, len: u32) {
39✔
119
        self.q.set_used(self.used, chain.id, len);
191✔
120
        self.used = self.q.index_add(self.used, chain.delta);
115✔
121
    }
122

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

142
    pub fn handle_desc(
69✔
143
        &mut self,
144
        q_index: u16,
145
        irq_sender: &impl IrqSender,
146
        mut op: impl FnMut(&mut DescChain) -> Result<Status>,
147
    ) -> Result<()> {
148
        let mut send_irq = false;
131✔
149
        let mut ret = Ok(());
131✔
150
        'out: loop {
×
151
            if !self.q.desc_avail(self.avail) {
210✔
152
                break;
50✔
153
            }
154
            self.q.enable_notification(false);
103✔
155
            while let Some(mut chain) = self.q.get_avail(self.avail, self.ram)? {
408✔
156
                let delta = chain.delta;
7✔
157
                match op(&mut chain) {
21✔
158
                    Err(e) => {
6✔
159
                        ret = Err(e);
10✔
160
                        self.q.enable_notification(true);
10✔
161
                        break 'out;
4✔
162
                    }
163
                    Ok(Status::Break) => break 'out,
8✔
164
                    Ok(Status::Done { len }) => {
40✔
165
                        self.push_used(chain, len);
6✔
166
                        send_irq = send_irq || self.q.interrupt_enabled(self.used, delta);
40✔
167
                    }
168
                    Ok(Status::Deferred) => {
4✔
169
                        self.deferred.insert(chain.id, chain);
14✔
170
                    }
171
                }
172
                self.avail = self.q.index_add(self.avail, delta);
52✔
173
            }
174
            self.q.enable_notification(true);
43✔
175
            fence(Ordering::SeqCst);
7✔
176
        }
177
        if send_irq {
103✔
178
            fence(Ordering::SeqCst);
108✔
179
            irq_sender.queue_irq(q_index);
74✔
180
        }
181
        ret
7✔
182
    }
183
}
184

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

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

© 2025 Coveralls, Inc