Skip to main content

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}