mio.rs81.40%
1
// Copyright 2024 Google LLC2
//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 at6
//7
// https://www.apache.org/licenses/LICENSE-2.08
//9
// Unless required by applicable law or agreed to in writing, software10
// 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 and13
// limitations under the License.14
15
use std::os::fd::AsRawFd;16
use std::sync::Arc;17
use std::sync::mpsc::Receiver;18
use std::thread::JoinHandle;19
20
use mio::event::Event;21
use mio::unix::SourceFd;22
use mio::{Events, Interest, Poll, Registry, Token};23
use snafu::ResultExt;24
25
use crate::hv::IoeventFd;26
use crate::mem::mapped::{Ram, RamBus};27
use crate::sync::notifier::Notifier;28
use crate::virtio::dev::{29
ActiveBackend, Backend, BackendEvent, Context, StartParam, Virtio, WakeEvent, Worker,30
WorkerState,31
};32
use crate::virtio::queue::{Queue, QueueReg, VirtQueue};33
use crate::virtio::{IrqSender, Result, error};34
35
pub 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
where42
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
where52
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
where62
Q: VirtQueue<'m>,63
S: IrqSender,64
E: IoeventFd;65
66
fn reset(&mut self, registry: &Registry);67
}68
69
impl BackendEvent for Event {70
fn token(&self) -> u64 {45x71
self.token().0 as u6445x72
}45x73
}74
75
const TOKEN_QUEUE: u64 = 1 << 62;76
77
pub struct Mio {78
poll: Poll,79
}80
81
impl Mio {82
pub fn spawn_worker<D, S, E>(6x83
dev: D,6x84
event_rx: Receiver<WakeEvent<S, E>>,6x85
memory: Arc<RamBus>,6x86
queue_regs: Arc<[QueueReg]>,6x87
) -> Result<(JoinHandle<()>, Arc<Notifier>)>6x88
where6x89
D: VirtioMio,6x90
S: IrqSender,6x91
E: IoeventFd,6x92
{93
let poll = Poll::new().context(error::CreatePoll)?;6x94
let m = Mio { poll };6x95
Worker::spawn(dev, m, event_rx, memory, queue_regs)6x96
}6x97
}98
99
impl<D> Backend<D> for Mio100
where101
D: VirtioMio,102
{103
fn register_notifier(&mut self, token: u64) -> Result<Arc<Notifier>> {6x104
let mut notifier = Notifier::new()?;6x105
let registry = self.poll.registry();6x106
registry.register(&mut notifier, Token(token as usize), Interest::READABLE)?;6x107
Ok(Arc::new(notifier))6x108
}6x109
110
fn reset(&self, dev: &mut D) -> Result<()> {6x111
dev.reset(self.poll.registry());6x112
Ok(())6x113
}6x114
115
fn event_loop<'m, S, Q, E>(6x116
&mut self,6x117
memory: &'m Ram,6x118
context: &mut Context<D, S, E>,6x119
queues: &mut [Option<Queue<'_, 'm, Q>>],6x120
param: &StartParam<S, E>,6x121
) -> Result<()>6x122
where6x123
S: IrqSender,6x124
Q: VirtQueue<'m>,6x125
E: IoeventFd,6x126
{127
let mut events = Events::with_capacity(128);6x128
let mut active_mio = ActiveMio {6x129
queues,6x130
irq_sender: &*param.irq_sender,6x131
ioeventfds: param.ioeventfds.as_deref().unwrap_or(&[]),6x132
poll: &mut self.poll,6x133
mem: memory,6x134
};6x135
context.dev.activate(param.feature, &mut active_mio)?;6x136
let registry = active_mio.poll.registry();6x137
for (index, fd) in active_mio.ioeventfds.iter().enumerate() {6x138
if context.dev.ioeventfd_offloaded(index as u16)? {139
continue;140
}141
let token = index as u64 | TOKEN_QUEUE;142
registry143
.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_mio42x152
.poll42x153
.poll(&mut events, None)42x154
.context(error::PollEvents)?;42x155
for event in events.iter() {45x156
context.handle_event(event, &mut active_mio)?;45x157
if context.state != WorkerState::Running {45x158
break 'out;6x159
}39x160
}161
}162
let registry = active_mio.poll.registry();6x163
for (index, fd) in active_mio.ioeventfds.iter().enumerate() {6x164
if context.dev.ioeventfd_offloaded(index as u16)? {165
continue;166
}167
registry168
.deregister(&mut SourceFd(&fd.as_fd().as_raw_fd()))169
.context(error::EventSource)?;170
}171
Ok(())6x172
}6x173
}174
175
pub struct ActiveMio<'a, 'r, 'm, Q, S, E>176
where177
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
186
impl<'m, D, Q, S, E> ActiveBackend<D> for ActiveMio<'_, '_, 'm, Q, S, E>187
where188
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<()> {9x196
let token = event.token().0 as u64;9x197
if token & TOKEN_QUEUE == TOKEN_QUEUE {9x198
dev.handle_queue(token as u16, self)199
} else {200
dev.handle_event(event, self)9x201
}202
}9x203
204
fn handle_queue(&mut self, dev: &mut D, index: u16) -> Result<()> {30x205
dev.handle_queue(index, self)30x206
}30x207
}208