Override console Ctrl+C event handler with handler in module signal
#1951
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.
This is basically a fix for the
signalmodule on POSIX. What was happening was that on POSIX, signals (to be more accurate:SIGINTonly) are handled bySimpleSignalState, which installs aConsoleCancelEventHandleronConsole.CancelKeyPress. However,BasicConsolealso installs its handler to handle Ctrl+C, and it happens very early during execution, way before modulesignalcan be imported. Since the event handlers are executed in the order of registrations,BasicConsoleis seeing the event beforesignal, callingThreadAbort(which obviously does not work on .NET), and modulesignalhad no chance to even react toSIGINT. This means that settingSIGINTto be ignored, or to terminate the program, or to call a custom event handler was ineffective.This problem does not occur on Windows because
NtSignalStateinstalls its event handler by making a syscall toSetConsoleCtrlHandlerinkernel32.dll, which does its callbacks in a "last registered — first called" fashion, so the late registration insignaloverrulesBasicConsole.There is no straightforward way to prevent
BasicConsoleto register its event handler, but there is a way to override what it does by modifying a public property onBasicConsole, and this is what this PR does. The only quirk here was that the reference to aBasicConsoleinstance was not readily available to modules, so I added a new property onPythonContextto provide it. If there is a better way of doing it I would be glad to hear it.