Skip to main content

ntex_rt/
driver.rs

1//! The platform-specified driver.
2use 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 {
49    fn notify(&self) -> io::Result<()>;
50}
51
52#[cfg(windows)]
53#[macro_export]
54macro_rules! syscall {
55    (BOOL, $e:expr) => {
56        $crate::syscall!($e, == 0)
57    };
58    (SOCKET, $e:expr) => {
59        $crate::syscall!($e, != 0)
60    };
61    (HANDLE, $e:expr) => {
62        $crate::syscall!($e, == ::windows_sys::Win32::Foundation::INVALID_HANDLE_VALUE)
63    };
64    ($e:expr, $op: tt $rhs: expr) => {{
65        #[allow(unused_unsafe)]
66        let res = unsafe { $e };
67        if res $op $rhs {
68            Err(::std::io::Error::last_os_error())
69        } else {
70            Ok(res)
71        }
72    }};
73}
74
75/// Helper macro to execute a system call
76#[cfg(unix)]
77#[macro_export]
78macro_rules! syscall {
79    (break $e:expr) => {
80        loop {
81            match $crate::syscall!($e) {
82                Ok(fd) => break ::std::task::Poll::Ready(Ok(fd as usize)),
83                Err(e) if e.kind() == ::std::io::ErrorKind::WouldBlock || e.raw_os_error() == Some(::libc::EINPROGRESS)
84                    => break ::std::task::Poll::Pending,
85                Err(e) if e.kind() == ::std::io::ErrorKind::Interrupted => {},
86                Err(e) => break ::std::task::Poll::Ready(Err(e)),
87            }
88        }
89    };
90    ($e:expr, $f:ident($fd:expr)) => {
91        match $crate::syscall!(break $e) {
92            ::std::task::Poll::Pending => Ok($crate::sys::Decision::$f($fd)),
93            ::std::task::Poll::Ready(Ok(res)) => Ok($crate::sys::Decision::Completed(res)),
94            ::std::task::Poll::Ready(Err(e)) => Err(e),
95        }
96    };
97    ($e:expr) => {{
98        #[allow(unused_unsafe)]
99        let res = unsafe { $e };
100        if res == -1 {
101            Err(::std::io::Error::last_os_error())
102        } else {
103            Ok(res)
104        }
105    }};
106}
107
108/// Execute a future with custom `block_on` method and wait for result
109pub(super) fn block_on<F, R>(run: &dyn Runner, fut: F) -> Result<R, Box<dyn Any + Send>>
110where
111    F: Future<Output = R> + 'static,
112    R: 'static,
113{
114    // run loop
115    let result = Rc::new(RefCell::new(None));
116    let result_inner = result.clone();
117
118    ntex_error::set_backtrace_start_alt("ntex/ntex-rt/src/driver.rs", 0);
119    run.block_on(Box::pin(async move {
120        let r = fut.await;
121        *result_inner.borrow_mut() = Some(r);
122    }))?;
123
124    unsafe {
125        crate::remove_all_items();
126    }
127    Ok(result.borrow_mut().take().unwrap())
128}
129
130pub(super) fn block_on_panic<F, R>(run: &dyn Runner, fut: F) -> R
131where
132    F: Future<Output = R> + 'static,
133    R: 'static,
134{
135    match block_on(run, fut) {
136        Ok(v) => v,
137        Err(e) => panic::resume_unwind(e),
138    }
139}