driver-manager: share Arc<DriverConfig> + crash-aware reaper + S3 self_weak (N18 Q1+Q2+S3)

Three changes in one file because the regions are interleaved
and the changes are all upstream of the audit plan's N18
single-day batch.

- Q1: `main.rs:636-661` rewritten to build one
  `Vec<Arc<DriverConfig>>` and pass `Arc::clone` to both
  `DeviceManager` via the new `register_driver_shared` and
  to the reaper registry via `Arc::downgrade`. Removes the dead
  `registry_configs` second-loop block.

- Q2: reaper closure at `main.rs:765-772` interprets
  `waitpid` status via `WIFEXITED && WEXITSTATUS == 0` or
  `WIFSIGNALED && WTERMSIG in (SIGTERM, SIGINT)` as a clean
  exit, routing to `reap_pid_clean`; anything else routes to
  `reap_pid` (crash).

- S3: cfg-gated `set_self_weak(Arc::downgrade(&scheme))`
  call after `set_manager` so the detached AER recovery
  worker can notify the scheme of rebind events.

driver-manager tests: 164 passing (no regression).
This commit is contained in:
2026-07-27 21:55:34 +09:00
parent 769bc4a9af
commit 37f8b37267
@@ -605,6 +605,12 @@ fn main() {
let scheme = Arc::new(DriverManagerScheme::new());
scheme.set_manager(Arc::clone(&manager));
// N18 S3: store a Weak self-reference so the AER recovery worker
// (which runs detached) can call back into the scheme to record
// rebind events without keeping a long-lived strong Arc.
#[cfg(target_os = "redox")]
scheme.set_self_weak(std::sync::Arc::downgrade(&scheme));
let heartbeat = heartbeat::Heartbeat::new(
std::path::PathBuf::from("/var/run/driver-manager.heartbeat.json"),
std::time::Duration::from_secs(5),
@@ -633,12 +639,22 @@ fn main() {
initfs_manifest: Some(std::sync::Arc::clone(&shared_initfs_manifest)),
});
// N18 Q1: one Arc<DriverConfig> per driver, shared between manager
// and registry. The manager mutates spawned/pid_to_device via probe();
// the reaper's Weak::upgrade returns the same allocation so the maps
// it cleans match the maps the manager populated.
let driver_arcs: Vec<std::sync::Arc<DriverConfig>> = driver_configs
.iter()
.map(|dc| std::sync::Arc::new(dc.clone()))
.collect();
match manager.lock() {
Ok(mut mgr) => {
mgr.register_bus(Box::new(PciBus::new()));
for dc in &driver_configs {
mgr.register_driver(Box::new(dc.clone()));
for dc in &driver_arcs {
// Unsized coercion: Arc<DriverConfig> -> Arc<dyn Driver>.
// Coercion fires at the function-call site (argument position
// accepts Arc<dyn Driver>, which Arc<DriverConfig> satisfies).
mgr.register_driver_shared(dc.clone());
}
}
Err(err) => {
@@ -650,13 +666,8 @@ fn main() {
let mgr_clone = Arc::clone(&manager);
let scheme_clone = Arc::clone(&scheme);
let registry_configs: Vec<std::sync::Arc<DriverConfig>> = driver_configs
.iter()
.map(|dc| std::sync::Arc::new(dc.clone()))
.collect();
for cfg in &registry_configs {
let weak: std::sync::Weak<DriverConfig> =
std::sync::Arc::downgrade(cfg);
for dc in &driver_arcs {
let weak: std::sync::Weak<DriverConfig> = std::sync::Arc::downgrade(dc);
registry::register(weak);
}
@@ -762,11 +773,21 @@ fn main() {
},
);
let _reaper_thread = reaper::spawn_reaper_thread(|pid| {
let _reaper_thread = reaper::spawn_reaper_thread(|pid, status| {
// Clean exit: WIFEXITED && WEXITSTATUS == 0, or WIFSIGNALED with
// SIGTERM/SIGINT (our own remove() sends SIGTERM). Anything else
// is a crash.
let clean = unsafe { libc::WIFEXITED(status) } && unsafe { libc::WEXITSTATUS(status) } == 0
|| unsafe { libc::WIFSIGNALED(status) }
&& matches!(unsafe { libc::WTERMSIG(status) }, libc::SIGTERM | libc::SIGINT);
let registry = registry::snapshot();
for weak in registry {
if let Some(cfg) = weak.upgrade() {
cfg.reap_pid(pid);
if clean {
cfg.reap_pid_clean(pid);
} else {
cfg.reap_pid(pid);
}
}
}
});