compio_driver/fusion/
mod.rs

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