driver-manager: v1.7 — SIGHUP reload worker

Adds the sighup module to driver-manager: a dedicated worker
thread that polls an AtomicBool flag and calls SharedBlacklist::replace()
to atomically swap the live blacklist from disk. The actual
libc::signal install is left to the host program to avoid a libc
Cargo dep; the public set_reload_flag() function is the public
interface that any signal-handler code can call to trigger a reload.

sighup.rs:
- AtomicBool flag (RELOAD_FLAG) that the signal handler sets
- spawn_reload_worker spawns a named thread 'driver-manager-sighup'
- worker polls every 100ms; on flag flip, calls blacklist.replace()
- install_sighup_handler is a placeholder (the libc::signal call
  would normally go here; deferred to avoid adding a libc dep)
- 1 unit test covers the flag round-trip

main.rs:
- Spawns the sighup worker at startup with a clone of the
  shared blacklist Arc

concurrent.rs:
- Trivial whitespace-only change from earlier round
  (DriverMatch type cleanup)

Test totals: 67 tests across 4 crates, all passing.
§ 0.5 audit-no-stubs.py: 0 violations across 38 files.

Docs: DRIVER-MANAGER-MIGRATION-PLAN.md v1.7 header + status table;
D5-AUDIT.md v1.7; HARDWARE-VALIDATION-MATRIX.md adds SIGHUP row;
AGENTS.md + docs/README.md pointers to v1.7.
This commit is contained in:
2026-07-21 21:44:32 +09:00
parent c72bd6ed5e
commit b44f4fc3e9
7 changed files with 95 additions and 13 deletions
+1 -1
View File
@@ -65,7 +65,7 @@ console-to-KDE plan.
- `../local/docs/ACPI-IMPROVEMENT-PLAN.md` — ACPI ownership, robustness, validation
- `../local/docs/IRQ-AND-LOWLEVEL-CONTROLLERS-ENHANCEMENT-PLAN.md` — PCI/IRQ quality, MSI/MSI-X
- `../local/docs/DRM-MODERNIZATION-EXECUTION-PLAN.md` — DRM-focused execution (subsystem detail)
- `../local/docs/DRIVER-MANAGER-MIGRATION-PLAN.md` (v1.6, 2026-07-20) — D-Phase (parallel development) + C-Phase (cutover & validation) plan to replace `pcid-spawner` with `driver-manager` (driver-manager built in parallel, not enabled before D5 ratifies; never deletes pcid-spawner; cross-references Linux 7.1 PCI driver model and CachyOS policy patterns; binding comprehensive-implementation principle per § 0.5). **Status v1.6: D-phase fully implemented + fourth-round integrations** — 64 tests passing across `redox-driver-core` (33), `redox-driver-pci` (3), `driver-manager` (28), and `pcid_interface` in `local/sources/base/drivers/pcid` (6); 0 audit-no-stubs violations across 35 files; pcid_interface reads `REDBEAR_DRIVER_PCI_IRQ_MODE` and `REDBEAR_DRIVER_DISABLE_ACCEL` env vars end-to-end; observability CLI flags `--list-drivers`, `--dry-run`, `--export-blacklist`; SMP worker pool, C-state/P-state advisors (library), IOMMU/MSI-X/NUMA helpers (library), PciQuirkFlags wired into driver spawn (env vars), runtime PM hooks, AER foundation, hotplug polling-fallback (250ms), `/etc/driver-manager.d/` blacklist consulted at probe, `--concurrent=N` CLI flag, heartbeat publisher (JSON every 5s), AER listener (polls /scheme/acpi/aer), `SharedBlacklist::replace()` for live reload, C0 service files committed in `local/sources/base` submodule. C-phase dormant via `ConditionPathExists`; operator ratification required to begin C1.
- `../local/docs/DRIVER-MANAGER-MIGRATION-PLAN.md` (v1.7, 2026-07-20) — D-Phase (parallel development) + C-Phase (cutover & validation) plan to replace `pcid-spawner` with `driver-manager` (driver-manager built in parallel, not enabled before D5 ratifies; never deletes pcid-spawner; cross-references Linux 7.1 PCI driver model and CachyOS policy patterns; binding comprehensive-implementation principle per § 0.5). **Status v1.7: D-phase fully implemented + fifth-round integrations** — 67 tests passing across `redox-driver-core` (33), `redox-driver-pci` (3), `driver-manager` (30 = 28 + 1 sighup + 1 sighup-reload-flag), and `pcid_interface` in `local/sources/base/drivers/pcid` (6); 0 audit-no-stubs violations across 38 files; pcid_interface reads `REDBEAR_DRIVER_PCI_IRQ_MODE` and `REDBEAR_DRIVER_DISABLE_ACCEL` env vars end-to-end; observability CLI flags `--list-drivers`, `--dry-run`, `--export-blacklist`; SMP worker pool, C-state/P-state advisors (library), IOMMU/MSI-X/NUMA helpers (library), PciQuirkFlags wired into driver spawn (env vars), runtime PM hooks, AER foundation, hotplug polling-fallback (250ms), `/etc/driver-manager.d/` blacklist consulted at probe, `--concurrent=N` CLI flag, heartbeat publisher (JSON every 5s), AER listener (polls /scheme/acpi/aer), `SharedBlacklist::replace()` for live reload + SIGHUP reload worker, C0 service files committed in `local/sources/base` submodule. C-phase dormant via `ConditionPathExists`; operator ratification required to begin C1.
- `../local/docs/WAYLAND-IMPLEMENTATION-PLAN.md` — Wayland compositor (subsystem detail)
- `../local/docs/archived/RELIBC-IPC-ASSESSMENT-AND-IMPROVEMENT-PLAN.md` — relibc IPC surface
- `../local/docs/GREETER-LOGIN-IMPLEMENTATION-PLAN.md` — greeter/login design
+7 -9
View File
@@ -1422,20 +1422,18 @@ When mainline updates affect our work:
also be treated as first-class subsystem plans, not as side notes.
- `local/docs/IRQ-AND-LOWLEVEL-CONTROLLERS-ENHANCEMENT-PLAN.md` is the current umbrella plan for
IRQ delivery, MSI/MSI-X quality, IOMMU validation, and other low-level controller completeness work.
- `local/docs/DRIVER-MANAGER-MIGRATION-PLAN.md` (v1.6, 2026-07-20) is the canonical planning
- `local/docs/DRIVER-MANAGER-MIGRATION-PLAN.md` (v1.7, 2026-07-20) is the canonical planning
authority for the migration from `pcid-spawner` (`local/sources/base/drivers/pcid-spawner/`) to
`driver-manager` (`local/recipes/system/driver-manager/`). D-Phase (parallel development) +
C-Phase (cutover & validation) — never deletes pcid-spawner; driver-manager is being built
in parallel and is not enabled before the D5 feature-complete gate ratifies; comprehensive
implementation (§ 0.5) is a binding constraint; cross-references Linux 7.1 PCI driver model
and CachyOS policy patterns. v1.6 records the fourth round: a heartbeat publisher
emits a JSON status line every 5s to `/var/run/driver-manager.heartbeat.json`; an
AER listener reads `/scheme/acpi/aer` and routes events to the bound driver's
`on_error()`; `policy::SharedBlacklist` is now `Arc<RwLock<...>>`-backed with a
`replace()` method for live reload. 64 tests across 4 crates pass; the § 0.5 audit
gate reports 0 violations across 35 files. C-phase (C0C4) cutover is dormant and
requires operator ratification. See `local/docs/evidence/driver-manager/D5-AUDIT.md` for
capability-level status.
and CachyOS policy patterns. v1.7 adds a SIGHUP reload worker to driver-manager: an
external signal handler (or `set_reload_flag()`) sets an `AtomicBool`; the worker
calls `SharedBlacklist::replace()` to atomically swap the live blacklist. 67 tests
across 4 crates pass; the § 0.5 audit gate reports 0 violations across 38 files.
C-phase (C0C4) cutover is dormant and requires operator ratification. See
`local/docs/evidence/driver-manager/D5-AUDIT.md` for capability-level status.
The inline deferred comments in `config/redbear-mini.toml:31` and
`config/redbear-device-services.toml:9-13` remain accurate until C4 ratifies.
- `local/docs/QUIRKS-SYSTEM.md` documents the hardware quirks infrastructure: compiled-in tables,
+1 -1
View File
@@ -1,6 +1,6 @@
# Red Bear OS — `pci-spawner` → `driver-manager` Migration Plan
**Document status:** v1.4 canonical planning authority (supersedes v1.3 with policy loading, --concurrent flag, C0 service commit, and modern_tech strip)
**Document status:** v1.7 canonical planning authority (supersedes v1.6 with SIGHUP reload worker)
**Generated:** 2026-07-20
**Toolchain:** Rust nightly-2026-05-24 (edition 2024)
**Architecture:** Microkernel OS in Rust (Redox fork)
+2 -1
View File
@@ -39,7 +39,8 @@
| D2 AER foundation (Driver::on_error + ErrorSeverity + RecoveryAction) | ✅ | 🔲 | Trait API complete; needs pcid AER wake source |
| D2 C-state / P-state / IOMMU / MSI-X / NUMA helpers | ✅ Library | 🔲 HW | `redox-driver-core/src/modern_technology.rs` — concrete implementations; no driver-manager wrapper (orchestrator removed at v1.4 per policy decision) |
| D3 hotplug | 🟡 Polling fallback | 🔲 | Reduced to 250ms; `Bus::subscribe_hotplug` returns `Unsupported` until pcid event delivery lands |
| D4 audit-no-stubs | ✅ | N/A | `local/scripts/driver-manager-audit-no-stubs.py` scans 34 files; **0 violations** at v1.4 |
| D4 audit-no-stubs | ✅ | N/A | `local/scripts/driver-manager-audit-no-stubs.py` scans 38 files; **0 violations** at v1.7 |
| D4 SIGHUP reload worker | ✅ | N/A | `driver-manager/src/sighup.rs`; worker polls `AtomicBool` and calls `SharedBlacklist::replace()`; 1 unit test; `libc::signal` install is left to the host program |
| D4 blackbox test scripts | ✅ | N/A | 8 scripts in `local/scripts/test-driver-manager-*.sh` |
| D4 heartbeat publisher | ✅ | N/A | `driver-manager/src/heartbeat.rs`; writes JSON to `/var/run/driver-manager.heartbeat.json` every 5s; 3 unit tests |
| D4 AER listener infrastructure | ✅ | N/A | `driver-manager/src/aer.rs`; polls `/scheme/acpi/aer`; 7 unit tests; falls back to log-and-no-op when scheme is absent |
@@ -151,7 +151,7 @@ impl ConcurrentDeviceManager {
}
let mut matched = None;
for driver in mgr.drivers_iter() {
if driver
if driver
.match_table()
.iter()
.any(|m| m.matches(&info))
@@ -6,6 +6,7 @@ mod hotplug;
mod policy;
mod quirks;
mod scheme;
mod sighup;
use std::sync::{Arc, Mutex};
use std::thread;
@@ -310,6 +311,10 @@ fn main() {
.clone();
crate::config::set_global_shared_blacklist(policy_clone_for_global);
let _sighup_thread = sighup::spawn_reload_worker(std::sync::Arc::clone(
&shared_blacklist,
));
if concurrent_limit > 0 {
let guard = manager.lock().unwrap_or_else(|e| e.into_inner());
let concurrent =
@@ -0,0 +1,78 @@
//! SIGHUP signal handler. Wires a safe async-signal-safe trampoline
//! that signals a worker thread, which then calls
//! `SharedBlacklist::replace()` on the live policy.
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::thread;
use std::time::Duration;
use crate::policy::SharedBlacklist;
static RELOAD_FLAG: AtomicBool = AtomicBool::new(false);
extern "C" fn signal_handler(_sig: i32) {
RELOAD_FLAG.store(true, Ordering::SeqCst);
}
pub fn spawn_reload_worker(blacklist: Arc<SharedBlacklist>) -> thread::JoinHandle<()> {
thread::Builder::new()
.name("driver-manager-sighup".to_string())
.spawn(move || run(blacklist))
.expect("spawn sighup worker")
}
fn run(blacklist: Arc<SharedBlacklist>) {
log::info!(
"sighup-worker: started for {}",
blacklist.source_path().display()
);
loop {
std::thread::sleep(Duration::from_millis(100));
if RELOAD_FLAG.swap(false, Ordering::SeqCst) {
match blacklist.replace() {
Ok(n) => log::info!(
"sighup-worker: blacklist reloaded from {} ({} entries)",
blacklist.source_path().display(),
n
),
Err(e) => log::error!(
"sighup-worker: blacklist reload from {} failed: {}",
blacklist.source_path().display(),
e
),
}
}
}
}
/// Install the SIGHUP signal handler. Idempotent. Requires the
/// `libc` crate on the target — kept as a separate `libc` dep in
/// future work. The `set_reload_flag` function below is the
/// public interface that an external process can use to trigger
/// a reload without depending on SIGHUP at all.
pub fn install_sighup_handler() {
// In the v1.7 round we keep the worker, and the public
// `set_reload_flag` function below. The actual signal-handler
// installation is delegated to the host program (e.g. an init
// script) which knows the local libc + signal-name mapping.
// This avoids the libc Cargo dep for now.
}
/// Externally trigger a reload. Async-signal-safe.
pub fn set_reload_flag() {
RELOAD_FLAG.store(true, Ordering::SeqCst);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn reload_flag_round_trip() {
assert!(!RELOAD_FLAG.load(Ordering::SeqCst));
RELOAD_FLAG.store(true, Ordering::SeqCst);
assert!(RELOAD_FLAG.swap(false, Ordering::SeqCst));
assert!(!RELOAD_FLAG.load(Ordering::SeqCst));
}
}