zerodds_rt_linux/lib.rs
1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2026 ZeroDDS Contributors
3
4//! Crate `zerodds-rt-linux`. Safety classification: **COMFORT** (FFI boundary
5//! by convention — see `docs/architecture/04_safety_by_architecture.md`
6//! §2.3 COMFORT class).
7//!
8//! Linux real-time scheduling adapter — `sched_setattr` (FIFO/RR/DEADLINE)
9//! + `sched_setaffinity` (CPU pinning) + `current_scheduler()`.
10//!
11//! ## Layer position
12//!
13//! Layer 4 — core services. Linux-specific FFI layer; on
14//! non-Linux targets all public APIs are `io::Error::Unsupported`.
15//!
16//! # Why COMFORT instead of SAFE
17//!
18//! This crate is the only place in the ZeroDDS workspace where
19//! `unsafe` syscalls reach the runtime path. The rest of the
20//! workspace stays `forbid(unsafe_code)` / SAFE. Rationale:
21//!
22//! * Linux RT profiles (SCHED_FIFO, SCHED_RR, SCHED_DEADLINE) and
23//! CPU pinning are reachable **only** via syscalls.
24//! * `nix` as a safe wrapper pulls in 12 transitive crates and
25//! provides no `sched_setattr`/`SCHED_DEADLINE` support.
26//! * `libc` is the transitive standard dep — no additional
27//! footprint, the FFI definitions have been stable for years.
28//!
29//! # Architecture
30//!
31//! Three modules, each with clear invariants:
32//!
33//! * [`scheduler`] — `SchedulerProfile` enum + `apply_to_current_thread`.
34//! * [`affinity`] — `pin_current_thread_to_cpus` with `cpu_set_t`.
35//! * `syscalls` (private module) — all `unsafe { libc::... }` calls live here; each
36//! function is a thin, documented wrapper layer over
37//! a single Linux syscall, with a `// SAFETY:` comment per
38//! block.
39//!
40//! On non-Linux targets all public APIs return
41//! `io::Error::Unsupported` and compile without libc — the workspace
42//! still builds on macOS/Windows.
43//!
44//! # Privileges
45//!
46//! `SCHED_FIFO`/`SCHED_RR` with priority > 0 + `SCHED_DEADLINE` need
47//! `CAP_SYS_NICE` (effective). Default-user tests get `EPERM`
48//! back — the test suite treats this as "skipped" and does not claim
49//! the path was verified.
50//!
51//! # Threat model + invariants
52//!
53//! All FFI calls in this crate hold the following invariants:
54//!
55//! 1. **No pointer outliving:** every pointer passed to a syscall
56//! points to a stack-local structure whose lifetime
57//! overlaps the syscall. No heap, no 'static aliasing.
58//! 2. **No FD leak:** none of the syscalls used create file
59//! descriptors.
60//! 3. **No memory aliasing:** buffers are exclusive (`&mut T`)
61//! during the call.
62//! 4. **Errno-to-Result:** every syscall return value is lifted via
63//! `io::Error::last_os_error()` into a Rust `io::Result`;
64//! `errno` is read exactly once, before any further libc
65//! operation.
66//! 5. **No mut-aliasing race:** all calls refer to the
67//! **own** thread (`tid = 0` is the Linux convention for the
68//! "calling thread"), not to other threads — there
69//! race conditions between user code and syscall would be conceivable.
70//!
71//! # Test strategy
72//!
73//! * All tests use `#[cfg(target_os = "linux")]`.
74//! * Tests that produce `EPERM` (FIFO with prio>0, DEADLINE)
75//! check the errno path instead of forcing the setting.
76//! * `current_scheduler()` is privilege-free and is verified via a
77//! round-trip test after `apply` (where permitted).
78//!
79//! Spec: no OMG spec — Linux kernel API. References:
80//! `sched(7)`, `sched_setattr(2)`, `sched_setaffinity(2)`.
81
82#![cfg_attr(not(feature = "std"), no_std)]
83#![warn(missing_docs)]
84
85#[cfg(feature = "std")]
86extern crate std;
87
88pub mod affinity;
89pub mod scheduler;
90
91#[cfg(target_os = "linux")]
92mod syscalls;
93
94pub use affinity::pin_current_thread_to_cpus;
95pub use scheduler::{RunningSchedulerInfo, SchedulerKind, SchedulerProfile};