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

2
Cargo.lock generated
View File

@@ -573,7 +573,7 @@ dependencies = [
[[package]] [[package]]
name = "shed" name = "shed"
version = "0.6.1" version = "0.6.2"
dependencies = [ dependencies = [
"ariadne", "ariadne",
"bitflags", "bitflags",

View File

@@ -2,7 +2,7 @@
name = "shed" name = "shed"
description = "A linux shell written in rust" description = "A linux shell written in rust"
publish = false publish = false
version = "0.6.1" version = "0.6.2"
edition = "2024" edition = "2024"

View File

@@ -14,7 +14,7 @@
{ {
packages.default = pkgs.rustPlatform.buildRustPackage { packages.default = pkgs.rustPlatform.buildRustPackage {
pname = "shed"; pname = "shed";
version = "0.6.1"; version = "0.6.2";
src = self; src = self;

View File

@@ -23,6 +23,7 @@ pub mod testutil;
use std::os::fd::BorrowedFd; use std::os::fd::BorrowedFd;
use std::process::ExitCode; use std::process::ExitCode;
use std::sync::atomic::Ordering; use std::sync::atomic::Ordering;
use std::time::Duration;
use nix::errno::Errno; use nix::errno::Errno;
use nix::poll::{PollFd, PollFlags, PollTimeout, poll}; 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 readline.writer.flush_write("\x1b[?2004h")?; // enable bracketed paste mode
let mut screensaver_deadline: Option<Instant> = None;
// Main poll loop // Main poll loop
loop { loop {
write_meta(|m| { 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); let screensaver_idle_time = read_shopts(|o| o.prompt.screensaver_idle_time);
if screensaver_idle_time > 0 && !screensaver_cmd.is_empty() { if screensaver_idle_time > 0 && !screensaver_cmd.is_empty() {
exec_if_timeout = Some(screensaver_cmd); 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 { } else {
screensaver_deadline = None;
PollTimeout::MAX PollTimeout::MAX
} }
} else { } else {
@@ -328,7 +338,9 @@ fn shed_interactive(args: ShedArgs) -> ShResult<()> {
match poll(&mut fds, timeout) { match poll(&mut fds, timeout) {
Ok(0) => { Ok(0) => {
// We timed out. // 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 prepared = ReadlineEvent::Line(cmd.clone());
let saved_hist_opt = read_shopts(|o| o.core.auto_hist); let saved_hist_opt = read_shopts(|o| o.core.auto_hist);
let _guard = scopeguard::guard(saved_hist_opt, |opt| { let _guard = scopeguard::guard(saved_hist_opt, |opt| {
@@ -420,6 +432,7 @@ fn shed_interactive(args: ShedArgs) -> ShResult<()> {
} }
Ok(n) => { Ok(n) => {
readline.feed_bytes(&buffer[..n]); readline.feed_bytes(&buffer[..n]);
screensaver_deadline = None;
} }
Err(Errno::EINTR) => { Err(Errno::EINTR) => {
// Interrupted, continue to handle signals // Interrupted, continue to handle signals