Notice that getppid() returns 0 -- this happens because when entering an existing pid namespace, the parent of a non-init process (which exists outside of the namespace) gets replaced by 0. This sometimes confuses processes (especially shells), but is for the most part fairly innocent...
... except for the problem that 79f40f6 aimed to fix. The parent gets its own pid with getpid(), but that value has no chance of being the same as getppid() when the child is in the pid namespace. I'm not sure how it even managed to work, but I think we got saved by init being able to get an accurate value for getppid().
In any case, this was the wrong approach. A more reliable way of detecting whether your parent died, is to simply arrange for said parent to set up a nonblocking pipe, and do nothing with it. When reading from the pipe in the child, one of two things can then happen: either the read succeeds with EOF, meaning the pipe was closed by the kernel on process death, or the read fails with EAGAIN, which means the process is still alive.
79f40f6 (sig: make PDEATHSIG handling non-racy) introduced a failure mode that I hadn't forseen at the time; consider the following:
$ bst --pidfile=/tmp/pid sleep infinity & $ bst --share all=/tmp/pid true
If you strace the second bst invocation, you'll see the following:
... [pid 3475469] prctl(PR_SET_PDEATHSIG, SIGKILL) = 0 [pid 3475469] getppid() = 0 [pid 3475469] tgkill(1, 1, SIGKILL) = 0
Notice that getppid() returns 0 -- this happens because when entering an existing pid namespace, the parent of a non-init process (which exists outside of the namespace) gets replaced by 0. This sometimes confuses processes (especially shells), but is for the most part fairly innocent...
... except for the problem that 79f40f6 aimed to fix. The parent gets its own pid with getpid(), but that value has no chance of being the same as getppid() when the child is in the pid namespace. I'm not sure how it even managed to work, but I think we got saved by init being able to get an accurate value for getppid().
In any case, this was the wrong approach. A more reliable way of detecting whether your parent died, is to simply arrange for said parent to set up a nonblocking pipe, and do nothing with it. When reading from the pipe in the child, one of two things can then happen: either the read succeeds with EOF, meaning the pipe was closed by the kernel on process death, or the read fails with EAGAIN, which means the process is still alive.