I want to fork a process and wait for the parent to exit before doing something in the child.
The naive way would be a busy loop like this:
# BAD WAY!
pid = os.fork()
if pid == 0:
while True:
if os.path.isdir("/proc/%s" % pid):
break
time.sleep(0.1)
# Parent is dead there.
But this is vulnerable to PID reuse issues. If another process is created right after the parent exits and gets its PID, the child will never exit.
Another way would be to use a flock()
on a specific file. But it's not going to work, because the child shares the same locks as the parent.
A foolproof way to do this is using a special trick: create a pipe in the parent, and in the child, you just wait until you get an EOF.
# Good way
read_fd, write_fd = os.pipe()
pid = os.fork()
if pid > 0:
# Close the read pipe, so that only the child is the reader.
os.close(read_fd)
# It is important to voluntarily leak write_fd there,
# so that the kernel will close it for the parent process
# when it will exit, triggering our trick.
elif pid == 0:
# Daemon ourselves first.
os.setsid()
for fd in {0, 1, 2}:
os.close(fd)
# Close the write pipe so that the parent is the only writer.
# This will make sure we then get an EOF when the only writer exits.
os.close(write_fd)
# Now, we're waiting on the read pipe for an EOF.
# PS: the assert is not necessary in production...
assert os.read(read_fd, 1) == ""
os.close(read_fd)
# At this point, the parent is dead.