Skip to content

pidwait waits for only half of the given processes

Apparently pidwait waits for only half of the given processes.

bash example to reproduce:

$ for i in {2,4}; do sleep $i & done; time pidwait -u $LOGNAME sleep
[1] 8630
[2] 8631
[1]-  Done                    sleep $i

real	0m2.005s
user	0m0.012s
sys	0m0.015s

You see that pidwait takes only 2 seconds but it should take 4 seconds if it waited for the sleep 4 command.

strace shows why this is:

pidfd_open(8659, 0)                     = 4
epoll_ctl(3, EPOLL_CTL_ADD, 4, {events=EPOLLIN|EPOLLET, data=0x4}) = 0
pidfd_open(8660, 0)                     = 5
epoll_ctl(3, EPOLL_CTL_ADD, 5, {events=EPOLLIN|EPOLLET, data=0x5}) = 0
epoll_wait(3, [{events=EPOLLIN, data=0x4}], 32, -1) = 1
epoll_wait(3, [{events=EPOLLIN|EPOLLHUP, data=0x4}], 32, -1) = 1

It seems that for each finished process there are 2 epoll events: one EPOLLIN and one EPOLLIN|EPOLLHUP. I suppose that EPOLLIN occurs when the process has exited and EPOLLIN|EPOLLHUP occurs when the process has been collected by wait or waitpid.

Since the pidwait code merely counts the epoll events that have EPOLLIN set it counts every terminated process twice so that it only waits for half of the given processes.

BTW, the pidwait manpage doesn't clearly specify if it waits for processes until they have exited or until they have been collected (it might be worth having a commandline option to distinguish between the two).

$ ps --info
BSD j    OL_j
BSD l    OL_l
BSD s    OL_s
BSD u    OL_u
BSD v    OL_v
SysV -f  (none)
SysV -fl (none)
SysV -j  (none)
SysV -l  (none)

procps-ng version 4.0.4
Compiled with: glibc 2.40, gcc 15.0

header_gap=-1 lines_to_next_header=1
screen_cols=129 screen_rows=48

personality=0x00000000 (from "unknown")
EUID=1000 TTY=136,7 page_size=4096
sizeof(proc_t)=8 sizeof(long)=8 sizeof(long)=8
archdefs: x86_64