This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author njs
Recipients Mark, eryksun, louielu, martin.panter, njs, pitrou, terry.reedy
Date 2017-06-30.00:36:17
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1498782979.38.0.128542495971.issue29926@psf.upfronthosting.co.za>
In-reply-to
Content
Then maybe simplest solution is to scale back the claim :-).

The important semantic change would be that right now, interrupt_main() is documented to cause KeyboardInterrupt to be raised in the main thread. So if you register a custom SIGINT handler that *doesn't* raise KeyboardInterrupt, interrupt_main() doesn't care: it doesn't invoke your custom handler, it just raises KeyboardInterrupt. My proposal would make it so that interrupt_main() does cause custom SIGINT handlers to be called, as well as triggering all of the interpreters existing machinery for prompt signal delivery (waking up time.sleep etc.), so in that respect it would be much more similar to a "real" control-C than it is now. This is a non-trivial semantic change, so it would need to be documented, but I'm not attached to the "equivalent to control-C" phrasing.

Even on UNIX, a "real" control-C is delivered to all processes in the foreground process group (or something like that, ttys are weird), but we would want interrupt_main() to only be delivered to the current process, so the equivalence wouldn't be exact there either.

> That operation isn't buggy on its own to my knowledge

I spent quite some time trying to make this work in order to test control-C handling in trio, and eventually gave up because I just could not make it work reliably. One notable effect is that if you call GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0) in an appveyor test run, then it breaks appveyor -- at the end of the run it freezes with "Terminate batch job (Y/N)?" and then sits until the test run times out. It's possible to work around this with some extremely obscure code (make sure you always spawn a subprocess with CREATE_NEW_CONSOLE or maybe CREATE_NEW_CONSOLE_GROUP etc.), but (a) we can't tell people that they need to do that before running code that uses interrupt_main(), and (b) even when I did that, then I still had bizarre issues I couldn't figure out, where sometimes the event just wouldn't be delivered unless I ran the interpreter with the -u option for unbuffered stdio (?!?!) (see [1]).

I just don't think this is something that CPython can use.

I eventually switched to simulating control-C events for testing by calling raise(SIGINT), and that's worked much much better.

> I mentioned the possibility of calling CancelSynchronousIo in order to cancel a console read like Ctrl+C does (but clunkier) -- again, because of the equivalence claim. ERROR_OPERATION_ABORTED would need to be handled like EINTR on Unix. This would entail small changes to a lot of code, so it does need a separate issue if there's any support for this idea.

It still wouldn't be equivalent because control-C only cancels console reads, but CancelSynchronousIo would cancel *any* blocking I/O operation that the main thread was doing, right? So e.g. if the main thread was blocked doing socket.recv, then control-C wouldn't interrupt that, but interrupt_main() / PyErr_SetInterrupt() would. I can certainly see an argument that Python's C-level signal handler *should* call CancelSynchronousIo in general, and then raise(SIGINT) and control-C would be equivalent because they both called CancelSynchronousIo, but yeah, that's way beyond the scope of this issue.

[1] https://github.com/python-trio/trio/commit/95843654173e3e826c34d70a90b369ba6edf2c23#diff-345cfb6c136028f9514b67ee7bb8e035R11
History
Date User Action Args
2017-06-30 00:36:19njssetrecipients: + njs, terry.reedy, pitrou, martin.panter, Mark, eryksun, louielu
2017-06-30 00:36:19njssetmessageid: <1498782979.38.0.128542495971.issue29926@psf.upfronthosting.co.za>
2017-06-30 00:36:19njslinkissue29926 messages
2017-06-30 00:36:17njscreate