Eryk Sun <eryk...@gmail.com> added the comment:

Unless you're willing to step through hoops using ctypes or PyWin32, sending 
Ctrl+Break requires already being attached to the same console as the target. 
Note that the target isn't necessarily a single process that's attached to the 
console. Sending a control event is implemented by calling WinAPI 
GenerateConsoleCtrlEvent, which targets process group identifiers (i.e. like 
Unix killpg), not process identifiers (i.e. not like Unix kill). 

FYI, to generate the event, the console host (conhost.exe) uses an LPC port to 
relay the request to the session Windows server (csrss.exe), which is 
privileged to inject a thread in each target process. This control thread 
starts executing at a known entry point named "CtrlRoutine" in kernelbase.dll. 
(Prior to Windows 7 the console is actually hosted in csrss.exe, so there's no 
need to relay the request, and "CtrlRoutine" is implemented in kernel32.dll 
instead.)

If you don't know the group ID, then the only option is to broadcast Ctrl+Break 
to group 0, which includes every process that's attached to the console. First 
ignore SIGBREAK (the C signal for CTRL_BREAK_EVENT) via 
signal.signal(signal.SIGBREAK, signal.SIG_IGN). Otherwise the default handler 
will run, which exits the current process. Then send Ctrl+Break via os.kill(0, 
signal.CTRL_BREAK_EVENT). 

On the other hand, if you started the process as a new group, then its ID is 
also the group ID. For example, p = subprocess.Popen('vault.exe', 
creationflags=subprocess.CREATE_NEW_PROCESS_GROUP). In this case you can   send 
Ctrl+Break via os.kill(p.pid, signal.CTRL_BREAK_EVENT). Windows will generate 
the event only in the subset of processes that are both in the target process 
group and currently attached to the console that originated the request.

The current implementation of os.kill() is behaving as designed and documented 
in Python 2.7. There is no bug in this case. However, the docs should clarify 
that the target when sending a console control event is a process group, not a 
process. They should also refer to the subprocess docs to explain how to create 
a new group via the CREATE_NEW_PROCESS_GROUP creation flag. Also, the line 
about accepting process handles should be stricken. A process handle is an 
integer that's indistinguishable from a process/group identifier, so the 
statement makes no sense, and thankfully the code doesn't try to implement 
anything that crazy.

In Python 3, someone decided that if GenerateConsoleCtrlEvent fails, os.kill() 
should also try TerminateProcess, to allow terminating the process explicitly 
with exit codes 0 (CTRL_C_EVENT) and 1 (CTRL_BREAK_EVENT). Of course, killing a 
process using a console control event is nothing at all like terminating it 
abruptly, so to me this looks quite strange; it's coding with a sledgehammer. 
Anyway, if TerminateProcess succeeds it should, but currently does not, clear 
the error from the failed GenerateConsoleCtrlEvent call. That's a bug.

I suggest resolving the bug by partially backing out of the change. It should 
only call GenerateConsoleCtrlEvent for the enum values signal.CTRL_C_EVENT and 
signal.CTRL_BREAK_EVENT, which I think was suggested by Steve Dower at one 
point. TerminateProcess can be called otherwise for 0 and 1 values. In this 
case, os.kill() would no longer magically switch between fundamentally 
different functions in a single call. An exception should always be raised if 
GenerateConsoleCtrlEvent fails. Possibly in 3.8, os.killpg() could be added on 
Windows for sending console control events to process groups, while deprecating 
or discouraging using os.kill() for this.

----------
nosy: +eryksun
versions: +Python 3.7, Python 3.8

_______________________________________
Python tracker <rep...@bugs.python.org>
<https://bugs.python.org/issue33245>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to