Skip to content

fix(unix): retry EINTR in poll/select/read#286

Open
jh-block wants to merge 2 commits intoconsole-rs:mainfrom
jh-block:fix-eintr-misread-as-ctrl-c
Open

fix(unix): retry EINTR in poll/select/read#286
jh-block wants to merge 2 commits intoconsole-rs:mainfrom
jh-block:fix-eintr-misread-as-ctrl-c

Conversation

@jh-block
Copy link
Copy Markdown

@jh-block jh-block commented May 5, 2026

Fixes #212.

read_single_key treats any Err(Interrupted) from read_single_key_impl as Ctrl-C and forwards it via libc::raise(SIGINT). That's correct only for the synthesized Err(Interrupted) read_bytes returns when it sees a \x03 byte. EINTR returned by poll/select/read because of an unrelated signal (SIGCHLD, SIGWINCH, etc.) takes the same path and incorrectly kills the program with SIGINT.

Retry EINTR inside the syscall wrappers so Err(Interrupted) reaching read_single_key unambiguously means a \x03 byte was read.

@jh-block jh-block force-pushed the fix-eintr-misread-as-ctrl-c branch from e629345 to 0f4804e Compare May 5, 2026 13:32
@jh-block jh-block changed the title fix(unix): retry EINTR in poll/select/read so unrelated signals don't surface as spurious key events fix(unix): retry EINTR in poll/select/read May 5, 2026
@jh-block jh-block force-pushed the fix-eintr-misread-as-ctrl-c branch from 0f4804e to 02dec12 Compare May 5, 2026 13:34
@djc
Copy link
Copy Markdown
Member

djc commented May 5, 2026

Thanks for the clippy fix -- can you split it out in a separate commit please?

For the first hunk's loop, I think we could do break instead of return at the end? Seems slightly nicer.

@jh-block jh-block force-pushed the fix-eintr-misread-as-ctrl-c branch 2 times, most recently from d4bbaab to efd7139 Compare May 5, 2026 13:49
jh-block added 2 commits May 5, 2026 15:50
Fixes console-rs#212.

read_single_key treats any Err(Interrupted) from read_single_key_impl
as Ctrl-C and forwards it via libc::raise(SIGINT). That's correct only
for the synthesized Err(Interrupted) read_bytes returns when it sees a
\x03 byte. EINTR returned by poll/select/read because of an unrelated
signal (SIGCHLD, SIGWINCH, etc.) takes the same path and incorrectly
kills the program with SIGINT.

Retry EINTR inside the syscall wrappers so Err(Interrupted) reaching
read_single_key unambiguously means a \x03 byte was read.
Silences clippy::collapsible_match warning on clippy 1.95+.
@jh-block jh-block force-pushed the fix-eintr-misread-as-ctrl-c branch from efd7139 to e08b569 Compare May 5, 2026 13:50
@djc
Copy link
Copy Markdown
Member

djc commented May 5, 2026

This does not seem like a clean split. Also, the first commit looks like it makes some unrelated/unnecessary changes. If you are using an LLM to help with this, please self-review before asking for my review.

@jh-block
Copy link
Copy Markdown
Author

jh-block commented May 5, 2026

Can you clarify what you mean? The only perhaps-unrelated change in the first commit is reducing the scope of the unsafe block in select_fd to the actual unsafe code, rather than covering the whole method with it, which seemed appropriate since otherwise the entire loop (which is just normal safe logic) would be within the unsafe block. Do you want me to revert that, or split it into a separate commit, or are you referring to something else?

@jh-block
Copy link
Copy Markdown
Author

jh-block commented May 7, 2026

@djc is there any chance you could take another look at the two commits? I am not sure how to interpret your earlier comment; the split of the clippy fix and the logic fix into two commits is clean, and the first commit (the EINTR logic fix) contains only the changes I intended to make. If you would like something changed can you indicate what it is?

@djc
Copy link
Copy Markdown
Member

djc commented May 9, 2026

This hunk from the first commit seems like an unnecessary increase in scope of the unsafe block?

Screenshot 2026-05-09 at 14 10 27

Comment thread src/unix_term.rs
Comment on lines +164 to +167
if err.kind() == io::ErrorKind::Interrupted {
continue;
}
break Err(err);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: suggest writing this as

match err.kind() {
    io::ErrorKind::Interrupted => continue,
    _ => break Err(err),
}

Comment thread src/unix_term.rs
Comment on lines +201 to +204
if err.kind() == io::ErrorKind::Interrupted {
continue;
}
break Err(err);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SIGWINCH generates SIGINT

2 participants