Skip to content

Add EINTR handling for std.stdio and std.process#11007

Merged
thewilsonator merged 4 commits intodlang:masterfrom
CyberShadow:eintr-retry-helper
May 6, 2026
Merged

Add EINTR handling for std.stdio and std.process#11007
thewilsonator merged 4 commits intodlang:masterfrom
CyberShadow:eintr-retry-helper

Conversation

@CyberShadow
Copy link
Copy Markdown
Member

@CyberShadow CyberShadow commented May 5, 2026

Fixes #11006. As a bonus, also fixes #11005 (bug was noticed during implementation).

claude added 4 commits May 5, 2026 14:50
Introduces a new package(std) module providing two composable retry
primitives for interrupted system calls:

- retryOnEINTR: loops while a one-shot syscall returns an error sentinel
  and errno == EINTR; propagates the final result to the caller.
- retryShortIO: drives a partial-progress I/O loop (à la fwrite/posix.write)
  until all bytes are transferred or a non-transient error occurs; accepts an
  optional onEINTR hook (clearerr discipline for stdio call sites).

Replaces the nested retryInterrupted template in std.process and provides
the primitive for fixing std.stdio's EINTR-prone write paths.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The byte-array fast path of LockingTextWriter.put throws ErrnoException
when fwrite reports a short write, matching the writer's documented
contract. The per-character fall-through path discarded the return
values of fputc/fputwc, so write errors (closed/broken pipe, full
disk, EBADF, etc.) corrupted output silently.

Wrap the underlying calls in putcChecked / putwcChecked so the
per-character path raises the same ErrnoException as the byte-array
path. Demonstrated by the new /dev/full test.

dlang#11005
…rites

A signal whose handler does not carry SA_RESTART can interrupt fwrite(3)
mid-write, causing it to return a short count with errno == EINTR and
the stream's error indicator set. Three write paths in std.stdio
treated this as fatal: LockingTextWriter.put (byte-array fast path and
per-character paths), File.rawWrite, and BinaryWriterImpl.rawWrite.
Programs would crash on the next writeln after a signal landed mid-flush.

Wrap the underlying fwrite/fputc/fputwc calls in std.internal.retry's
retryShortIO and retryOnEINTR so EINTR is transparently retried until
the buffer is fully written or a non-transient error occurs.

dlang#11006
Removes the local nested retryInterrupted template in spawnProcessPosix
and switches its three call sites to the shared retryOnEINTR helper.
Pure refactor — semantics are identical.
Copy link
Copy Markdown
Contributor

@thewilsonator thewilsonator left a comment

Choose a reason for hiding this comment

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

ping when this is no longer draft

@CyberShadow CyberShadow marked this pull request as ready for review May 5, 2026 22:34
@CyberShadow CyberShadow requested a review from schveiguy as a code owner May 5, 2026 22:34
@CyberShadow
Copy link
Copy Markdown
Member Author

@thewilsonator Thanks, was waiting for CI. Ready for review.

@thewilsonator thewilsonator merged commit f8fbfb4 into dlang:master May 6, 2026
10 checks passed
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.

EINTR signal causes spurious failure in std.stdio writes LockingTextWriter silently drops fputc/fputwc errors

3 participants