Fix screensaver idle timeout overflow by using 1s poll intervals with deadline tracking instead of direct millisecond conversion

This commit is contained in:
2026-03-21 03:54:15 -04:00
parent 898002812e
commit ef1d92a108
4 changed files with 18 additions and 5 deletions

View File

@@ -23,6 +23,7 @@ pub mod testutil;
use std::os::fd::BorrowedFd;
use std::process::ExitCode;
use std::sync::atomic::Ordering;
use std::time::Duration;
use nix::errno::Errno;
use nix::poll::{PollFd, PollFlags, PollTimeout, poll};
@@ -255,6 +256,8 @@ fn shed_interactive(args: ShedArgs) -> ShResult<()> {
readline.writer.flush_write("\x1b[?2004h")?; // enable bracketed paste mode
let mut screensaver_deadline: Option<Instant> = None;
// Main poll loop
loop {
write_meta(|m| {
@@ -317,8 +320,15 @@ fn shed_interactive(args: ShedArgs) -> ShResult<()> {
let screensaver_idle_time = read_shopts(|o| o.prompt.screensaver_idle_time);
if screensaver_idle_time > 0 && !screensaver_cmd.is_empty() {
exec_if_timeout = Some(screensaver_cmd);
PollTimeout::from((screensaver_idle_time * 1000) as u16)
if screensaver_deadline.is_none() {
screensaver_deadline = Some(Instant::now() + Duration::from_secs(screensaver_idle_time as u64));
}
// We unfortunately cant just set the PollTimeout to use 'idle_time * 1000' as the timeout
// because u16 overflows after 65 seconds (65535 ms).
// So we set a one second timeout and check against the Instant in 'screensaver_deadline'
PollTimeout::from(1000u16)
} else {
screensaver_deadline = None;
PollTimeout::MAX
}
} else {
@@ -328,7 +338,9 @@ fn shed_interactive(args: ShedArgs) -> ShResult<()> {
match poll(&mut fds, timeout) {
Ok(0) => {
// We timed out.
if let Some(cmd) = exec_if_timeout {
if let Some(cmd) = exec_if_timeout
&& screensaver_deadline.is_some_and(|d| Instant::now() >= d) {
screensaver_deadline = None;
let prepared = ReadlineEvent::Line(cmd.clone());
let saved_hist_opt = read_shopts(|o| o.core.auto_hist);
let _guard = scopeguard::guard(saved_hist_opt, |opt| {
@@ -420,6 +432,7 @@ fn shed_interactive(args: ShedArgs) -> ShResult<()> {
}
Ok(n) => {
readline.feed_bytes(&buffer[..n]);
screensaver_deadline = None;
}
Err(Errno::EINTR) => {
// Interrupted, continue to handle signals