net_io/driver/mod.rs
1//! Drivers: what moves the bytes.
2//!
3//! The blocking pool ships in `0.3.0`, the reactor (epoll, kqueue, IOCP) in
4//! `0.5.0`, io_uring after `1.0.0`. The [`Driver`] trait is public from `0.5.0`
5//! (Tier 3, unstable until `1.0.0`) so an executor adapter and later drivers can
6//! build on it.
7//!
8//! The interface is completion-shaped (decision D-005): an operation owns its
9//! buffers until its completion hands them back, which is what IOCP and io_uring
10//! need; epoll and kqueue adapt by making the non-blocking call when readiness
11//! arrives. Cancellation always ends in exactly one completion.
12
13// Without the reactor only the vocabulary is left, for the public interface.
14#![cfg_attr(not(feature = "reactor"), allow(dead_code, unused_imports))]
15
16#[cfg(all(feature = "reactor", windows))]
17pub(crate) mod iocp;
18#[cfg(all(feature = "reactor", unix))]
19pub(crate) mod ready;
20
21use std::collections::VecDeque;
22use std::io::IoSlice;
23use std::net::SocketAddr;
24use std::sync::Arc;
25use std::time::Duration;
26
27use crate::buf::Buffer;
28use crate::error::{NetError, OsErrorClass};
29use crate::session::{Chunk, Output};
30
31/// Which driver moves the bytes.
32///
33/// `Auto` picks the reactor where it is built and available, otherwise the
34/// blocking pool.
35///
36/// # Examples
37///
38/// ```
39/// assert_eq!(net_io::DriverKind::default(), net_io::DriverKind::Auto);
40/// ```
41#[non_exhaustive]
42#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
43pub enum DriverKind {
44 /// A bounded pool of threads, one connection per thread.
45 Blocking,
46 /// One event loop per worker (epoll, kqueue, IOCP); from `0.5.0`.
47 Reactor,
48 /// io_uring on Linux; after `1.0.0`.
49 Uring,
50 /// The reactor where available, otherwise the blocking pool.
51 #[default]
52 Auto,
53}
54
55impl DriverKind {
56 /// The driver `Auto` resolves to in this build.
57 pub(crate) fn resolve(self) -> DriverKind {
58 match self {
59 DriverKind::Auto if DriverKind::reactor_built() && !cfg!(net_io_force_blocking) => {
60 DriverKind::Reactor
61 }
62 DriverKind::Auto => DriverKind::Blocking,
63 other => other,
64 }
65 }
66
67 /// Whether this build has a reactor for this OS.
68 pub(crate) const fn reactor_built() -> bool {
69 cfg!(feature = "reactor")
70 }
71}
72
73/// A borrowed socket, as a [`Driver`] registers it.
74#[cfg(unix)]
75pub type BorrowedSocket<'a> = std::os::fd::BorrowedFd<'a>;
76/// A borrowed socket, as a [`Driver`] registers it.
77#[cfg(windows)]
78pub type BorrowedSocket<'a> = std::os::windows::io::BorrowedSocket<'a>;
79
80/// Names a registered socket. The low 32 bits index a dense table inside the
81/// driver, so keep them small; the high bits are free for a generation.
82///
83/// ```
84/// let t = net_io::Token(7);
85/// assert_eq!(t, net_io::Token(7));
86/// ```
87#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
88pub struct Token(pub u64);
89
90impl Token {
91 pub(crate) fn index(self) -> usize {
92 (self.0 & 0xFFFF_FFFF) as usize
93 }
94}
95
96/// What to do on a registered socket. The operation owns its buffers until its
97/// completion returns them.
98#[non_exhaustive]
99#[derive(Debug)]
100pub enum Operation {
101 /// Completes when a connection is waiting (accept it from the listener).
102 /// Refused on Windows, where a listener is never registered (D-016).
103 Accept {
104 /// The listener.
105 listener: Token,
106 },
107 /// Receives into `buffer`'s spare room (at most once); `Ok(0)` is end of stream.
108 Receive {
109 /// The socket.
110 token: Token,
111 /// Where the bytes land; returned by the completion.
112 buffer: Buffer,
113 },
114 /// Completes when bytes can be read, without holding a buffer: idle
115 /// connections wait this way.
116 ReceiveZero {
117 /// The socket.
118 token: Token,
119 },
120 /// Sends what `chunks` holds; the result says how many bytes went out, which
121 /// can be fewer than all of them. The chunks come back with the completion.
122 Send {
123 /// The socket.
124 token: Token,
125 /// The bytes.
126 chunks: SendChunks,
127 },
128 /// Connects a registered, non-blocking socket.
129 Connect {
130 /// The socket.
131 token: Token,
132 /// The peer.
133 addr: SocketAddr,
134 },
135 /// Completes once every other operation on the socket has; the caller then
136 /// closes it. Abortive when asked (linger 0).
137 Close {
138 /// The socket.
139 token: Token,
140 /// Reset instead of FIN.
141 abortive: bool,
142 },
143 /// Completes at once (a turn of the loop).
144 Nop {
145 /// Echoed in the completion.
146 token: Token,
147 },
148}
149
150impl Operation {
151 fn token(&self) -> Token {
152 match self {
153 Operation::Accept { listener } => *listener,
154 Operation::Receive { token, .. }
155 | Operation::ReceiveZero { token }
156 | Operation::Send { token, .. }
157 | Operation::Connect { token, .. }
158 | Operation::Close { token, .. }
159 | Operation::Nop { token } => *token,
160 }
161 }
162}
163
164/// Which operation a completion finishes.
165///
166/// ```
167/// assert_ne!(net_io::OperationKind::Receive, net_io::OperationKind::Send);
168/// ```
169#[non_exhaustive]
170#[derive(Clone, Copy, Debug, PartialEq, Eq)]
171pub enum OperationKind {
172 /// [`Operation::Accept`].
173 Accept,
174 /// [`Operation::Receive`] and [`Operation::ReceiveZero`].
175 Receive,
176 /// [`Operation::Send`].
177 Send,
178 /// [`Operation::Connect`].
179 Connect,
180 /// [`Operation::Close`].
181 Close,
182 /// [`Operation::Nop`].
183 Nop,
184}
185
186/// A finished operation.
187#[non_exhaustive]
188#[derive(Debug)]
189pub struct Completion {
190 /// The socket.
191 pub token: Token,
192 /// Which operation finished.
193 pub kind: OperationKind,
194 /// Bytes moved, or the error class. A cancelled operation is `Aborted`.
195 pub result: Result<usize, OsErrorClass>,
196 /// The receive buffer, returned with its new length.
197 pub buffer: Option<Buffer>,
198 /// The send chunks, returned as they were.
199 pub chunks: Option<SendChunks>,
200}
201
202impl Completion {
203 pub(crate) fn new(
204 token: Token,
205 kind: OperationKind,
206 result: Result<usize, OsErrorClass>,
207 ) -> Completion {
208 Completion {
209 token,
210 kind,
211 result,
212 buffer: None,
213 chunks: None,
214 }
215 }
216}
217
218/// How many completions one wait returns.
219pub(crate) const COMPLETIONS: usize = 256;
220
221/// What a wait fills; fixed capacity (256), so a wait never allocates.
222#[derive(Debug)]
223pub struct Completions {
224 items: Vec<Completion>,
225}
226
227impl Default for Completions {
228 fn default() -> Completions {
229 Completions::new()
230 }
231}
232
233impl Completions {
234 /// Room for 256 completions.
235 #[must_use]
236 pub fn new() -> Completions {
237 Completions {
238 items: Vec::with_capacity(COMPLETIONS),
239 }
240 }
241
242 /// How many completions are held.
243 #[must_use]
244 pub fn len(&self) -> usize {
245 self.items.len()
246 }
247
248 /// Whether none are held.
249 #[must_use]
250 pub fn is_empty(&self) -> bool {
251 self.items.is_empty()
252 }
253
254 /// Takes the completions out, oldest first.
255 pub fn drain(&mut self) -> impl Iterator<Item = Completion> + '_ {
256 self.items.drain(..)
257 }
258
259 #[cfg(feature = "reactor")]
260 pub(crate) fn push(&mut self, c: Completion) {
261 self.items.push(c);
262 }
263
264 #[cfg(feature = "reactor")]
265 pub(crate) fn has_room(&self) -> bool {
266 self.items.len() < COMPLETIONS
267 }
268}
269
270/// The bytes of one send: up to 64 chunks, taken from an [`Output`] or built from
271/// a pool buffer.
272#[derive(Debug, Default)]
273pub struct SendChunks {
274 pub(crate) chunks: VecDeque<Chunk>,
275}
276
277impl SendChunks {
278 /// One pool buffer.
279 #[must_use]
280 pub fn from_buffer(buffer: Buffer) -> SendChunks {
281 let mut chunks = VecDeque::with_capacity(1);
282 chunks.push_back(Chunk::Pooled(buffer, 0));
283 SendChunks { chunks }
284 }
285
286 /// Takes everything queued in `output`; give it back with [`SendChunks::restore`].
287 pub(crate) fn take(output: &mut Output) -> SendChunks {
288 SendChunks {
289 chunks: std::mem::take(&mut output.chunks),
290 }
291 }
292
293 /// Puts the chunks back into `output`, keeping the queue's allocation.
294 pub(crate) fn restore(self, output: &mut Output) {
295 output.chunks = self.chunks;
296 }
297
298 /// Bytes held.
299 #[must_use]
300 pub fn pending(&self) -> usize {
301 self.chunks.iter().map(|c| c.remaining().len()).sum()
302 }
303
304 /// Marks `n` bytes of the front chunks sent; `true` when bytes remain.
305 #[cfg(feature = "reactor")]
306 pub(crate) fn advance(&mut self, mut n: usize) -> bool {
307 while let Some(front) = self.chunks.front_mut() {
308 let rem = front.remaining().len();
309 if n < rem {
310 match front {
311 Chunk::Pooled(_, off) | Chunk::Static(_, off) => *off += n,
312 }
313 return true;
314 }
315 if self.chunks.len() == 1 {
316 return false;
317 }
318 n -= rem;
319 self.chunks.pop_front();
320 }
321 false
322 }
323
324 /// The first buffer back, for a send built with [`SendChunks::from_buffer`].
325 pub(crate) fn into_buffer(mut self) -> Option<Buffer> {
326 match self.chunks.pop_front() {
327 Some(Chunk::Pooled(b, _)) => Some(b),
328 _ => None,
329 }
330 }
331
332 /// Fills `out` with the chunks' bytes; returns how many slices.
333 #[cfg(feature = "reactor")]
334 pub(crate) fn slices<'a>(&'a self, out: &mut [IoSlice<'a>]) -> usize {
335 let mut n = 0;
336 for chunk in self.chunks.iter().take(out.len()) {
337 out[n] = IoSlice::new(chunk.remaining());
338 n += 1;
339 }
340 n
341 }
342}
343
344/// Why [`Driver::submit`] refused an operation; it comes back with its buffers.
345#[derive(Debug)]
346pub struct Rejected {
347 /// The operation.
348 pub operation: Operation,
349}
350
351/// Wakes a driver's [`Driver::wait`] from any thread.
352#[derive(Clone, Debug)]
353pub struct DriverWaker {
354 pub(crate) inner: Arc<WakerInner>,
355}
356
357#[cfg(feature = "reactor")]
358pub(crate) type WakerInner = crate::sys::PollWaker;
359#[cfg(not(feature = "reactor"))]
360#[derive(Debug)]
361pub(crate) struct WakerInner;
362
363impl DriverWaker {
364 /// Ends the current or next wait. Cheap to call repeatedly.
365 pub fn wake(&self) {
366 #[cfg(feature = "reactor")]
367 self.inner.wake();
368 }
369}
370
371/// The reactor driver for this OS: epoll, kqueue, or an I/O completion port.
372/// `capacity` sizes its tables for that many sockets; they grow past it.
373///
374/// One per worker. A token's low 32 bits index a table the driver keeps, so keep
375/// them small and dense, and put a generation in the high 32 bits to catch a
376/// completion for a slot that moved on. On Windows a listener cannot be registered
377/// and `Operation::Accept` is refused (accept from a thread of your own, D-016).
378///
379/// ```
380/// # fn main() -> Result<(), net_io::NetError> {
381/// use std::time::Duration;
382/// use net_io::{Completions, Operation, Token};
383/// let mut driver = net_io::new_reactor_driver(16)?;
384/// driver.submit(Operation::Nop { token: Token(1) }).expect("a no-op is always taken");
385/// let mut done = Completions::new();
386/// assert_eq!(driver.wait(&mut done, Some(Duration::from_secs(1)))?, 1);
387/// # Ok(())
388/// # }
389/// ```
390///
391/// # Errors
392///
393/// `DriverSetup` when the OS refuses the queue.
394#[cfg(feature = "reactor")]
395pub fn new_reactor_driver(capacity: usize) -> Result<Box<dyn Driver>, NetError> {
396 #[cfg(unix)]
397 let driver = ready::ReadyDriver::new(capacity)?;
398 #[cfg(windows)]
399 let driver = iocp::IocpDriver::new(capacity)?;
400 Ok(Box::new(driver))
401}
402
403/// A driver: one per worker, used from one thread. See the module docs.
404///
405/// Unstable until `1.0.0`. A socket must stay open from [`Driver::register`] until
406/// [`Driver::deregister`] returns.
407pub trait Driver: Send {
408 /// Which driver this is.
409 fn kind(&self) -> DriverKind;
410
411 /// Adds a non-blocking socket under `token`.
412 ///
413 /// # Errors
414 ///
415 /// `Os` when the OS refuses.
416 fn register(&mut self, socket: BorrowedSocket<'_>, token: Token) -> Result<(), NetError>;
417
418 /// Starts an operation; its completion arrives through [`Driver::wait`].
419 ///
420 /// # Errors
421 ///
422 /// [`Rejected`] gives the operation and its buffers back: the token is not
423 /// registered, or the same kind of operation is already pending on it.
424 fn submit(&mut self, operation: Operation) -> Result<(), Rejected>;
425
426 /// Fills `out` with finished operations, waiting up to `timeout` for the
427 /// first (`None`: until one finishes or the waker fires). Returns how many.
428 ///
429 /// # Errors
430 ///
431 /// `Os` when the wait itself fails.
432 fn wait(&mut self, out: &mut Completions, timeout: Option<Duration>)
433 -> Result<usize, NetError>;
434
435 /// Cancels the pending operation of kind `which`; it still completes exactly
436 /// once (with `Aborted`, or with its result if it already finished).
437 ///
438 /// # Errors
439 ///
440 /// `Os` when the OS refuses.
441 fn cancel(&mut self, token: Token, which: OperationKind) -> Result<(), NetError>;
442
443 /// Removes the socket; no completion arrives for it afterwards.
444 ///
445 /// # Errors
446 ///
447 /// `Os` when the OS refuses.
448 fn deregister(&mut self, token: Token) -> Result<(), NetError>;
449
450 /// A waker for this driver.
451 fn waker(&self) -> DriverWaker;
452}
453
454pub(crate) fn operation_token(op: &Operation) -> Token {
455 op.token()
456}