Skip to main content

compio_driver/sys/fusion/
mod.rs

1pub(crate) mod op;
2
3#[cfg_attr(all(doc, docsrs), doc(cfg(all())))]
4pub use std::os::fd::{AsFd, AsRawFd, BorrowedFd, OwnedFd, RawFd};
5use std::{
6    io,
7    task::{Poll, Waker},
8    time::Duration,
9};
10
11use compio_log::warn;
12pub use iour::{IourOpCode, OpEntry};
13pub use poll::{Decision, OpType, PollOpCode};
14
15pub(crate) use super::iour::is_op_supported;
16use super::{iour, poll};
17pub use crate::driver_type::DriverType; // Re-export so current user won't be broken
18use crate::{BufferPool, Key, ProactorBuilder, key::ErasedKey};
19
20pub enum Extra {
21    Poll(poll::Extra),
22    IoUring(iour::Extra),
23}
24
25impl From<poll::Extra> for Extra {
26    fn from(inner: poll::Extra) -> Self {
27        Self::Poll(inner)
28    }
29}
30
31impl From<iour::Extra> for Extra {
32    fn from(inner: iour::Extra) -> Self {
33        Self::IoUring(inner)
34    }
35}
36
37#[allow(dead_code)]
38impl super::Extra {
39    pub(in crate::sys) fn try_as_iour(&self) -> Option<&iour::Extra> {
40        if let Extra::IoUring(extra) = &self.0 {
41            Some(extra)
42        } else {
43            None
44        }
45    }
46
47    pub(in crate::sys) fn try_as_iour_mut(&mut self) -> Option<&mut iour::Extra> {
48        if let Extra::IoUring(extra) = &mut self.0 {
49            Some(extra)
50        } else {
51            None
52        }
53    }
54
55    pub(in crate::sys) fn try_as_poll(&self) -> Option<&poll::Extra> {
56        if let Extra::Poll(extra) = &self.0 {
57            Some(extra)
58        } else {
59            None
60        }
61    }
62
63    pub(in crate::sys) fn try_as_poll_mut(&mut self) -> Option<&mut poll::Extra> {
64        if let Extra::Poll(extra) = &mut self.0 {
65            Some(extra)
66        } else {
67            None
68        }
69    }
70}
71
72/// Fused [`OpCode`]
73///
74/// This trait encapsulates both operation for `io-uring` and `polling`
75pub trait OpCode: PollOpCode + IourOpCode {}
76
77impl<T: PollOpCode + IourOpCode + ?Sized> OpCode for T {}
78
79#[allow(clippy::large_enum_variant)]
80enum FuseDriver {
81    Poll(poll::Driver),
82    IoUring(iour::Driver),
83}
84
85/// Low-level fusion driver.
86pub(crate) struct Driver {
87    fuse: FuseDriver,
88}
89
90impl Driver {
91    /// Create a new fusion driver with given number of entries
92    pub fn new(builder: &ProactorBuilder) -> io::Result<Self> {
93        let (ty, fallback) = match &builder.driver_type {
94            Some(t) => (*t, false),
95            None => (DriverType::suggest(), true),
96        };
97        match ty {
98            DriverType::Poll => Ok(Self {
99                fuse: FuseDriver::Poll(poll::Driver::new(builder)?),
100            }),
101            DriverType::IoUring => match iour::Driver::new(builder) {
102                Ok(driver) => Ok(Self {
103                    fuse: FuseDriver::IoUring(driver),
104                }),
105                // use _e here so that when `enable_log` is disabled, clippy won't complain
106                Err(_e) if fallback => {
107                    warn!("Fail to create io-uring driver: {_e:?}, fallback to polling driver.");
108                    Ok(Self {
109                        fuse: FuseDriver::Poll(poll::Driver::new(builder)?),
110                    })
111                }
112                Err(e) => Err(e),
113            },
114            _ => unreachable!("Fuse driver will only be enabled on linux"),
115        }
116    }
117
118    #[allow(dead_code)]
119    pub fn as_iour(&self) -> Option<&iour::Driver> {
120        if let FuseDriver::IoUring(driver) = &self.fuse {
121            Some(driver)
122        } else {
123            None
124        }
125    }
126
127    pub fn driver_type(&self) -> DriverType {
128        match &self.fuse {
129            FuseDriver::Poll(driver) => driver.driver_type(),
130            FuseDriver::IoUring(driver) => driver.driver_type(),
131        }
132    }
133
134    pub fn default_extra(&self) -> Extra {
135        match &self.fuse {
136            FuseDriver::Poll(driver) => Extra::Poll(driver.default_extra()),
137            FuseDriver::IoUring(driver) => Extra::IoUring(driver.default_extra()),
138        }
139    }
140
141    pub fn attach(&mut self, fd: RawFd) -> io::Result<()> {
142        match &mut self.fuse {
143            FuseDriver::Poll(driver) => driver.attach(fd),
144            FuseDriver::IoUring(driver) => driver.attach(fd),
145        }
146    }
147
148    pub fn cancel<T>(&mut self, key: Key<T>) {
149        match &mut self.fuse {
150            FuseDriver::Poll(driver) => driver.cancel(key),
151            FuseDriver::IoUring(driver) => driver.cancel(key),
152        }
153    }
154
155    pub fn push(&mut self, op: ErasedKey) -> Poll<io::Result<usize>> {
156        match &mut self.fuse {
157            FuseDriver::Poll(driver) => driver.push(op),
158            FuseDriver::IoUring(driver) => driver.push(op),
159        }
160    }
161
162    pub fn poll(&mut self, timeout: Option<Duration>) -> io::Result<()> {
163        match &mut self.fuse {
164            FuseDriver::Poll(driver) => driver.poll(timeout),
165            FuseDriver::IoUring(driver) => driver.poll(timeout),
166        }
167    }
168
169    pub fn waker(&self) -> Waker {
170        match &self.fuse {
171            FuseDriver::Poll(driver) => driver.waker(),
172            FuseDriver::IoUring(driver) => driver.waker(),
173        }
174    }
175
176    pub fn create_buffer_pool(
177        &mut self,
178        buffer_len: u16,
179        buffer_size: usize,
180    ) -> io::Result<BufferPool> {
181        match &mut self.fuse {
182            FuseDriver::IoUring(driver) => Ok(driver.create_buffer_pool(buffer_len, buffer_size)?),
183            FuseDriver::Poll(driver) => Ok(driver.create_buffer_pool(buffer_len, buffer_size)?),
184        }
185    }
186
187    /// # Safety
188    ///
189    /// caller must make sure release the buffer pool with correct driver
190    pub unsafe fn release_buffer_pool(&mut self, buffer_pool: BufferPool) -> io::Result<()> {
191        unsafe {
192            match &mut self.fuse {
193                FuseDriver::Poll(driver) => driver.release_buffer_pool(buffer_pool),
194                FuseDriver::IoUring(driver) => driver.release_buffer_pool(buffer_pool),
195            }
196        }
197    }
198}
199
200impl AsRawFd for Driver {
201    fn as_raw_fd(&self) -> RawFd {
202        match &self.fuse {
203            FuseDriver::Poll(driver) => driver.as_raw_fd(),
204            FuseDriver::IoUring(driver) => driver.as_raw_fd(),
205        }
206    }
207}