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