This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: With asyncio subprocess, send_signal() and the child process watcher will both call waitpid()
Type: behavior Stage:
Components: asyncio Versions: Python 3.9
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: asvetlov, lincheney, yselivanov
Priority: normal Keywords:

Created on 2021-03-21 06:53 by lincheney, last changed 2022-04-11 14:59 by admin.

Messages (1)
msg389218 - (view) Author: (lincheney) Date: 2021-03-21 06:53
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.
History
Date User Action Args
2022-04-11 14:59:43adminsetgithub: 87744
2021-03-21 06:53:15lincheneycreate