Skip to content

Commit 1ed7c2b

Browse files
committed
refactor(driver): get rid of pin
1 parent 31d234d commit 1ed7c2b

23 files changed

Lines changed: 2566 additions & 1768 deletions

File tree

compio-driver/Cargo.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@ cfg-if = { workspace = true }
2323
flume = { workspace = true, default-features = false }
2424
futures-util = { workspace = true }
2525
socket2 = { workspace = true, features = ["all"] }
26-
pin-project-lite = { workspace = true }
2726
thin-cell = { workspace = true }
2827
smallvec = { workspace = true, optional = true, features = ["union"] }
2928
synchrony = { workspace = true, features = ["waker_slot"] }
3029
bitflags = { version = "2.11.0" }
30+
paste = { workspace = true }
3131

3232
# Windows specific dependencies
3333
[target.'cfg(windows)'.dependencies]
@@ -52,7 +52,6 @@ io-uring = { version = "0.7.0", optional = true }
5252
io_uring_buf_ring = { version = "0.2.2", optional = true }
5353
once_cell = { workspace = true, optional = true }
5454
polling = { version = "3.3.0", optional = true }
55-
paste = { workspace = true }
5655
slab = { workspace = true, optional = true }
5756

5857
[dev-dependencies]

compio-driver/build.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ fn main() {
1414
freebsd: { target_os = "freebsd" },
1515
solarish: { any(target_os = "illumos", target_os = "solaris") },
1616
aio: { any(freebsd, solarish) },
17+
polling: { any(all(unix, not(target_os = "linux")), feature = "polling") },
1718
io_uring: { all(target_os = "linux", feature = "io-uring") },
1819
fusion: { all(target_os = "linux", feature = "io-uring", feature = "polling") },
1920

compio-driver/src/control.rs

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
#![allow(dead_code)]
2+
3+
use std::{
4+
mem::{ManuallyDrop, MaybeUninit},
5+
ptr,
6+
};
7+
8+
use compio_buf::IntoInner;
9+
10+
use crate::{DriverType, OpCode};
11+
12+
cfg_if::cfg_if! {
13+
if #[cfg(fusion)] {
14+
use crate::{PollOpCode, IourOpCode};
15+
} else if #[cfg(io_uring)] {
16+
use crate::OpCode as IourOpCode;
17+
} else if #[cfg(polling)]{
18+
use crate::OpCode as PollOpCode;
19+
}
20+
}
21+
22+
#[cfg(not(fusion))]
23+
type ControlInner<T> = <T as OpCode>::Control;
24+
25+
#[cfg(fusion)]
26+
enum ControlInner<T: OpCode + ?Sized> {
27+
Poll(<T as PollOpCode>::Control),
28+
IoUring(<T as IourOpCode>::Control),
29+
}
30+
31+
#[cfg(fusion)]
32+
impl<T: OpCode> ControlInner<T> {
33+
pub fn iour(&mut self) -> &mut <T as IourOpCode>::Control {
34+
match self {
35+
ControlInner::Poll(_) => unreachable!("Current driver is not `io-uring`"),
36+
ControlInner::IoUring(control) => control,
37+
}
38+
}
39+
40+
pub fn poll(&mut self) -> &mut <T as PollOpCode>::Control {
41+
match self {
42+
ControlInner::Poll(control) => control,
43+
ControlInner::IoUring(_) => unreachable!("Current driver is not `polling`"),
44+
}
45+
}
46+
}
47+
48+
/// A utility type that put a [`OpCode`] and its [`OpCode::Control`] together.
49+
///
50+
/// The only way to access this type is through [`ErasedKey`], which pins it on
51+
/// the heap and guarantees any self-referential pointers to be valid.
52+
///
53+
/// [`ErasedKey`]: crate::key::ErasedKey
54+
pub(crate) struct Carrier<T: OpCode + ?Sized> {
55+
control: MaybeUninit<ControlInner<T>>,
56+
op: T,
57+
}
58+
59+
impl<T: OpCode> IntoInner for Carrier<T> {
60+
type Inner = T;
61+
62+
fn into_inner(self) -> Self::Inner {
63+
let mut this = ManuallyDrop::new(self);
64+
unsafe {
65+
// SAFETY: `new_uninit` ensures that the type is initialized
66+
MaybeUninit::assume_init_drop(&mut this.control);
67+
// SAFETY: `self` is warpped in ManuallyDrop and is not used after here
68+
ptr::read(&this.op)
69+
}
70+
}
71+
}
72+
73+
impl<T: OpCode> Carrier<T> {
74+
/// Create a new Carrier with given OpCode.
75+
///
76+
/// # Safety
77+
///
78+
/// Returned [`Carrier`] must be [`initialized`] before converting to `dyn
79+
/// Carry` or calling any of the `as_` getters.
80+
///
81+
/// [`initialized`]: Self::init
82+
pub unsafe fn new_uninit(op: T) -> Self {
83+
Self {
84+
control: MaybeUninit::uninit(),
85+
op,
86+
}
87+
}
88+
89+
/// Init the Carrier
90+
///
91+
/// # Safety
92+
///
93+
/// `self` must have stable address until control is no longer used, include
94+
/// all function calls via `dyn Carry` and `as_` getters.
95+
pub unsafe fn init(&mut self, driver_ty: DriverType) {
96+
#[cfg(fusion)]
97+
{
98+
let control = match driver_ty {
99+
DriverType::Poll => ControlInner::Poll(unsafe { PollOpCode::init(&mut self.op) }),
100+
DriverType::IoUring => {
101+
ControlInner::IoUring(unsafe { IourOpCode::init(&mut self.op) })
102+
}
103+
DriverType::IOCP => unreachable!("Cannot be windows"),
104+
};
105+
106+
self.control.write(control);
107+
}
108+
109+
#[cfg(not(fusion))]
110+
{
111+
_ = driver_ty;
112+
113+
let control = unsafe { OpCode::init(&mut self.op) };
114+
self.control.write(control);
115+
}
116+
}
117+
118+
#[cfg(io_uring)]
119+
pub fn as_iour(&mut self) -> (&mut T, &mut <T as IourOpCode>::Control) {
120+
// SAFETY: `new_uninit` ensures that the type is initialized
121+
let control = unsafe { self.control.assume_init_mut() };
122+
#[cfg(fusion)]
123+
{
124+
(&mut self.op, control.iour())
125+
}
126+
#[cfg(not(fusion))]
127+
{
128+
(&mut self.op, control)
129+
}
130+
}
131+
132+
#[cfg(polling)]
133+
pub fn as_poll(&mut self) -> (&mut T, &mut <T as PollOpCode>::Control) {
134+
// SAFETY: `new_uninit` ensures that the type is initialized
135+
let control = unsafe { self.control.assume_init_mut() };
136+
#[cfg(fusion)]
137+
{
138+
(&mut self.op, control.poll())
139+
}
140+
#[cfg(not(fusion))]
141+
{
142+
(&mut self.op, control)
143+
}
144+
}
145+
146+
#[cfg(windows)]
147+
pub fn as_iocp(&self) -> (&T, &<T as OpCode>::Control) {
148+
// SAFETY: `new_uninit` ensures that the type is initialized
149+
let control = unsafe { self.control.assume_init_ref() };
150+
151+
(&self.op, control)
152+
}
153+
154+
#[cfg(windows)]
155+
pub fn as_iocp_mut(&mut self) -> (&mut T, &mut <T as OpCode>::Control) {
156+
// SAFETY: `new_uninit` ensures that the type is initialized
157+
let control = unsafe { self.control.assume_init_mut() };
158+
159+
(&mut self.op, control)
160+
}
161+
}
162+
163+
impl<T: OpCode + ?Sized> Drop for Carrier<T> {
164+
fn drop(&mut self) {
165+
// SAFETY: `new_uninit` ensures that the type is initialized
166+
unsafe { MaybeUninit::assume_init_drop(&mut self.control) };
167+
}
168+
}

0 commit comments

Comments
 (0)