New submission from Eli Bendersky email@example.com:
docs@ list report by Daniel Dieterle:
in the documentation (http://docs.python.org/library/subprocess.html#subprocess.Popen.send_signal) is a bug.
CTRL_C_EVENT can not be sent to processes started with a creationflags parameter which includes CREATE_NEW_PROCESS_GROUP. Why can be read in the msdn documentation http://msdn.microsoft.com/en-us/library/windows/desktop/ms683155%28v=vs.85%2... .
A workaround using CTRL_C_EVENT nevertheless is described here: http://stackoverflow.com/questions/7085604/sending-c-to-python-subprocess-ob...
I do not know why the subprocess.CREATE_NEW_PROCESS_GROUP parameter was introduced. But it is useless for terminating a process with os.kill() in combination with signal.SIGTERM, which corresponds to a CTRL-C-EVENT. A CTRL-C-EVENT is only forwarded to the process if the process group is zero. Therefore the Note in the documentation on Popen.send_signal() is wrong.
---------- assignee: docs@python components: Documentation messages: 147272 nosy: docs@python, eli.bendersky priority: normal severity: normal status: open title: Possible problem in documentation of module subprocess, method send_signal versions: Python 2.7
Eli Bendersky firstname.lastname@example.org added the comment:
Brian, I see this text (along with the implementation) was added by you in 60197:0ab89e8bdedc
Could you state your opinion on this issue?
---------- nosy: +brian.curtin
Brian Curtin email@example.com added the comment:
But it is useless for terminating a process with os.kill() in combination with signal.SIGTERM, which corresponds to a CTRL-C-EVENT.
SIGTERM does not correspond to CTRL_C_EVENT. They may be similar in what they do, but os.kill on Windows only works with exactly CTRL_C_EVENT and CTRL_BREAK_EVENT, as this uses GenerateConsoleCtrlEvent which only works with those two values. As the documentation states, anything other than those two constants is sent to TerminateProcess. If you call os.kill with signal.SIGTERM, it would kill the process with return code 15.
I will look into adjusting the text a little, and I also need to look into the tests. I currently have CTRL_C_EVENT tests skipped, probably because I am passing the wrong process stuff as he mentioned. I had it working at some point, but I may have generalized it too far.
---------- assignee: docs@python -> brian.curtin components: +Windows stage: -> needs patch type: -> behavior versions: +Python 3.2, Python 3.3
Eryk Sun added the comment:
You can send CTRL_C_EVENT to a process group. But it requires the group leader to manually enable Ctrl+C handling. Initially it's disabled when creating a process with CREATE_NEW_PROCESS_GROUP.
The attached script demonstrates sending CTRL_C_EVENT to a process group. The child process is the group leader, so CTRL+C event processing has to be manually enabled in it by calling SetConsoleCtrlHandler(NULL, FALSE). This flag gets inherited by the grandchild process. Example output:
Process 0300: created process 0464 Process 0464: created process 0456 Process 0464: received CTRL+C Process 0456: received CTRL+C
That said, given that MSDN [erroneously] claims that this isn't possible, probably the subprocess docs should only mention sending CTRL_BREAK_EVENT.
---------- nosy: +eryksun versions: +Python 3.4, Python 3.5, Python 3.6 -Python 3.2, Python 3.3 Added file: http://bugs.python.org/file41242/proc_group_ctrl_c.py
Eryk Sun firstname.lastname@example.org added the comment:
Popen.send_signal() documents that sending CTRL_C_EVENT (cancel) to a process group is possible, which is clearly a true statement and easily demonstrated. OTOH, the Windows documentation of GenerateConsoleCtrlEvent() claims it's not possible. If you know what the system really does for this case, then the latter claim reads as inconsistent in spirit with the "remarks" section on the very same page, as well as the documentation of SetConsoleCtrlHandler(). It's also strangely worded to say the event isn't "received" by processes in the group, when it's actually about whether each individual process elects to ignore the cancel event that it receives.
The documentation of send_signal() could explain that the cancel event may be ignored in processes, which is initially the case for a new group and is inheritable by child processes. Sending the cancel event to all processes in the console session (process group 0) does nothing to resolve the general problem. It can help with a particular problem where the application has desired behavior for the cancel event and is known to be neutral about ignoring it, i.e. it never calls SetConsoleCtrlHandler(NULL, ...) to either enable or disable ignoring of the cancel event, and is known to not have been created as a new process group or by a parent process that ignores the cancel event.
It's worth discussing that CTRL_BREAK_EVENT can never be ignored at the process level. An application has to go out of its way to ignore the break event. It's the preferred event to send a console application when you need to terminate the process. Often it calls the default handler, which calls ExitProcess(), which at least gives shared libraries a chance to detach cleanly (i.e. DLL_PROCESS_DETACH). The C runtime maps the break event to SIGBREAK, and it also maps CTRL_CLOSE_EVENT to SIGBREAK. Thus if all you can set is a C signal handler, as is the case for Python scripts by default, then you need to handle SIGBREAK in order to exit gracefully for the cases of closing the console, manual Ctrl+Break, and a generated break event. This includes using Task Manager or taskkill.exe to non-forcefully kill the process that effectively owns the console session, which is implemented by sending WM_CLOSE to the console window.
---------- versions: +Python 3.10, Python 3.9 -Python 2.7, Python 3.4, Python 3.5, Python 3.6