From d67c8cce29db7935d2588609606faad6d8b8a710 Mon Sep 17 00:00:00 2001 From: luytan Date: Tue, 22 Sep 2026 21:19:04 +0200 Subject: [PATCH 1/2] feat(cardwired): refresh on thunderbolt event --- .../cardwire-daemon/src/tasks/monitor_udev.rs | 58 +++++++++++++------ 1 file changed, 41 insertions(+), 17 deletions(-) diff --git a/crates/cardwire-daemon/src/tasks/monitor_udev.rs b/crates/cardwire-daemon/src/tasks/monitor_udev.rs index 10ebbf21..4de0dbae 100644 --- a/crates/cardwire-daemon/src/tasks/monitor_udev.rs +++ b/crates/cardwire-daemon/src/tasks/monitor_udev.rs @@ -1,30 +1,54 @@ //! Used to listen to other dbus interface, mainly for auto battery switch and display detection -use log::{error, info}; -use tokio::io::{Interest, unix::AsyncFd}; - use crate::interface::DebugInterface; +use log::{error, info}; +use tokio::io::unix::AsyncFd; +/// listen to pci/thunderbolt event and refres the GPU list when necessary pub async fn monitor_pci_changes(debug_int: DebugInterface) -> zbus::Result<()> { - let udev_monitor = udev::MonitorBuilder::new()?.match_subsystem("pci")?; - let udev_fd = AsyncFd::new(udev_monitor.listen()?)?; + let udev_pci_monitor = udev::MonitorBuilder::new()?.match_subsystem("pci")?; + let udev_pci_fd = AsyncFd::new(udev_pci_monitor.listen()?)?; + let udev_thunderbolt_monitor = udev::MonitorBuilder::new()?.match_subsystem("thunderbolt")?; + let udev_thunderbolt_fd = AsyncFd::new(udev_thunderbolt_monitor.listen()?)?; loop { - let mut guard = udev_fd.ready(Interest::READABLE).await?; - if guard.ready().is_readable() { - for event in udev_fd.get_ref().iter() { - if let Some(action) = event.action() - && (action == "bind" || action == "unbind") - { - info!("detected pci event, refreshing GPU interfaces"); - match debug_int.refresh_gpu().await { - Ok(()) => {} - Err(e) => { - error!("failed to refresh gpu interface: {}", e); + tokio::select! { + guard_res = udev_pci_fd.readable() => { + if let Ok(mut guard) = guard_res && guard.ready().is_readable() { + for event in udev_pci_fd.get_ref().iter() { + if let Some(action) = event.action() + && (action == "bind" || action == "unbind") + { + info!("detected pci event, refreshing GPU interfaces"); + match debug_int.refresh_gpu().await { + Ok(()) => {} + Err(e) => { + error!("failed to refresh gpu interface: {}", e); + } + } + } + } + guard.clear_ready(); + } + } + guard_res = udev_thunderbolt_fd.readable() => { + if let Ok(mut guard) = guard_res && guard.ready().is_readable() { + for event in udev_thunderbolt_fd.get_ref().iter() { + if let Some(action) = event.action() + && (action == "add" || action == "remove" || action == "change") + // try to match most actions, refreshing isnt that ressource intensive + { + info!("detected pci event, refreshing GPU interfaces"); + match debug_int.refresh_gpu().await { + Ok(()) => {} + Err(e) => { + error!("failed to refresh gpu interface: {}", e); + } + } } } + guard.clear_ready(); } } } - guard.clear_ready(); } } From 52da1d49153cff6d8c8496bdddc56e3f83ae066b Mon Sep 17 00:00:00 2001 From: luytan Date: Tue, 22 Sep 2026 21:28:09 +0200 Subject: [PATCH 2/2] refactor(cardwired): handle udev monitor errors --- .../cardwire-daemon/src/tasks/monitor_udev.rs | 58 +++++++++++-------- 1 file changed, 35 insertions(+), 23 deletions(-) diff --git a/crates/cardwire-daemon/src/tasks/monitor_udev.rs b/crates/cardwire-daemon/src/tasks/monitor_udev.rs index 4de0dbae..1cffce5a 100644 --- a/crates/cardwire-daemon/src/tasks/monitor_udev.rs +++ b/crates/cardwire-daemon/src/tasks/monitor_udev.rs @@ -13,40 +13,52 @@ pub async fn monitor_pci_changes(debug_int: DebugInterface) -> zbus::Result<()> loop { tokio::select! { guard_res = udev_pci_fd.readable() => { - if let Ok(mut guard) = guard_res && guard.ready().is_readable() { - for event in udev_pci_fd.get_ref().iter() { - if let Some(action) = event.action() - && (action == "bind" || action == "unbind") - { - info!("detected pci event, refreshing GPU interfaces"); - match debug_int.refresh_gpu().await { - Ok(()) => {} - Err(e) => { - error!("failed to refresh gpu interface: {}", e); + match guard_res { + Ok(mut guard) => { + for event in udev_pci_fd.get_ref().iter() { + if let Some(action) = event.action() + && (action == "bind" || action == "unbind") + { + info!("detected pci event, refreshing GPU interfaces"); + match debug_int.refresh_gpu().await { + Ok(()) => {} + Err(e) => { + error!("failed to refresh gpu interface: {}", e); + } } } } + guard.clear_ready(); + } + Err(err) => { + error!("[UDEV_MONITOR_PCI]: {:?}", err); + return Err(err.into()) } - guard.clear_ready(); } } guard_res = udev_thunderbolt_fd.readable() => { - if let Ok(mut guard) = guard_res && guard.ready().is_readable() { - for event in udev_thunderbolt_fd.get_ref().iter() { - if let Some(action) = event.action() - && (action == "add" || action == "remove" || action == "change") - // try to match most actions, refreshing isnt that ressource intensive - { - info!("detected pci event, refreshing GPU interfaces"); - match debug_int.refresh_gpu().await { - Ok(()) => {} - Err(e) => { - error!("failed to refresh gpu interface: {}", e); + match guard_res { + Ok(mut guard) => { + for event in udev_thunderbolt_fd.get_ref().iter() { + if let Some(action) = event.action() + && (action == "add" || action == "remove" || action == "change") + // try to match most actions, refreshing isnt that ressource intensive + { + info!("detected pci event, refreshing GPU interfaces"); + match debug_int.refresh_gpu().await { + Ok(()) => {} + Err(e) => { + error!("failed to refresh gpu interface: {}", e); + } } } } + guard.clear_ready(); + } + Err(err) => { + error!("[UDEV_MONITOR_THUNDERBOLT]: {:?}", err); + return Err(err.into()) } - guard.clear_ready(); } } }