classification
Title: Possible problem in documentation of module subprocess, method send_signal
Type: behavior Stage: needs patch
Components: Documentation, Windows Versions: Python 3.10, Python 3.9
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: brian.curtin Nosy List: brian.curtin, docs@python, eli.bendersky, eryksun, nitika
Priority: normal Keywords:

Created on 2011-11-08 03:23 by eli.bendersky, last changed 2021-02-24 21:50 by eryksun.

Files
File name Uploaded Description Edit
proc_group_ctrl_c.py eryksun, 2015-12-05 00:01
Messages (7)
msg147272 - (view) Author: Eli Bendersky (eli.bendersky) * (Python committer) Date: 2011-11-08 03:23
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%29.aspx .

A workaround using CTRL_C_EVENT nevertheless is described here:
http://stackoverflow.com/questions/7085604/sending-c-to-python-subprocess-objects-on-windows/7980368#7980368 

--

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.
msg147425 - (view) Author: Eli Bendersky (eli.bendersky) * (Python committer) Date: 2011-11-11 09:24
Brian, I see this text (along with the implementation) was added by you in  60197:0ab89e8bdedc

Could you state your opinion on this issue?
msg147432 - (view) Author: Brian Curtin (brian.curtin) * (Python committer) Date: 2011-11-11 14:19
> 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.
msg194314 - (view) Author: Eli Bendersky (eli.bendersky) * (Python committer) Date: 2013-08-03 22:27
Brian - gentle ping
msg213288 - (view) Author: Nitika Agarwal (nitika) * Date: 2014-03-12 20:10
Hi, I would like to propose a patch for this.
msg255903 - (view) Author: Eryk Sun (eryksun) * (Python triager) Date: 2015-12-05 00:01
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.
msg387640 - (view) Author: Eryk Sun (eryksun) * (Python triager) Date: 2021-02-24 21:50
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.
History
Date User Action Args
2021-02-24 21:50:23eryksunsetmessages: + msg387640
versions: + Python 3.9, Python 3.10, - Python 2.7, Python 3.4, Python 3.5, Python 3.6
2015-12-05 00:01:03eryksunsetfiles: + proc_group_ctrl_c.py
versions: + Python 3.4, Python 3.5, Python 3.6, - Python 3.2, Python 3.3
nosy: + eryksun

messages: + msg255903
2014-03-12 20:10:33nitikasetnosy: + nitika
messages: + msg213288
2013-08-03 22:27:14eli.benderskysetmessages: + msg194314
2011-11-11 14:19:25brian.curtinsetversions: + Python 3.2, Python 3.3
messages: + msg147432

assignee: docs@python -> brian.curtin
components: + Windows
type: behavior
stage: needs patch
2011-11-11 09:24:06eli.benderskysetnosy: + brian.curtin
messages: + msg147425
2011-11-08 03:23:14eli.benderskycreate