pythonsignalswaitchild-processubuntu-22.04

Python sigwait on SIGCHLD - does not return on child termination


I am trying to wait in python until either

There is a function os.sigwait that seems to fit this purpose, but I cannot get it to return on a forked child process exit by calling os.sigwait({signal.SIGCHLD}) - this ends in a deadlock.

What I tried:

#!/usr/bin/env python3
import signal
import os
import time

if __name__ == '__main__':
    pid = None  # initial value

    try:
        pid = os.fork() # method is available only on UNIX platforms

        if pid != 0:  # parent
            # Wait for child exit or SIGINT
            # (should also work for signals other than SIGINT)
            signal.sigwait({signal.SIGCHLD, signal.SIGINT})
            print("Got signal")
            # never reaching this statement by child exit

        else:  # child
            time.sleep(3)

    finally:
        if pid is None: # fork failed
            pass
        elif pid == 0:
            print("\nChild cleaning up")
        else:
            print("\nParent cleaning up")

Solution

  • Pulling the answer out of comments:

    The solution is to call pthread_sigmask(SIG_BLOCK, {SIGCHLD, SIGINT}) before calling sigwait().

    The sigwait family of functions are designed to accept pending signals, rather than to deliver as do sigaction and signal. For this to work properly, the desired signals need to be masked (blocked) before they can be reliably accepted. Indeed, in the POSIX specification, calling sigwait on a set of signals without first blocking those signals is undefined