[New-bugs-announce] [issue43578] With asyncio subprocess, send_signal() and the child process watcher will both call waitpid()

lincheney report at bugs.python.org
Sun Mar 21 02:53:15 EDT 2021


New submission from lincheney <lincheney at gmail.com>:

Under unix, when creating a asyncio subprocess, the child process watcher will call waitpid() to reap the child, but if you call send_signal() (or terminate() or kill() ) on the asyncio subprocess, this will also call waitpid(), causing exactly one of these to fail, as you cannot call waitpid() on a PID more than once.

If the send_signal() fails, this doesn't seem much of an issue.
If the child process watcher fails however, it sets the returncode to 255 and also returns 255 when running wait() and also emits a warning.

I've seen this behaviour with the ThreadedChildWatcher, but possibly other Unix child watchers that use waitpid() suffer from the same problem.

The behaviour is racey (it depends on which one completes the waitpid() first), but if you try it enough it will appear:
```
import asyncio
import signal

async def main():
    while True:
        proc = await asyncio.create_subprocess_exec('sleep', '0.1')
        await asyncio.sleep(0.1)
        try:
            proc.send_signal(signal.SIGUSR1)
        except ProcessLookupError:
            pass
        assert (await proc.wait() != 255)

asyncio.run(main())

```

The output looks like:
```
Unknown child process pid 1394331, will report returncode 255
Traceback (most recent call last):
  File "/tmp/bob.py", line 14, in <module>
    asyncio.run(main())
  File "/usr/lib/python3.9/asyncio/runners.py", line 44, in run
    return loop.run_until_complete(main)
  File "/usr/lib/python3.9/asyncio/base_events.py", line 642, in run_until_complete
    return future.result()
  File "/tmp/bob.py", line 12, in main
    assert (await proc.wait() != 255)
AssertionError
```

This would be expected behaviour if I were explicitly calling waitpid() myself (ie I'm shooting my own foot, so I'd deserve the bad behaviour), but that's not the case here nor any other exotic code.

----------
components: asyncio
messages: 389218
nosy: asvetlov, lincheney, yselivanov
priority: normal
severity: normal
status: open
title: With asyncio subprocess, send_signal() and the child process watcher will both call waitpid()
type: behavior
versions: Python 3.9

_______________________________________
Python tracker <report at bugs.python.org>
<https://bugs.python.org/issue43578>
_______________________________________


More information about the New-bugs-announce mailing list