Reduce polling retries and repeated compositor lookups

This commit is contained in:
Samuel Onoja committed 2026-09-27 06:58:09 +01:00
1 parent dcca5fec88
commit 917379d548
4 files changed
+146 -24

No files matched your search

+57 -6
View File
@@ -90,6 +90,16 @@ pub struct Service {
pub generation: u64,
}
type PollState = (Mutex<(u64, bool, Option<String>, bool)>, Condvar);
fn wait_for_poll(shared: &PollState) -> Option<u64> {
let state = shared
.1
.wait_while(shared.0.lock().unwrap(), |state| state.1 && !state.3)
.unwrap();
(!state.3).then_some(state.0)
}
impl Service {
pub fn start(settings: Option<Vec<String>>) -> Self {
let live_settings = Arc::new(Mutex::new(settings));
@@ -105,12 +115,11 @@ impl Service {
let polling = shared.clone();
thread::spawn(move || {
loop {
let before = {
let state = polling.0.lock().unwrap();
if state.3 {
break;
}
state.0
// A poll overlapping a write is discarded below. Wait for the
// write to finish before retrying instead of launching commands
// repeatedly while a slow control operation is still running.
let Some(before) = wait_for_poll(&polling) else {
break;
};
let snapshot = poll();
let state = polling.0.lock().unwrap();
@@ -476,6 +485,48 @@ fn execute(action: &Action, settings: Option<&[String]>) -> Result<(), String> {
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn polling_waits_for_a_write_and_uses_the_completed_generation() {
let shared = Arc::new((Mutex::new((7, true, None, false)), Condvar::new()));
let worker_state = shared.clone();
let (sender, receiver) = mpsc::channel();
let worker = thread::spawn(move || {
sender.send(wait_for_poll(&worker_state)).unwrap();
});
assert!(matches!(
receiver.recv_timeout(Duration::from_millis(30)),
Err(mpsc::RecvTimeoutError::Timeout)
));
{
let mut state = shared.0.lock().unwrap();
state.0 = 8;
state.1 = false;
shared.1.notify_one();
}
assert_eq!(
receiver.recv_timeout(Duration::from_secs(2)).unwrap(),
Some(8)
);
worker.join().unwrap();
}
#[test]
fn shutdown_unblocks_polling_even_during_a_write() {
let shared = Arc::new((Mutex::new((7, true, None, false)), Condvar::new()));
let worker_state = shared.clone();
let (sender, receiver) = mpsc::channel();
let worker = thread::spawn(move || {
sender.send(wait_for_poll(&worker_state)).unwrap();
});
{
let mut state = shared.0.lock().unwrap();
state.3 = true;
shared.1.notify_one();
}
assert_eq!(receiver.recv_timeout(Duration::from_secs(2)).unwrap(), None);
worker.join().unwrap();
}
#[test]
fn audio_parser_handles_mute_and_rejects_invalid_values() {
assert_eq!(parse_audio("Volume: 0.42 [MUTED]"), Some((42, true)));