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

> I'm not actually sure what the proposal here is. Are we suggesting 
> that all Python's means of terminating a process should use the 
> same exit code?

That's how I read it, but I don't agree if it means always pretending that a 
process was killed by a SIGTERM POSIX signal. That's fighting an uphill battle 
against the platform and its conventions.

I singled out the case where multiprocessing tries to pretend that Windows has 
Unix signals. It documents that `exitcode` will be negative if terminated by a 
signal. It doesn't qualify that this is only in Unix.

    exitcode
        The child’s exit code. This will be None if the process has not
        yet terminated. A negative value -N indicates that the child
        was terminated by signal N.

A negative exit code in Windows (i.e. 0x8000_0000 and above) has many possible 
meanings. Generally it indicates an abnormal error of some sort that terminated 
the process, and generally the code is an NTSTATUS or HRESULT value, such as 
STATUS_CONTROL_C_EXIT or E_FAIL (0x8000_4005). However, there isn't a 
convention to use an NTSTATUS or HRESULT error code when manually terminating a 
process. Instead, the convention is to use EXIT_FAILURE (1).

multiprocessing pretends that terminate() is implemented with a SIGTERM signal. 
To do so, it terminates with an exit code that's just above the system 16-bit 
range:

    TERMINATE = 0x10000

    def terminate(self):
        if self.returncode is None:
            try:
                _winapi.TerminateProcess(int(self._handle), TERMINATE)
            except OSError:
                if self.wait(timeout=1.0) is None:
                    raise

and maps this code to -signal.SIGTERM:

    def wait(self, timeout=None):
        if self.returncode is None:
            if timeout is None:
                msecs = _winapi.INFINITE
            else:
                msecs = max(0, int(timeout * 1000 + 0.5))

            res = _winapi.WaitForSingleObject(int(self._handle), msecs)
            if res == _winapi.WAIT_OBJECT_0:
                code = _winapi.GetExitCodeProcess(self._handle)
                if code == TERMINATE:
                    code = -signal.SIGTERM
                self.returncode = code

        return self.returncode

I don't know why it doesn't simply use -SIGTERM instead of involving the 
intermediate error code. 

It's apparently trying to close a loop for scripts that call terminate() and 
look for this case, or for logging, but the platform convention in Windows 
doesn't allow distinguishing when a process was forcibly terminated. We don't 
know whether an exit status of 1 means the process failed internally or was 
forcibly terminated by another tool. So we can't rely on the exit code in 
Windows in the same way that it can be relied on in POSIX. All we know is that 
the process failed. Terminating with an exit code of 15 or -15 in some cases 
does nothing to solve the problem in general.

----------
title: Inconsistent returncode/exitcode for terminated child processes on 
Windows -> Inconsistent exitcode for terminated child processes on Windows
versions: +Python 3.10 -Python 3.7

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

Reply via email to