1use std::future::Future;
2
3#[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
9pub 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 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 #[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 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 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 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#[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}