8822113df8
- 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.
156 lines
5.3 KiB
Rust
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);
|
|
}
|
|
}
|