1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
#[cfg(feature = "blocking-default")]
use crate::blocking::DefaultBlockingThreadPool;
use crate::{blocking::BlockingThreadPool, driver::AnyDriver};
/// I/O driver selection for the async runtime.
///
/// This enum allows choosing which I/O driver to use when building the runtime.
#[derive(Clone)]
pub enum DriverKind {
/// Uses the Mio driver for I/O operations (Unix only).
#[cfg(unix)]
Mio,
/// Uses the IOCP driver for completion-based I/O operations (Windows only).
#[cfg(windows)]
Iocp,
/// Uses the mock driver for testing purposes.
Mock,
/// Uses the io_uring driver (Linux only).
#[cfg(target_os = "linux")]
IoUring,
/// Uses the io_uring driver with custom entry count (Linux only).
#[cfg(target_os = "linux")]
IoUringEntries(u32),
/// Uses a custom io_uring driver (Linux only).
#[cfg(target_os = "linux")]
IoUringCustom(io_uring::Builder),
/// Uses a custom io_uring driver with custom entry count (Linux only).
#[cfg(target_os = "linux")]
IoUringCustomEntries(u32, io_uring::Builder),
}
impl DriverKind {
/// Creates a new runtime I/O driver from this kind.
#[inline]
pub(crate) fn into_driver(self) -> Result<AnyDriver, std::io::Error> {
match self {
#[cfg(unix)]
DriverKind::Mio => AnyDriver::new_mio(),
#[cfg(windows)]
DriverKind::Iocp => AnyDriver::new_iocp(),
DriverKind::Mock => Ok(AnyDriver::new_mock()),
#[cfg(target_os = "linux")]
DriverKind::IoUring => AnyDriver::new_uring(),
#[cfg(target_os = "linux")]
DriverKind::IoUringCustom(builder) => AnyDriver::new_uring_custom(builder),
#[cfg(target_os = "linux")]
DriverKind::IoUringEntries(entries) => AnyDriver::new_uring_with_entries(entries),
#[cfg(target_os = "linux")]
DriverKind::IoUringCustomEntries(entries, builder) => {
AnyDriver::new_uring_custom_with_entries(entries, builder)
}
}
}
}
/// Builder for configuring and creating an async runtime.
///
/// Provides a convenient way to configure the runtime's I/O driver
/// before building it.
///
/// # Examples
///
/// ```
/// use zincio::RuntimeBuilder;
///
/// let runtime = RuntimeBuilder::new()
/// .build();
/// ```
pub struct RuntimeBuilder {
driver_kind: Option<DriverKind>,
enable_timer: bool,
enable_fs_offload: bool,
blocking_pool: Option<Box<dyn BlockingThreadPool>>,
batch_size: usize,
}
impl RuntimeBuilder {
/// Creates a new runtime builder with default configuration.
///
/// By default, the builder will select the best available driver for the platform.
pub fn new() -> Self {
Self {
driver_kind: None,
enable_timer: false,
enable_fs_offload: false,
blocking_pool: None,
batch_size: 256,
}
}
/// Sets the I/O driver for the runtime.
pub fn driver(mut self, driver_kind: DriverKind) -> Self {
self.driver_kind = Some(driver_kind);
self
}
/// Enables or disables the timer for the runtime.
///
/// By default, the timer is disabled.
pub fn enable_timer(mut self, enable: bool) -> Self {
self.enable_timer = enable;
self
}
/// Enables or disables the offload of file I/O to blocking threads for the runtime.
///
/// By default, the fs offload is disabled.
pub fn enable_fs_offload(mut self, enable: bool) -> Self {
self.enable_fs_offload = enable;
self
}
/// Sets the blocking thread pool for the runtime.
pub fn blocking_pool(mut self, blocking_pool: Box<dyn BlockingThreadPool>) -> Self {
self.blocking_pool = Some(blocking_pool);
self
}
/// Sets the number of tasks polled per scheduler loop iteration (the poll
/// batch size). Larger batches amortize syscall/flush overhead across more
/// tasks; smaller batches reduce worst-case latency for a single long
/// batch. Defaults to 256.
///
/// For a thread-per-core web server handling many short-lived requests,
/// raising this (e.g. 512-1024) can improve throughput under bursty
/// accept/completion floods; lowering it tightens tail latency when a
/// single task does significant synchronous work per poll.
pub fn batch_size(mut self, batch_size: usize) -> Self {
self.batch_size = batch_size;
self
}
/// Configure the underlying `io_uring` builder.
///
/// Only used when the io_uring driver is selected (Linux). Allows
/// tuning flags such as `setup_sqpoll`, `setup_coop_taskrun`,
/// `setup_submit_all`, etc. with automatic fallback for older kernels.
///
/// # Example
/// ```
/// # #[cfg(target_os = "linux")]
/// # {
/// use zincio::RuntimeBuilder;
/// let rt = RuntimeBuilder::new()
/// .uring(|b| { b.setup_sqpoll(2000); })
/// .build()
/// .unwrap();
/// # }
/// ```
#[cfg(target_os = "linux")]
pub fn uring<F>(mut self, f: F) -> Self
where
F: FnOnce(&mut io_uring::Builder),
{
let mut builder = match self.driver_kind.take() {
Some(DriverKind::IoUringCustom(b)) => b,
_ => io_uring::IoUring::builder(),
};
f(&mut builder);
self.driver_kind = Some(DriverKind::IoUringCustom(builder));
self
}
/// Sets the default blocking thread pool for the runtime with specified maximum number of threads.
#[cfg(feature = "blocking-default")]
pub fn default_blocking_pool(mut self, max_threads: usize) -> Self {
self.blocking_pool = Some(Box::new(DefaultBlockingThreadPool::with_max_threads(
max_threads,
)));
self
}
/// Builds the async runtime with the configured settings.
///
/// If no driver was explicitly set, selects the best available driver for the platform.
pub fn build(self) -> Result<crate::executor::Runtime, std::io::Error> {
let driver = if let Some(driver_kind) = self.driver_kind {
driver_kind.into_driver()?
} else {
AnyDriver::new_best()?
};
Ok(crate::executor::Runtime::with_options(
driver,
self.enable_timer,
self.blocking_pool,
self.enable_fs_offload,
self.batch_size,
))
}
}
impl Default for RuntimeBuilder {
fn default() -> Self {
Self::new()
}
}