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:
+1
-1
@@ -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
@@ -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 (C0–C4) 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 (C0–C4) 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,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)
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user