On Tue, Sep 24, 2019 at 2:00 PM Michael Kerrisk (man-pages) <mtk.manpages@xxxxxxxxx> wrote: > > Hello Christian, > > >>> If you're the parent of the process you can do this without CLONE_PIDFD: > >>> pid = fork(); > >>> pidfd = pidfd_open(); > >>> ret = pidfd_send_signal(pidfd, 0, NULL, 0); > >>> if (ret < 0 && errno == ESRCH) > >>> /* pidfd refers to another, recycled process */ > >> > >> Although there is still the race between the fork() and the > >> pidfd_open(), right? > > > > Actually no and my code is even too complex. > > If you are the parent, and this is really a sequence that obeys the > > ordering pidfd_open() before waiting: > > > > pid = fork(); > > if (pid == 0) > > exit(EXIT_SUCCESS); > > pidfd = pidfd_open(pid, 0); > > waitid(pid, ...); > > > > Then you are guaranteed that pidfd will refer to pid. No recycling can > > happen since the process has not been waited upon yet (That is, > > D'oh! Yes, of course. You still have a race if you're the parent and you have SIGCHLD set to SIG_IGN though. > > excluding special cases such as where you have a mainloop where a > > callback reacts to a SIGCHLD event and waits on the child behind your > > back and your next callback in the mainloop calls pidfd_open() while the > > pid has been recycled etc.). That's a pretty common case though, especially if you're a library. > > A race could only appear in sequences where waiting happens before > > pidfd_open(): > > > > pid = fork(); > > if (pid == 0) > > exit(EXIT_SUCCESS); > > waitid(pid, ...); > > pidfd = pidfd_open(pid, 0); > > > > which honestly simply doesn't make any sense. So if you're the parent > > and you combine fork() + pidfd_open() correctly things should be fine > > without even having to verify via pidfd_send_signal() (I missed that in > > my first mail.). > > Thanks for the additional detail. > > I added the following to the pidfd_open() page, to > prevent people making the same thinko as me: > > The following code sequence can be used to obtain a file descrip‐ > tor for the child of fork(2): > > pid = fork(); > if (pid > 0) { /* If parent */ > pidfd = pidfd_open(pid, 0); > ... > } > > Even if the child process has already terminated by the time of > the pidfd_open() call, the returned file descriptor is guaranteed > to refer to the child because the parent has not yet waited on the > child (and therefore, the child's ID has not been recycled). I'd prefer that sample code be robust in all cases.