agent: code-atomiser-fix — hotkey supervisor rearchitecture (Race-1, Race-2, TOCTOU)

Fixes three interlocking concurrency leaks in the evdev hotkey listener
flagged by the atomiser full-sweep. Every spawned task is now owned by a
SupervisorHandle that broadcasts cooperative shutdown and joins every
JoinHandle with a 2s per-task timeout on stop(). Per-device attachment is
now insert-before-spawn under one mutex hold, closing the TOCTOU window.
The Tauri command layer now stores the forwarder JoinHandle alongside
the listener so reconfigures join it cleanly instead of leaking one
permanent forwarder per hotkey change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-13 15:21:50 +01:00
parent 9f67ab2d86
commit 1068ad9c7d
7 changed files with 781 additions and 132 deletions

View File

@@ -2,6 +2,10 @@
//!
//! On macOS and Windows, Tauri's global-shortcut plugin handles hotkeys
//! natively. This stub exists so the crate compiles on all platforms.
//!
//! The signature here mirrors the Linux backend so the consumer (the
//! Tauri command layer) can use the same call shape on every platform:
//! `EvdevHotkeyListener::start(...).await` and `listener.stop().await`.
use tokio::sync::mpsc;
@@ -18,12 +22,16 @@ pub enum HotkeyEvent {
pub struct EvdevHotkeyListener;
impl EvdevHotkeyListener {
pub fn start(_combo: HotkeyCombo, _event_tx: mpsc::Sender<HotkeyEvent>) -> Self {
/// Mirrors the Linux backend's async constructor so consumers can
/// `await` the same call shape regardless of platform.
pub async fn start(_combo: HotkeyCombo, _event_tx: mpsc::Sender<HotkeyEvent>) -> Self {
tracing::info!("evdev hotkey listener is a no-op on this platform");
Self
}
pub fn set_hotkey(&self, _combo: HotkeyCombo) {}
pub async fn stop(&self) {}
/// Consuming stop mirrors the Linux backend so callers can rely on
/// the listener being unusable after shutdown on every platform.
pub async fn stop(self) {}
}