Skip to main content

air_sys_types/
poll.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
5//! Types de la famille `poll` — attente synchrone bornée (`ppoll(2)`).
6//!
7//! Cf. `docs/specs/layer-0/family-poll.md` (ADR-044, re-sceau `couche-0-v1.5`).
8//!
9//! - [`PollEvents`] : drapeaux `POLL*` surveillés / rendus. **Promu** ici depuis
10//!   le module `io_uring` (où il vivait au Temps 2c) et **ré-exporté** par
11//!   `io_uring` : type **inchangé sur le fil** (mêmes bits, même `repr`), zéro
12//!   rupture pour les appelants existants.
13//! - [`PollFd`] : vue **empruntée** (+0) d'un descripteur + `events` demandés +
14//!   `revents` rendus par le kernel.
15//!
16//! Le wrapper `ppoll` qui consomme ces types vit dans
17//! `air-sys-syscall::poll`.
18
19use crate::fd::BorrowedFd;
20
21bitflags::bitflags! {
22    /// Événements `poll(2)`/`epoll` surveillés/prêts (variante 32 bits
23    /// `poll32_events`). Cf. `<poll.h>` : `POLL*` / `EPOLL*` (bits bas identiques).
24    ///
25    /// Promu depuis le module `io_uring` (Temps 2c) vers la famille `poll`
26    /// (ADR-044). Les valeurs (`repr(u32)`, bits) sont **inchangées** : `io_uring`
27    /// le ré-exporte, aucun appelant n'est cassé.
28    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
29    pub struct PollEvents: u32 {
30        /// `POLLIN` : données prêtes en lecture.
31        const IN    = 0x001;
32        /// `POLLPRI` : données urgentes (out-of-band).
33        const PRI   = 0x002;
34        /// `POLLOUT` : prêt pour l'écriture.
35        const OUT   = 0x004;
36        /// `POLLERR` : condition d'erreur (toujours signalée).
37        const ERR   = 0x008;
38        /// `POLLHUP` : raccrochage (toujours signalé).
39        const HUP   = 0x010;
40        /// `POLLNVAL` : FD invalide.
41        const NVAL  = 0x020;
42        /// `POLLRDHUP` : la moitié écriture du pair est fermée.
43        const RDHUP = 0x2000;
44    }
45}
46
47/// Vue d'une entrée `struct pollfd` du kernel : un descripteur **emprunté**, les
48/// `events` surveillés et les `revents` rendus par `ppoll(2)`.
49///
50/// **Aucune prise d'ownership** : le `fd` est un [`BorrowedFd`] (+0). L'appelant
51/// reste seul propriétaire et garde la responsabilité de sa fermeture.
52///
53/// **Représentation ABI.** Le type est `#[repr(C)]` avec exactement la
54/// disposition de `struct pollfd` (`int fd; short events; short revents;` —
55/// 8 octets, alignement 4). C'est ce qui permet à `ppoll` de prendre la **slice
56/// de l'appelant directement**, sans allocation ni copie (Principe 4). Les champs
57/// `events`/`revents` du kernel sont des `short` (16 bits) : tous les drapeaux
58/// [`PollEvents`] définis tiennent dans ces 16 bits (`RDHUP = 0x2000` est le plus
59/// haut). La surface publique reste typée [`PollEvents`] via [`Self::new`],
60/// [`Self::events`] et [`Self::revents`] ; la nature 16 bits est un détail interne
61/// fidèle au kernel.
62#[repr(C)]
63#[derive(Debug, Clone, Copy)]
64pub struct PollFd<'fd> {
65    /// `int fd` — descripteur emprunté surveillé.
66    fd: BorrowedFd<'fd>,
67    /// `short events` — événements demandés (16 bits, image de [`PollEvents`]).
68    events: u16,
69    /// `short revents` — événements rendus par le kernel (vide à la construction).
70    revents: u16,
71}
72
73impl<'fd> PollFd<'fd> {
74    /// Construit une entrée de surveillance pour `fd` et les `events` demandés.
75    ///
76    /// `revents` est vide à la construction ; il sera rempli par le kernel au
77    /// retour de `ppoll`.
78    #[must_use]
79    pub fn new(fd: BorrowedFd<'fd>, events: PollEvents) -> Self {
80        Self {
81            fd,
82            events: events_to_kernel(events),
83            revents: 0,
84        }
85    }
86
87    /// Descripteur emprunté surveillé par cette entrée.
88    #[must_use]
89    pub fn fd(&self) -> BorrowedFd<'fd> {
90        self.fd
91    }
92
93    /// Événements demandés (tels que passés à [`Self::new`]).
94    #[must_use]
95    pub fn events(&self) -> PollEvents {
96        PollEvents::from_bits_retain(u32::from(self.events))
97    }
98
99    /// Événements signalés par le kernel après `ppoll` (vide si non prêt).
100    ///
101    /// Restitution **intégrale** de l'information du kernel (ADR-032) : tous les
102    /// bits rendus sont conservés, y compris ceux non modélisés par une constante
103    /// (`from_bits_retain`).
104    #[must_use]
105    pub fn revents(&self) -> PollEvents {
106        PollEvents::from_bits_retain(u32::from(self.revents))
107    }
108}
109
110/// Projette les [`PollEvents`] (32 bits) sur le champ `short events` (16 bits) du
111/// kernel.
112///
113/// Opération **totale et sans `as`** (extraction des 16 bits bas par octets) :
114/// tous les drapeaux `POLL*` définis tiennent dans 16 bits, et le champ kernel
115/// `events` est lui-même 16 bits — la projection est donc fidèle à l'ABI, jamais
116/// une troncature d'information utile.
117fn events_to_kernel(events: PollEvents) -> u16 {
118    let [low, high, _, _] = events.bits().to_le_bytes();
119    u16::from_le_bytes([low, high])
120}
121
122// Disposition ABI figée : `PollFd` doit être bit-pour-bit `struct pollfd`
123// (`int` + `short` + `short` = 8 octets, alignement 4) pour que `ppoll` passe la
124// slice de l'appelant au kernel sans copie.
125const _: () = {
126    assert!(core::mem::size_of::<PollFd<'_>>() == 8);
127    assert!(core::mem::align_of::<PollFd<'_>>() == 4);
128};
129
130#[cfg(test)]
131mod tests;