Couche 0 d’Air — introduction (développeurs)
Document de présentation, pour entrer vite dans la couche 0 et savoir où trouver la
référence. Les ADR (docs/adrs/) sont des documents internes au projet ; ce
document-ci s’adresse aux développeurs qui consomment ou étudient la couche 0.
Ce qu’est la couche 0
La couche 0 est le socle syscall d’Air : une API Rust typée et sûre au-dessus des appels système Linux, sans libc. Deux crates :
air-sys-types— les types purs (aucun syscall) : identifiants typés (Pid,Tid,Uid/Gid,WatchDescriptor…),Errno, drapeaux/bitflags, types miroirs#[repr(C)]des structures kernel.air-sys-syscall— les wrappers qui appellent le kernel viacore::arch::asm!et rendent desResult<T, Errno>.
Ce que tu y trouves :
- 11 familles de syscalls :
process,fs,mem,signal,time,net,ipc,security,system,device(uevent/evdev),ebpf(bpf()+perf_event_open) ; - le module
io_uringcomplet (12 « Temps » : cœur, fichiers, réseau, async,uring_cmd, registration, buffers fournis, opérations liées, multishot, multi-thread, confinement, accès brut) — la fondation des I/O asynchrones d’Air ; - des extensions :
fs::inotify, affinité CPU (sched_set/getaffinity),mem::MmapRegion, l’extension privsep deprocess(setgroups/setres*id).
Pourquoi cette architecture
- Pas de libc, pas de
rustix. La couche 0 parle au kernel directement enasm!. Objectif : maîtrise totale du comportement, aucune dépendance C, et un capno_std-compatible. (ADR-004 : Linux tier-1.) - Sûreté par le typage.
Option<T>au lieu des sentinelles kernel (-1/0),Result<T, Errno>au lieu d’errno global,OwnedFd/BorrowedFd(RAII, pas de fuite de FD), newtypes par identifiant. (Conventions gravées : ADR-021.) - io_uring comme socle async. Le runtime asynchrone d’Air (ADR-023) se bâtit sur io_uring (ADR-022/028), pas sur epoll ni Tokio. Modèle d’ownership « slab S1 » sûr, prouvé (Miri/loom).
- Variantes modernes préférées :
clone3(pasclone),pidfd_*(pas le PID nu),waitid(paswait/waitpid),signalfd(ADR-020), les register-ops*2d’io_uring… - Rigueur de couche fondatrice : 100 % de couverture lignes + branches (hors
exceptions documentées), property-testing, fuzzing sur tout parseur de données
externes, Miri/loom sur l’
unsafe/le concurrent. (Principe 1.)
Pourquoi un noyau 6.12 minimum
6.12 est un noyau LTS (support long, cohérent avec l’horizon de durabilité d’Air),
et c’est la version où la surface io_uring dont Air dépend est disponible (jusqu’aux
opérations et register-ops récents), aux côtés de Landlock, seccomp-bpf, eBPF, etc.
Cibler une seule version stable évite l’enfer des #ifdef de compatibilité et
garde la couche 0 simple et auditable. Les numéros de syscalls et dispositions sont
vérifiés par architecture (x86_64 et aarch64) sur l’uapi 6.12.
Ce que tu n’y trouveras pas (et pourquoi)
- Aucune libc, aucun
rustix— par conception (cf. ci-dessus). - Les syscalls legacy délibérément écartés, listés et justifiés dans
UNSUPPORTED.md: les variantes anciennes supplantées par une variante moderne (clone,wait/waitpid, PID nus…), et les mécanismes io_uring obsolètes (PROVIDE_BUFFERS/REMOVE_BUFFERSop-based, register-ops v1 non taguées…). - Différés par décision (présents nulle part, et c’est voulu) : epoll (le
besoin de readiness est couvert par le
poll/multishot d’io_uring ; seuls des typesEpoll*spéculatifs existent), fanotify (primitif privilégié, pour un service de sécurité ultérieur), futex synchrone (viendra avec l’implémentation futex maison d’air-thread).
UNSUPPORTED.md est la liste de référence de ces choix.
Dépendances externes
Aucune en production. La couche 0 est du Rust pur + asm! — pas de C, pas de
libc, pas de rustix. Les seules dépendances sont test-only (property-testing,
loom, cargo-fuzz), isolées et soumises à deny.toml/cargo audit (carve-out
ADR-030). C’est inhabituel et assumé : la fondation ne dépend de rien au-dessus
du kernel.
Pour le développeur C/C++
La couche 0 n’expose pas d’ABI C, et c’est volontaire : toute sa valeur vit dans
le système de types Rust (RAII, lifetimes, Option/Result, ownership io_uring)
— qui ne traverse pas une frontière C. Si tu es en C/C++ :
- syscalls bruts → utilise ta libc (glibc/musl) ; io_uring en C → liburing ;
- fonctionnalités Air → la C ABI des couches 1+ (
air-base-lib, puisair-runtime/air-aircom), là où Air est polyglotte par conception (ADR-027) ; - asseoir des outils C sur la stack Air est l’objet d’une piste
libc-compat(exploration,docs/notes/), pas de la couche 0.
Référence — pour aller plus loin
- Specs par famille :
docs/specs/layer-0/family-*.md. - Module io_uring : inventaire maître
io-uring-0-inventaire.md+ un document par Temps (io-uring-1-core.md…io-uring-4-raw.md). - Décisions : ADR-021 (conventions couche 0), ADR-019 (erreurs), ADR-020 (signaux), ADR-022/028 (io_uring), ADR-029 (nommage), ADR-024/030/034 (dépendances), ADR-031/035 (couverture & taxonomie d’exceptions).
- Listes de référence :
UNSUPPORTED.md(legacy écartés),COVERAGE-EXCEPTIONS.md(exceptions de couverture justifiées). - API : la référence rustdoc générée (
/api/).
Licence du document : MPL 2.0.