1use std::{any::Any, cell::RefCell, fmt, io, panic, pin::Pin, rc::Rc};
3
4use crate::rt::Runtime;
5
6pub type BlockFuture = Pin<Box<dyn Future<Output = ()>>>;
7
8#[derive(Copy, Clone, Debug, PartialEq, Eq)]
9pub enum DriverType {
10 Poll,
11 IoUring,
12 Iocp,
13}
14
15impl DriverType {
16 pub const fn name(&self) -> &'static str {
17 match self {
18 DriverType::Poll => "polling",
19 DriverType::IoUring => "io-uring",
20 DriverType::Iocp => "iocp",
21 }
22 }
23
24 pub const fn is_polling(&self) -> bool {
25 matches!(self, &DriverType::Poll)
26 }
27}
28
29pub trait Runner: Send + Sync + 'static {
30 fn block_on(&self, fut: BlockFuture) -> Result<(), Box<dyn Any + Send>>;
31}
32
33pub trait Driver: 'static {
34 fn handle(&self) -> Box<dyn Notify>;
35
36 fn run(&self, rt: &Runtime) -> io::Result<()>;
37
38 fn clear(&self) {}
39}
40
41#[derive(Copy, Clone, Debug, PartialEq, Eq)]
42pub enum PollResult {
43 Ready,
44 Pending,
45 PollAgain,
46}
47
48pub trait Notify: Send + Sync + fmt::Debug + 'static {
55 fn notify(&self) -> io::Result<()>;
56}
57
58#[cfg(windows)]
59#[macro_export]
60macro_rules! syscall {
61 (BOOL, $e:expr) => {
62 $crate::syscall!($e, == 0)
63 };
64 (SOCKET, $e:expr) => {
65 $crate::syscall!($e, != 0)
66 };
67 (HANDLE, $e:expr) => {
68 $crate::syscall!($e, == ::windows_sys::Win32::Foundation::INVALID_HANDLE_VALUE)
69 };
70 ($e:expr, $op: tt $rhs: expr) => {{
71 #[allow(unused_unsafe)]
72 let res = unsafe { $e };
73 if res $op $rhs {
74 Err(::std::io::Error::last_os_error())
75 } else {
76 Ok(res)
77 }
78 }};
79}
80
81#[cfg(unix)]
83#[macro_export]
84macro_rules! syscall {
85 (break $e:expr) => {
86 loop {
87 match $crate::syscall!($e) {
88 Ok(fd) => break ::std::task::Poll::Ready(Ok(fd as usize)),
89 Err(e) if e.kind() == ::std::io::ErrorKind::WouldBlock || e.raw_os_error() == Some(::libc::EINPROGRESS)
90 => break ::std::task::Poll::Pending,
91 Err(e) if e.kind() == ::std::io::ErrorKind::Interrupted => {},
92 Err(e) => break ::std::task::Poll::Ready(Err(e)),
93 }
94 }
95 };
96 ($e:expr, $f:ident($fd:expr)) => {
97 match $crate::syscall!(break $e) {
98 ::std::task::Poll::Pending => Ok($crate::sys::Decision::$f($fd)),
99 ::std::task::Poll::Ready(Ok(res)) => Ok($crate::sys::Decision::Completed(res)),
100 ::std::task::Poll::Ready(Err(e)) => Err(e),
101 }
102 };
103 ($e:expr) => {{
104 #[allow(unused_unsafe)]
105 let res = unsafe { $e };
106 if res == -1 {
107 Err(::std::io::Error::last_os_error())
108 } else {
109 Ok(res)
110 }
111 }};
112}
113
114pub(super) fn block_on<F, R>(run: &dyn Runner, fut: F) -> Result<R, Box<dyn Any + Send>>
116where
117 F: Future<Output = R> + 'static,
118 R: 'static,
119{
120 let result = Rc::new(RefCell::new(None));
122 let result_inner = result.clone();
123
124 ntex_error::set_backtrace_start_alt("ntex/ntex-rt/src/driver.rs", 0);
125 let _finalize = FinalizeArbiter;
128 run.block_on(Box::pin(async move {
129 let r = fut.await;
130 *result_inner.borrow_mut() = Some(r);
131 }))?;
132
133 crate::arbiter::run_shutdown_callbacks();
134 unsafe {
135 crate::remove_all_items();
136 }
137 Ok(result.borrow_mut().take().unwrap())
138}
139
140struct FinalizeArbiter;
141
142impl Drop for FinalizeArbiter {
143 fn drop(&mut self) {
144 if let Some(arb) = crate::Arbiter::try_current() {
145 arb.finalize();
146 }
147 }
148}
149
150pub(super) fn block_on_panic<F, R>(run: &dyn Runner, fut: F) -> R
151where
152 F: Future<Output = R> + 'static,
153 R: 'static,
154{
155 match block_on(run, fut) {
156 Ok(v) => v,
157 Err(e) => panic::resume_unwind(e),
158 }
159}
160
161#[cfg(test)]
162mod tests {
163 use super::DriverType;
164
165 #[test]
166 fn driver_type() {
167 assert_eq!(DriverType::Poll.name(), "polling");
168 assert_eq!(DriverType::IoUring.name(), "io-uring");
169 assert_eq!(DriverType::Iocp.name(), "iocp");
170 assert!(DriverType::Poll.is_polling());
171 assert!(!DriverType::IoUring.is_polling());
172 assert!(!DriverType::Iocp.is_polling());
173 }
174}