Replace the signal handling system - #4984
Merged
Merged
Conversation
SeanTAllen
marked this pull request as draft
March 9, 2026 20:31
SeanTAllen
commented
Mar 9, 2026
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.
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 The basic format of the release notes (using markdown) should be: Thanks. |
SeanTAllen
force-pushed
the
redesign-signal-handling
branch
3 times, most recently
from
July 7, 2026 21:44
00bee2a to
a052f10
Compare
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
force-pushed
the
redesign-signal-handling
branch
3 times, most recently
from
July 11, 2026 18:14
e029ff6 to
67f4bc3
Compare
SeanTAllen
force-pushed
the
redesign-signal-handling
branch
from
July 21, 2026 17:33
45e96a0 to
b8c90e9
Compare
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
force-pushed
the
redesign-signal-handling
branch
from
July 21, 2026 22:31
45e0073 to
5c7b48b
Compare
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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
SignalAuthand 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 throughSignalNotify.registration_failed, and the handler whose registration failed disposes itself. The notify'sdisposedcallback 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