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.

Title: Handling Ctrl+C while waiting on I/O in Windows
Type: enhancement Stage:
Components: Interpreter Core, IO, Windows Versions: Python 3.10, Python 3.9, Python 3.8
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: eryksun, paul.moore, sovetov, steve.dower, tim.golden, zach.ware
Priority: normal Keywords:

Created on 2021-03-16 21:48 by sovetov, last changed 2022-04-11 14:59 by admin.

Messages (2)
msg388890 - (view) Author: George Sovetov (sovetov) * Date: 2021-03-16 21:48
Ctrl+C alone has no effect, but Ctrl+Break works:
winrs -r: -u:Administrator -p:qweasd123 python -c "import sys;"
Although, if I press Ctrl+C, type zero or more symbols and then press Enter, KeyboardInterrupt is raised:
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "C:\Program Files\Python39\lib\encodings\", line 22, in decode
    def decode(self, input, final=False):

With the following commands, both Ctrl+C and Ctrl+Break work:
winrs -r: -u:Administrator -p:qweasd123 python -c "import time;time.sleep(10)"
"c:\Program Files\Python39\python.exe" -c "import sys;"
"c:\Program Files\Python39\python.exe" -c "import time;time.sleep(10)"

I faced this issue when working with WSMV (Windows remoting API) directly, but I reproduced this with winrs to make sure it's not a bug in my code. I send the Ctrl+C signal, got a no-error response, then poll the running command. It behaves as if a signal had no effect.
msg388896 - (view) Author: Eryk Sun (eryksun) * (Python triager) Date: 2021-03-16 23:52
winrshost.exe runs Python with its standard I/O redirected to pipes, so blocks the main thread while waiting for the synchronous read to complete. If the user types something, then the read completes and the main thread can call the SIGINT handler, which raises KeyboardInterrupt.

By default, SIGBREAK is not handled, so the console CTRL_BREAK_EVENT executes the default handler on the control thread, which calls ExitProcess(STATUS_CONTROL_C_EXIT).

Currently, the only I/O that can be interrupted is reading from console input, since the console itself cancels the request when the user presses Ctrl+C.

To interrupt synchronous I/O in general, the C signal handler could call WinAPI CancelSynchronousIo() with a handle for the main thread. Synchronous I/O calls would have to be updated to handle ERROR_OPERATION_ABORTED (from C _doserrno if calling C read/write). This entails calling PyErr_CheckSignals() in order to call the registered signal handler and return whether it raises an exception. But first PyOS_InterruptOccurred() has to be checked. If SIGINT isn't tripped, the abort request didn't originate from the signal handler, so the call should fail without calling PyErr_CheckSignals().

An asynchronous I/O request (e.g. socket I/O is typically asynchronous) can be canceled with CancelIo[Ex], which requires a handle for the open file that has the pending request. This case can only be addressed by the C signal handler if the main thread registers the file handle with the signal module before waiting for I/O completion. If a wait for I/O completion is alertable, then a user-mode APC can be queued to the thread in order to call CancelIo() on the file handle. If it's not an alertable wait, then the I/O request can be canceled with CancelIoEx(), but preferably the OVERLAPPED record for the request should also be registered, else all of the file's pending I/O requests will be canceled, instead of canceling only the request that's blocking the main thread.
Date User Action Args
2022-04-11 14:59:42adminsetgithub: 87689
2021-03-16 23:52:56eryksunsettype: enhancement
title: Handling Ctrl+C when waiting on stdin on Windows via winrs -> Handling Ctrl+C while waiting on I/O in Windows
components: + Interpreter Core, Windows, IO

nosy: + paul.moore, eryksun, tim.golden, zach.ware, steve.dower
versions: + Python 3.8, Python 3.10
messages: + msg388896
2021-03-16 21:48:50sovetovcreate