Files
RedBear-OS/local/recipes/system/driver-manager/source/src/hotplug.rs
T
vasilito 8822113df8 driver-manager: v2.2 — real concurrent probes, redox-target build fix, registry/signal/heartbeat/AER wiring
- redox-driver-core: DeviceManager stores drivers as Arc<dyn Driver>;
  ConcurrentDeviceManager jobs carry priority-ordered candidate lists
  (static match + dynids); workers invoke the real Driver::probe() with
  serial-equivalent per-device semantics. The previous synthetic-Bound
  dispatcher reported bindings with no driver spawned and bypassed
  exclusive_with/quirks/blacklist on buses with >= 4 devices.
- scheme.rs: SchemeSync::write matches the redox-scheme trait (&[u8]);
  /modalias write stores the lookup result per-handle, read returns it;
  O_WRONLY/O_RDWR from syscall::flag (usize) not libc (i32).
- config.rs: fix double-claim bug — probe() claimed the device before
  exclusive_with and again before spawn; the second pcid bind would
  always fail EALREADY on real hardware. One claim threaded to spawn.
- main.rs: set_registered_drivers() at startup (exclusive_with and
  /modalias were no-ops against an empty registry); heartbeat handle
  threaded into enumerate + hotplug; end_to_end_test/linux_loader
  cfg(test)-gated.
- reaper.rs/sighup.rs: really install SIGCHLD/SIGHUP handlers via
  libc::signal (previous install fns were empty placeholders; the reaper
  and blacklist reload never fired in production).
- unified_events.rs: AER events routed through route_to_driver with a
  live bound-device snapshot (new bound_device_pairs scheme accessor).
- Dead code removed or test-gated: standalone pciehp/AER listener
  threads, ProbeOutcome enum, SharedBlacklist::len/snapshot, placeholder
  install fns, heartbeat cv/stop, set_reload_flag.
- 94 tests pass (56 driver-manager + 33 redox-driver-core lib + 5
  dynid); zero crate-local warnings on host and x86_64-unknown-redox;
  audit-no-stubs: 0 violations.
2026-07-23 09:11:55 +09:00

156 lines
5.3 KiB
Rust

use std::collections::BTreeSet;
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;
use redox_driver_core::device::DeviceId;
use redox_driver_core::driver::ProbeResult;
use redox_driver_core::manager::DeviceManager;
use redox_driver_core::manager::ProbeEvent;
use crate::scheme::{DriverManagerScheme, notify_bind, notify_unbind};
pub fn run_hotplug_loop(
manager: Arc<Mutex<DeviceManager>>,
scheme: Arc<DriverManagerScheme>,
poll_interval_ms: u64,
heartbeat: crate::heartbeat::HeartbeatHandle,
) {
log::info!(
"hotplug: starting event loop ({} ms poll)",
poll_interval_ms
);
loop {
thread::sleep(Duration::from_millis(poll_interval_ms));
let events = match manager.lock() {
Ok(mut mgr) => mgr.enumerate(),
Err(err) => {
log::error!("hotplug: failed to enumerate devices: manager lock poisoned: {err}");
break;
}
};
let mut seen_pci_devices = BTreeSet::new();
let mut pci_enumerated = false;
for event in &events {
match event {
ProbeEvent::BusEnumerated { bus, .. } => {
if bus == "pci" {
pci_enumerated = true;
}
}
ProbeEvent::BusEnumerationFailed { bus, error } => {
log::error!("hotplug: bus {} enumeration failed: {:?}", bus, error);
}
ProbeEvent::AlreadyBound {
device,
driver_name,
} => {
track_pci_device(device, &mut seen_pci_devices);
notify_bound_device(scheme.as_ref(), device, driver_name);
log::debug!("hotplug: already bound {} -> {}", device.path, driver_name);
}
ProbeEvent::ProbeCompleted {
device,
driver_name,
result,
} => {
track_pci_device(device, &mut seen_pci_devices);
match result {
ProbeResult::Bound => {
log::info!("hotplug: bound {} -> {}", device.path, driver_name);
notify_bound_device(scheme.as_ref(), device, driver_name);
heartbeat.record_bound();
}
ProbeResult::Deferred { reason } => {
log::info!(
"hotplug: deferred {} -> {} ({})",
device.path,
driver_name,
reason
);
}
ProbeResult::Fatal { reason } => {
log::error!(
"hotplug: fatal {} -> {} ({})",
device.path,
driver_name,
reason
);
}
ProbeResult::NotSupported => {
log::debug!(
"hotplug: not-supported {} (no match)",
device.path
);
}
}
}
ProbeEvent::NoDriverFound { device } => {
track_pci_device(device, &mut seen_pci_devices);
log::debug!("hotplug: no driver for new device {}", device.path);
}
ProbeEvent::MissingDriver { device, .. } => {
track_pci_device(device, &mut seen_pci_devices);
log::trace!("hotplug: missing-driver (skipped)");
}
}
}
if pci_enumerated {
for pci_addr in scheme.bound_device_addresses() {
if !seen_pci_devices.contains(&pci_addr) {
log::info!("hotplug: removed {}", pci_addr);
notify_unbind(scheme.as_ref(), &pci_addr);
heartbeat.record_unbound();
}
}
}
let retry_events = match manager.lock() {
Ok(mut mgr) => mgr.retry_deferred(),
Err(err) => {
log::error!(
"hotplug: failed to retry deferred probes: manager lock poisoned: {err}"
);
break;
}
};
let mut resolved = 0usize;
for event in &retry_events {
if let ProbeEvent::ProbeCompleted {
device,
driver_name,
result,
} = event
{
if *result == ProbeResult::Bound {
resolved += 1;
notify_bound_device(scheme.as_ref(), device, driver_name);
heartbeat.record_bound();
}
}
}
if resolved > 0 {
log::info!("hotplug: resolved {} deferred probes", resolved);
}
}
}
fn track_pci_device(device: &DeviceId, seen_pci_devices: &mut BTreeSet<String>) {
if device.bus == "pci" {
seen_pci_devices.insert(device.path.clone());
}
}
fn notify_bound_device(scheme: &DriverManagerScheme, device: &DeviceId, driver_name: &str) {
if device.bus == "pci" {
notify_bind(scheme, &device.path, driver_name);
}
}