Skip to content

Commit 60d5697

Browse files
committed
Introduce Mutex<T: DeviceIoMut> adapter for DeviceIo
Many device backend drivers will mutate itself when handling IO requests. The DeviceIo trait assumes interior mutability, but it's a little complex to support interior mutability. So introduce the Mutex<T: DeviceIoMut> adapter to ease device backend driver implementations. And the Mutex<T: DeviceIoMut> adapter is an zero overhead abstraction without performance penalty. Liu Jiang <[email protected]>
1 parent 3daea68 commit 60d5697

File tree

1 file changed

+70
-3
lines changed

1 file changed

+70
-3
lines changed

src/lib.rs

Lines changed: 70 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
//! rust-vmm device model.
55
66
use std::cmp::{Ord, Ordering, PartialOrd};
7+
use std::sync::Mutex;
78

89
pub mod device_manager;
910
pub mod resources;
@@ -68,13 +69,16 @@ impl PartialOrd for IoAddress {
6869
}
6970
}
7071

71-
/// Device IO trait.
72+
/// Device IO trait adopting interior mutability pattern.
73+
///
7274
/// A device supporting memory based I/O should implement this trait, then
7375
/// register itself against the different IO type ranges it handles.
7476
/// The VMM will then dispatch IO (PIO or MMIO) VM exits by calling into the
7577
/// registered devices read or write method from this trait.
76-
/// The DeviceIo trait adopts the interior mutability pattern
77-
/// so we can get a real multiple threads handling.
78+
///
79+
/// The DeviceIo trait adopts the interior mutability pattern so we can get a real concurrent
80+
/// multiple threads handling. For device backend drivers not focusing on high performance,
81+
/// they may use the Mutex<T: DeviceIoMut> adapter to simplify implementation.
7882
pub trait DeviceIo: Send {
7983
/// Read from the guest physical address `base`, starting at `offset`.
8084
/// Result is placed in `data`.
@@ -83,3 +87,66 @@ pub trait DeviceIo: Send {
8387
/// Write `data` to the guest physical address `base`, starting from `offset`.
8488
fn write(&self, base: IoAddress, offset: IoAddress, data: &[u8]);
8589
}
90+
91+
/// Device IO trait without interior mutability.
92+
///
93+
/// Many device backend drivers will mutate itself when handling IO requests. The DeviceIo trait
94+
/// assumes interior mutability, but it's a little complex to support interior mutability. So
95+
/// the Mutex<T: DeviceIoMut> adapter may be used to ease device backend driver implementations.
96+
/// The Mutex<T: DeviceIoMut> adapter is an zero overhead abstraction without performance penalty.
97+
pub trait DeviceIoMut: Send {
98+
/// Read from the guest physical address `base`, starting at `offset`.
99+
/// Result is placed in `data`.
100+
fn read(&mut self, base: IoAddress, offset: IoAddress, data: &mut [u8]);
101+
102+
/// Write `data` to the guest physical address `base`, starting from `offset`.
103+
fn write(&mut self, base: IoAddress, offset: IoAddress, data: &[u8]);
104+
}
105+
106+
impl<T: DeviceIoMut> DeviceIo for Mutex<T> {
107+
fn read(&self, base: IoAddress, offset: IoAddress, data: &mut [u8]) {
108+
// Safe to unwrap() because we don't expect poisoned lock here.
109+
self.lock().unwrap().read(base, offset, data)
110+
}
111+
112+
fn write(&self, base: IoAddress, offset: IoAddress, data: &[u8]) {
113+
// Safe to unwrap() because we don't expect poisoned lock here.
114+
self.lock().unwrap().write(base, offset, data)
115+
}
116+
}
117+
118+
#[cfg(test)]
119+
mod tests {
120+
use super::*;
121+
use std::sync::Arc;
122+
123+
#[derive(Default)]
124+
struct MockDevice {
125+
data: u8,
126+
}
127+
128+
impl DeviceIoMut for MockDevice {
129+
fn read(&mut self, _base: IoAddress, _offset: IoAddress, data: &mut [u8]) {
130+
data[0] = self.data;
131+
}
132+
133+
fn write(&mut self, _base: IoAddress, _offset: IoAddress, data: &[u8]) {
134+
self.data = data[0];
135+
}
136+
}
137+
138+
fn register_device(device: Arc<dyn DeviceIo>) {
139+
device.write(IoAddress::Mmio(0), IoAddress::Mmio(0), &[0x10u8]);
140+
let mut buf = [0x0u8];
141+
device.read(IoAddress::Mmio(0), IoAddress::Mmio(0), &mut buf);
142+
assert_eq!(buf[0], 0x10);
143+
}
144+
145+
#[test]
146+
fn test_device_io_mut_adapter() {
147+
let device_mut = Arc::new(Mutex::new(MockDevice::default()));
148+
149+
register_device(device_mut.clone());
150+
assert_eq!(device_mut.lock().unwrap().data, 0x010);
151+
}
152+
}

0 commit comments

Comments
 (0)