Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Spec couche 0 — Famille process, affinité CPU (sched_setaffinity)

Spécification technique — Version 1.0 (cible kernel : Linux 6.12 LTS). Extension de la famille process.

Position

Ce document spécifie le primitif d’affinité CPU de la couche 0 — épingler une tâche sur un sous-ensemble de CPU logiques. Manque identifié en spécifiant la couche 1 : air-thread::cpu_affinity en a besoin et aucun wrapper sched_setaffinity/sched_getaffinity n’existait.

Placement : famille process. L’affinité est une propriété d’ordonnancement d’une tâche (identifiée par un Tid) ; elle vit donc avec gettid, clone3, waitid, setpgid… dans air-sys-syscall::process. Le masque réutilise CpuSet (déjà défini dans air-sys-types::system au Temps 3a pour IORING_REGISTER_IOWQ_AFF) — type partagé, non recréé. (Alternative écartée : famille system — mais system couvre l’information machine (uname, sysinfo, entropie), pas l’ordonnancement d’une tâche précise.)

Émergence (méthode doc-d’abord). Comme inotify, ce manque a été révélé par la spécification de la couche 1 — consommer la couche 0 fait apparaître ses trous. Pas de spec préalable : ce document est produit avant l’implémentation.


Surface

#![allow(unused)]
fn main() {
/// `sched_setaffinity(2)` — fixe l'affinité CPU d'une tâche : elle ne sera
/// ordonnancée que sur les CPU présents dans `cpus`. `tid = None` = tâche
/// appelante (sentinelle kernel `0` typée en `Option`, ADR-021 conv. 1).
pub fn set_cpu_affinity(tid: Option<Tid>, cpus: &CpuSet) -> Result<(), Errno>;

/// `sched_getaffinity(2)` — lit l'affinité courante **dans** `cpus` (buffer
/// fourni par l'appelant, zéro allocation). `tid = None` = tâche appelante.
pub fn get_cpu_affinity(tid: Option<Tid>, cpus: &mut CpuSet) -> Result<(), Errno>;
}
  • CpuSet réutilisé (air-sys-types::system, CPU_SETSIZE = 1024 bits / 128 octets, layout cpu_set_t) : new/set/clear/contains/count/is_empty/ as_bytes. get_cpu_affinity écrit dans le masque via un pointeur sur le &mut CpuSet (#[repr(C)] sans padding ⇒ tout motif d’octets valide) — aucun nouvel accesseur ajouté au type.
  • None = tâche appelante : traduit en pid = 0 (jamais exposé comme entier magique — ADR-021 conv. 1).
  • EINTR : sched_*affinity ne sont pas interruptibles ; aucun retry caché (ADR-021 conv. 2 reste la règle générale).

Syscalls sous-jacents (vérifiés uapi 6.12, par arche)

Syscallx86_64aarch64
sched_setaffinity203122
sched_getaffinity204123

set : le kernel lit len octets du masque (asm readonly). get : le kernel écrit dans le masque (asm sans readonly) et retourne le nombre d’octets remplis (≥ 0) ou -errno. La taille passée est size_of::<CpuSet>() (128 octets) ≥ la taille kernel de cpumask — le kernel remplit ce qu’il a et laisse le reste à zéro.

Préconditions / erreurs

  • set_cpu_affinity :
    • [Errno::EINVAL] : cpus ne contient aucun CPU autorisé / en ligne.
    • [Errno::ESRCH] : aucune tâche ne porte ce tid.
    • [Errno::EPERM] : privilèges insuffisants (changer l’affinité d’une tâche d’un autre utilisateur, ou contrainte cpuset cgroup).
  • get_cpu_affinity :
    • [Errno::ESRCH] : tid inexistant.
    • [Errno::EINVAL] : taille de masque incohérente — ne se produit pas avec un CpuSet de CPU_SETSIZE bits (toujours ≥ la taille kernel).

Tests

  • Round-trip (réel) : get l’affinité courante (count ≥ 1), set à un sous-ensemble (CPU 0, toujours en ligne), get et vérifier contains(0) + count == 1, puis restaurer l’affinité d’origine.
  • None vs Some(tid) : les deux ciblent la tâche appelante (Some(gettid())).
  • Erreurs : masque vide → EINVAL ; tid inexistant → ESRCH.
  • Cross-arch : numéros vérifiés x86_64 + aarch64 ; tests exécutés sur les deux.
  • Couverture 100 % lignes + branches (les chemins Ok/Err réels couvrent les deux bras ; affinity_pid None/Some couverts) ; aucune exception attendue.

Décisions de fond

  1. Affinité dans process (ordonnancement d’une tâche), masque partagé depuis system::CpuSet — pas de duplication de type.
  2. None = tâche appelante (pid = 0 typé), conforme ADR-021 conv. 1.
  3. Buffer fourni, zéro allocation pour get (l’appelant possède le CpuSet).
  4. Primitif débloquant la couche 1 (air-thread::cpu_affinity).

Licence du document : MPL 2.0 Statut : Spécification technique de l’affinité CPU (sched_set/getaffinity), extension de la famille process (couche 0), cible kernel 6.12 LTS.