ferron/
runtime.rs

1use std::future::Future;
2
3// Compilation errors
4#[cfg(all(feature = "runtime-monoio", feature = "runtime-tokio"))]
5compile_error!("Can't compile Ferron with both main runtimes enabled");
6#[cfg(not(any(feature = "runtime-monoio", feature = "runtime-tokio")))]
7compile_error!("Can't compile Ferron with no main runtimes enabled");
8
9/// A representation of an asynchronous runtime
10pub struct Runtime {
11  inner: RuntimeInner,
12  io_uring_enable_configured: Option<i32>,
13}
14
15enum RuntimeInner {
16  #[cfg(all(feature = "runtime-monoio", target_os = "linux"))]
17  MonoioIouring(monoio::Runtime<monoio::time::TimeDriver<monoio::IoUringDriver>>),
18  #[cfg(feature = "runtime-monoio")]
19  MonoioLegacy(monoio::Runtime<monoio::time::TimeDriver<monoio::LegacyDriver>>),
20  #[cfg(feature = "runtime-tokio")]
21  Tokio(tokio::runtime::Runtime),
22  TokioOnly(tokio::runtime::Runtime),
23}
24
25impl Runtime {
26  /// Creates a new asynchronous runtime
27  pub fn new_runtime(enable_uring: Option<bool>) -> Result<Self, std::io::Error> {
28    #[allow(unused_mut)]
29    let mut io_uring_enable_configured = None;
30
31    #[cfg(all(feature = "runtime-monoio", target_os = "linux"))]
32    if enable_uring.is_none_or(|x| x) && monoio::utils::detect_uring() {
33      match monoio::RuntimeBuilder::<monoio::IoUringDriver>::new()
34        .enable_all()
35        .attach_thread_pool(Box::new(BlockingThreadPool))
36        .build()
37      {
38        Ok(rt) => {
39          return Ok(Self {
40            inner: RuntimeInner::MonoioIouring(rt),
41            io_uring_enable_configured,
42          });
43        }
44        Err(e) => {
45          if enable_uring.is_some() {
46            Err(e)?;
47          } else {
48            io_uring_enable_configured = e.raw_os_error();
49          }
50        }
51      }
52    }
53    #[cfg(not(all(feature = "runtime-monoio", target_os = "linux")))]
54    let _ = enable_uring;
55
56    // `io_uring` is either disabled or not supported
57    #[cfg(feature = "runtime-monoio")]
58    let rt_inner = RuntimeInner::MonoioLegacy(
59      monoio::RuntimeBuilder::<monoio::LegacyDriver>::new()
60        .enable_all()
61        .attach_thread_pool(Box::new(BlockingThreadPool))
62        .build()?,
63    );
64    #[cfg(feature = "runtime-tokio")]
65    let rt_inner = RuntimeInner::Tokio(tokio::runtime::Builder::new_current_thread().enable_all().build()?);
66
67    Ok(Self {
68      inner: rt_inner,
69      io_uring_enable_configured,
70    })
71  }
72
73  /// Creates a new asynchronous runtime using only Tokio
74  pub fn new_runtime_tokio_only() -> Result<Self, std::io::Error> {
75    Ok(Self {
76      inner: RuntimeInner::TokioOnly(tokio::runtime::Builder::new_current_thread().enable_all().build()?),
77      io_uring_enable_configured: None,
78    })
79  }
80
81  /// Return the OS error if `io_uring` couldn't be configured
82  pub fn return_io_uring_error(&self) -> Option<std::io::Error> {
83    self.io_uring_enable_configured.map(std::io::Error::from_raw_os_error)
84  }
85
86  /// Run a future on the runtime
87  pub fn run(&mut self, fut: impl Future) {
88    match self.inner {
89      #[cfg(all(feature = "runtime-monoio", target_os = "linux"))]
90      RuntimeInner::MonoioIouring(ref mut rt) => rt.block_on(fut),
91      #[cfg(feature = "runtime-monoio")]
92      RuntimeInner::MonoioLegacy(ref mut rt) => rt.block_on(fut),
93      #[cfg(feature = "runtime-tokio")]
94      RuntimeInner::Tokio(ref mut rt) => rt.block_on(async move {
95        let local_set = tokio::task::LocalSet::new();
96        local_set.run_until(future).await;
97      }),
98      RuntimeInner::TokioOnly(ref mut rt) => rt.block_on(fut),
99    };
100  }
101}
102
103pub use ferron_common::runtime::*;
104
105/// A blocking thread pool for Monoio, implemented using `blocking` crate
106#[cfg(feature = "runtime-monoio")]
107struct BlockingThreadPool;
108
109#[cfg(feature = "runtime-monoio")]
110impl monoio::blocking::ThreadPool for BlockingThreadPool {
111  #[inline]
112  fn schedule_task(&self, task: monoio::blocking::BlockingTask) {
113    blocking::unblock(move || task.run()).detach();
114  }
115}