Description
Bug report
Today I ran into a very weird behaviour in one of my projects, that uses asyncio and multiprocessing.
When I interrupted the program with a Ctrl-C on the terminal, the signal handler set in asyncio with loop.add_signal_handler
was triggered multiple times! Further inspection showed, that if I manually send a SIGINT
to one of the worker child processes, it triggered the main process signal handler.
I could trace the issue to the socket used by asyncio to receive the signals via signal.set_wakeup_fd
, which seems to receive the signal bytes also from the child processes.
Running signal.set_wakeup_fd(-1)
at least once in the worker processes worked as a workaround for me but cannot be the final solution.
Also, it seems, that other signal operations also can clear the issue (for example some automatically manager child processes did not trigger the bug, as they seem to ignore SIGINT
).
In my project I used concurrent.futures.ProcessPoolExecutor
, but I don't think that matters, as long as the signal handler (and wakeup fd) is set before the child is started.
Your environment
- CPython versions tested on:
Python 3.10.4 - Operating system and architecture:
Kali Linux rolling with kernel: Debian 5.16.18-1kali1 (2022-04-01) x86_64
Bug output
asyncio_signal_bug.py.txt
# python3 asyncio_signal_bug.py
394236 Signal Handler set
394237 Worker 1 started
394240 Worker 2 started
^C394236 received signal: Signals.SIGINT
394236 received signal: Signals.SIGINT
394236 received signal: Signals.SIGINT
^C394236 received signal: Signals.SIGINT
394236 received signal: Signals.SIGINT
394236 received signal: Signals.SIGINT
# python3 asyncio_signal_bug.py --set-in-children
394241 Signal Handler set
394242 Worker 1 started
394245 Worker 2 started
^C394241 received signal: Signals.SIGINT
^C394241 received signal: Signals.SIGINT
^C394241 received signal: Signals.SIGINT
^C394241 received signal: Signals.SIGINT
^C394241 received signal: Signals.SIGINT
^C394241 received signal: Signals.SIGINT
Notice, that in the first block, for every ^C, there are three signals received, whereas in the second block (if signal.set_wakeup_fd(-1)
was called in the workers) there is only one.
Metadata
Metadata
Assignees
Projects
Status