On Windows there isn’t really a SIGKILL signal, hence it not existing in
signal on Windows.
Could we define SIGKILL on Windows, then internally take:
and have that call TerminateProcess?
I know it isn’t a 100% mapping of SIGKILL → TerminateProcess but its pretty darn close. From the winapi docs:
The TerminateProcess function is used to unconditionally cause a process to exit.
vs the GNU docs:
The SIGKILL signal is used to cause immediate program termination
TLDR: I propose defining
signal.SIGKILL on Windows and if it is used by
os.kill, internally call
TerminateProcess; after all they seem to be functionally similar.
I think there is strong precedent that functionality in
os is supposed to reflect the actual functionality offered by the operating system, including mirroring its API as closely as makes sense in Python; and then platform-agnostic wrappers are put at a higher level.
Actually upon looking at the source, it seems it actually already sort of does what I was asking about: https://github.com/python/cpython/blob/main/Modules/posixmodule.c#L8915
So I guess sending a kill with any regular signal is more/less the same on Windows… Weird.
Unfortunately, Python’s implementation of
os.kill() on Windows is kind of a mess.
First and foremost, the use of
GenerateConsoleCtrlEvent() is completely wrong. This API function requires a console process group ID (pgid). The current implementation of
GenerateConsoleCtrlEvent() in the console host (i.e. conhost.exe or openconsole.exe) is ridiculously buggy in many cases if it gets passed a pid that’s not a pgid. The only way to get a pid value that’s known to also be a pgid value is to spawn a process with the creation flag
os.kill() should only call
GenerateConsoleCtrlEvent() when passed a negative process ID, which, as specified by POSIX, indicates that it’s a process group ID. The pid value -1 should be special cased as Windows console process group 0, which includes every process in the current console session. The pid value 0 (i.e. every process in the current process group, according to POSIX) should fail with a
ValueError. It can’t be implemented on Windows since there’s no documented way to query the process group ID of the current process.
Also, when the pid value is negative, the implementation of
os.kill() should map
signal.SIGBREAK to the console control events
CTRL_BREAK_EVENT. Those are the only two values that should be supported in this code path. Any value other than
SIGBREAK should fail as a
ValueError. In particular, the special signal value 0 that POSIX specifies can’t be reasonably supported to test for the existence of a process group.
If the pid value is positive, then the implementation of
os.kill() should take the code path that calls
TerminateProcess(). This code path can allow any value for the signal number, which will be used as the exit status value of the process. To better support cross-platform code,
signal.SIGKILL could be defined as the integer enum value 1. It’s common on Windows to use 1 as the exit status when forcibly terminating a process. If the signal value is 0, only
OpenProcess() should be called, to test for existence and
PROCESS_TERMINATE access, as specified by POSIX.