Skip to content

Replace the signal handling system - #4984

Merged
SeanTAllen merged 1 commit into
mainfrom
redesign-signal-handling
Jul 21, 2026
Merged

Replace the signal handling system#4984
SeanTAllen merged 1 commit into
mainfrom
redesign-signal-handling

Conversation

@SeanTAllen

@SeanTAllen SeanTAllen commented Mar 8, 2026

Copy link
Copy Markdown
Member

The old signal system's problems were design-level, not bugs to patch around. Registering two handlers for the same signal did different things on different platforms: on Linux the first silently won and the loser hung forever waiting for notifications that never came (#5130); on macOS the second silently replaced the first. Signal handling was the one I/O primitive in the standard library with no capability gate. Registration accepted fatal signals that cannot be meaningfully handled, uncatchable ones the OS silently refused, and SIGUSR2, which the runtime reserves for scheduler wake — all without error, and a handler for the last two never fired. A registration that failed was indistinguishable from ordinary disposal, and its error path left the OS handler installed with nothing behind it (#5128); on the delivery side, a failed read sent a signal count from uninitialized memory (#5152). A signal arriving during runtime shutdown could touch freed memory (#5564).

This replaces the system, implementing RFC #87. Registration is gated by SignalAuth and takes only validated signal numbers (HandleableSignal). A signal fans out to up to 16 subscribers, the same way on every platform, and registration commits synchronously so a raise right after subscribing cannot be lost. Failures are reported through SignalNotify.registration_failed, and the handler whose registration failed disposes itself. The notify's disposed callback fires when unregistration has actually finished. Shutdown restores default dispositions instead of leaving the process pointing into freed runtime state.

User-facing details and migration examples are in the release note (.release-notes/replace-signal-handling.md). The Windows port targets the readiness backend that replaced IOCP on main (#5556), and main's silent-failure hardening in the ASIO backends carries through the redesigned signal paths.

Closes #5793
Closes #5152
Closes #5128
Closes #5130
Closes #5564

@ponylang-main ponylang-main added the discuss during sync Should be discussed during an upcoming sync label Mar 8, 2026
@SeanTAllen
SeanTAllen marked this pull request as draft March 9, 2026 20:31
Comment thread packages/term/ansi_term.pony Outdated
@SeanTAllen SeanTAllen removed the discuss during sync Should be discussed during an upcoming sync label Mar 11, 2026
@ponylang-main ponylang-main added the discuss during sync Should be discussed during an upcoming sync label Jul 2, 2026
@SeanTAllen
SeanTAllen marked this pull request as ready for review July 2, 2026 11:24
SeanTAllen added a commit to ponylang/rfcs that referenced this pull request Jul 2, 2026
The prototype (ponylang/ponyc#4984) settled several things this text
predated. Registration is synchronous on the subscribing thread rather
than serialized through the ASIO request queue — the queued design this
RFC originally prescribed cannot provide the raise-right-after-subscribe
guarantee, because the raise can reach the operating system before a
queued registration is processed. The subscriber table is capped at 16
per signal, and a registration that cannot complete (the cap, or the OS
refusing the install) is reported through a new
SignalNotify.registration_failed callback carrying the reason as a
closed union, then auto-disposed. SIGUSR2 left the whitelist: the
default-build runtime reserves it for scheduler wake, so no build can
both name it and handle it. The Windows section now describes the
readiness backend that replaced IOCP (ponylang/ponyc#5556), the validator
gained the Windows branch, and the drawbacks cover the DisposableActor
conformance loss and the structural-conformer break that the defaulted
callback creates.
@SeanTAllen SeanTAllen added the changelog - changed Automatically add "Changed" CHANGELOG entry on merge label Jul 3, 2026
@SeanTAllen SeanTAllen changed the title Redesign signal handling (RFC #220) Replace the signal handling system Jul 3, 2026
@ponylang-main

Copy link
Copy Markdown
Contributor

Hi @SeanTAllen,

The changelog - changed label was added to this pull request; all PRs with a changelog label need to have release notes included as part of the PR. If you haven't added release notes already, please do.

Release notes are added by creating a uniquely named file in the .release-notes directory. We suggest you call the file 4984.md to match the number of this pull request.

The basic format of the release notes (using markdown) should be:

## Title

End user description of changes, why it's important,
problems it solves etc.

If a breaking change, make sure to include 1 or more
examples what code would look like prior to this change
and how to update it to work after this change.

Thanks.

@SeanTAllen
SeanTAllen force-pushed the redesign-signal-handling branch 3 times, most recently from 00bee2a to a052f10 Compare July 7, 2026 21:44
SeanTAllen added a commit to ponylang/rfcs that referenced this pull request Jul 11, 2026
Reconcile the RFC with the prototype in ponylang/ponyc#4984: SIGUSR2 is
handleable on scheduler_scaling_pthreads builds, not rejected on every
build. Rename the constrained-signal type family to HandleableSignal to
leave room for a signal-sending validator later.
@SeanTAllen
SeanTAllen force-pushed the redesign-signal-handling branch 3 times, most recently from e029ff6 to 67f4bc3 Compare July 11, 2026 18:14
@SeanTAllen
SeanTAllen force-pushed the redesign-signal-handling branch from 45e96a0 to b8c90e9 Compare July 21, 2026 17:33
The old system's problems were design-level, not bugs to patch around.
Registering two handlers for the same signal did different things on
different platforms: on Linux the first silently won and the loser hung
forever waiting for notifications that never came; on macOS the second
silently replaced the first. Signal handling was the one I/O primitive
in the standard library with no capability gate: TCP, UDP, and files
all require an auth token, signals required nothing. Registration
accepted fatal signals that cannot be meaningfully handled, uncatchable
ones the OS silently refused, and SIGUSR2, which the runtime reserves
for scheduler wake — all without complaint, and a handler for the last
two never fired. A registration that failed was indistinguishable from
ordinary disposal, and its error path left the OS handler installed
with nothing to deliver to; on the delivery side, a failed eventfd read
sent a signal count from uninitialized memory. And a signal arriving
while the runtime shut down could run the handler against freed memory.

This replaces the system, implementing RFC #87. Registration is gated
by SignalAuth and takes only validated signal numbers (HandleableSignal).
A signal fans out to up to 16 subscribers, the same way on every
platform, and registration commits synchronously so a raise right
after subscribing cannot be lost. Failures are reported through
registration_failed, and the handler whose registration failed disposes
itself. The notify's disposed callback fires when the runtime has
finished unregistering, so a program can act on the registration
actually being gone. Disposing a signal's last handler restores the
disposition the signal had before it was handled — SIG_IGN for one the
runtime keeps ignored, like SIGPIPE, not a blanket default — and
shutdown does the same for any signal still registered, dropping late
signals instead of touching freed state.

Closes #5793
Closes #5152
Closes #5128
Closes #5130
Closes #5564
@SeanTAllen
SeanTAllen force-pushed the redesign-signal-handling branch from 45e0073 to 5c7b48b Compare July 21, 2026 22:31
@SeanTAllen
SeanTAllen merged commit e28fc30 into main Jul 21, 2026
20 checks passed
@SeanTAllen
SeanTAllen deleted the redesign-signal-handling branch July 21, 2026 23:47
@ponylang-main ponylang-main removed the discuss during sync Should be discussed during an upcoming sync label Jul 21, 2026
github-actions Bot pushed a commit that referenced this pull request Jul 21, 2026
github-actions Bot pushed a commit that referenced this pull request Jul 21, 2026
ahwayakchih added a commit to ahwayakchih/ponyc that referenced this pull request Jul 22, 2026
ahwayakchih added a commit to ahwayakchih/ponyc that referenced this pull request Jul 23, 2026
ahwayakchih added a commit to ahwayakchih/ponyc that referenced this pull request Jul 24, 2026
ahwayakchih added a commit to ahwayakchih/ponyc that referenced this pull request Jul 24, 2026
ahwayakchih added a commit to ahwayakchih/ponyc that referenced this pull request Jul 25, 2026
ahwayakchih added a commit to ahwayakchih/ponyc that referenced this pull request Aug 1, 2026
ahwayakchih added a commit to ahwayakchih/ponyc that referenced this pull request Aug 2, 2026
ahwayakchih added a commit to ahwayakchih/ponyc that referenced this pull request Aug 3, 2026
ahwayakchih added a commit to ahwayakchih/ponyc that referenced this pull request Aug 3, 2026
ahwayakchih added a commit to ahwayakchih/ponyc that referenced this pull request Aug 8, 2026
ahwayakchih added a commit to ahwayakchih/ponyc that referenced this pull request Aug 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changelog - changed Automatically add "Changed" CHANGELOG entry on merge

Projects

None yet

2 participants