Alioth Code Coverage

mio.rs81.40%

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
15use std::os::fd::AsRawFd;
16use std::sync::Arc;
17use std::sync::mpsc::Receiver;
18use std::thread::JoinHandle;
19
20use mio::event::Event;
21use mio::unix::SourceFd;
22use mio::{Events, Interest, Poll, Registry, Token};
23use snafu::ResultExt;
24
25use crate::hv::IoeventFd;
26use crate::mem::mapped::{Ram, RamBus};
27use crate::sync::notifier::Notifier;
28use crate::virtio::dev::{
29 ActiveBackend, Backend, BackendEvent, Context, StartParam, Virtio, WakeEvent, Worker,
30 WorkerState,
31};
32use crate::virtio::queue::{Queue, QueueReg, VirtQueue};
33use crate::virtio::{IrqSender, Result, error};
34
35pub trait VirtioMio: Virtio {
36 fn activate<'m, Q, S, E>(
37 &mut self,
38 feature: u128,
39 active_mio: &mut ActiveMio<'_, '_, 'm, Q, S, E>,
40 ) -> Result<()>
41 where
42 Q: VirtQueue<'m>,
43 S: IrqSender,
44 E: IoeventFd;
45
46 fn handle_queue<'m, Q, S, E>(
47 &mut self,
48 index: u16,
49 active_mio: &mut ActiveMio<'_, '_, 'm, Q, S, E>,
50 ) -> Result<()>
51 where
52 Q: VirtQueue<'m>,
53 S: IrqSender,
54 E: IoeventFd;
55
56 fn handle_event<'m, Q, S, E>(
57 &mut self,
58 event: &Event,
59 active_mio: &mut ActiveMio<'_, '_, 'm, Q, S, E>,
60 ) -> Result<()>
61 where
62 Q: VirtQueue<'m>,
63 S: IrqSender,
64 E: IoeventFd;
65
66 fn reset(&mut self, registry: &Registry);
67}
68
69impl BackendEvent for Event {
70 fn token(&self) -> u64 {42x
71 self.token().0 as u6442x
72 }42x
73}
74
75const TOKEN_QUEUE: u64 = 1 << 62;
76
77pub struct Mio {
78 poll: Poll,
79}
80
81impl Mio {
82 pub fn spawn_worker<D, S, E>(6x
83 dev: D,6x
84 event_rx: Receiver<WakeEvent<S, E>>,6x
85 memory: Arc<RamBus>,6x
86 queue_regs: Arc<[QueueReg]>,6x
87 ) -> Result<(JoinHandle<()>, Arc<Notifier>)>6x
88 where6x
89 D: VirtioMio,6x
90 S: IrqSender,6x
91 E: IoeventFd,6x
92 {
93 let poll = Poll::new().context(error::CreatePoll)?;6x
94 let m = Mio { poll };6x
95 Worker::spawn(dev, m, event_rx, memory, queue_regs)6x
96 }6x
97}
98
99impl<D> Backend<D> for Mio
100where
101 D: VirtioMio,
102{
103 fn register_notifier(&mut self, token: u64) -> Result<Arc<Notifier>> {6x
104 let mut notifier = Notifier::new()?;6x
105 let registry = self.poll.registry();6x
106 registry.register(&mut notifier, Token(token as usize), Interest::READABLE)?;6x
107 Ok(Arc::new(notifier))6x
108 }6x
109
110 fn reset(&self, dev: &mut D) -> Result<()> {6x
111 dev.reset(self.poll.registry());6x
112 Ok(())6x
113 }6x
114
115 fn event_loop<'m, S, Q, E>(6x
116 &mut self,6x
117 memory: &'m Ram,6x
118 context: &mut Context<D, S, E>,6x
119 queues: &mut [Option<Queue<'_, 'm, Q>>],6x
120 param: &StartParam<S, E>,6x
121 ) -> Result<()>6x
122 where6x
123 S: IrqSender,6x
124 Q: VirtQueue<'m>,6x
125 E: IoeventFd,6x
126 {
127 let mut events = Events::with_capacity(128);6x
128 let mut active_mio = ActiveMio {6x
129 queues,6x
130 irq_sender: &*param.irq_sender,6x
131 ioeventfds: param.ioeventfds.as_deref().unwrap_or(&[]),6x
132 poll: &mut self.poll,6x
133 mem: memory,6x
134 };6x
135 context.dev.activate(param.feature, &mut active_mio)?;6x
136 let registry = active_mio.poll.registry();6x
137 for (index, fd) in active_mio.ioeventfds.iter().enumerate() {6x
138 if context.dev.ioeventfd_offloaded(index as u16)? {
139 continue;
140 }
141 let token = index as u64 | TOKEN_QUEUE;
142 registry
143 .register(
144 &mut SourceFd(&fd.as_fd().as_raw_fd()),
145 Token(token as usize),
146 Interest::READABLE,
147 )
148 .context(error::EventSource)?;
149 }
150 'out: loop {
151 active_mio39x
152 .poll39x
153 .poll(&mut events, None)39x
154 .context(error::PollEvents)?;39x
155 for event in events.iter() {42x
156 context.handle_event(event, &mut active_mio)?;42x
157 if context.state != WorkerState::Running {42x
158 break 'out;6x
159 }36x
160 }
161 }
162 let registry = active_mio.poll.registry();6x
163 for (index, fd) in active_mio.ioeventfds.iter().enumerate() {6x
164 if context.dev.ioeventfd_offloaded(index as u16)? {
165 continue;
166 }
167 registry
168 .deregister(&mut SourceFd(&fd.as_fd().as_raw_fd()))
169 .context(error::EventSource)?;
170 }
171 Ok(())6x
172 }6x
173}
174
175pub struct ActiveMio<'a, 'r, 'm, Q, S, E>
176where
177 Q: VirtQueue<'m>,
178{
179 pub queues: &'a mut [Option<Queue<'r, 'm, Q>>],
180 pub irq_sender: &'a S,
181 pub ioeventfds: &'a [E],
182 pub poll: &'a mut Poll,
183 pub mem: &'m Ram,
184}
185
186impl<'m, D, Q, S, E> ActiveBackend<D> for ActiveMio<'_, '_, 'm, Q, S, E>
187where
188 D: VirtioMio,
189 Q: VirtQueue<'m>,
190 S: IrqSender,
191 E: IoeventFd,
192{
193 type Event = Event;
194
195 fn handle_event(&mut self, dev: &mut D, event: &Self::Event) -> Result<()> {9x
196 let token = event.token().0 as u64;9x
197 if token & TOKEN_QUEUE == TOKEN_QUEUE {9x
198 dev.handle_queue(token as u16, self)
199 } else {
200 dev.handle_event(event, self)9x
201 }
202 }9x
203
204 fn handle_queue(&mut self, dev: &mut D, index: u16) -> Result<()> {30x
205 dev.handle_queue(index, self)30x
206 }30x
207}
208