For further fine tuning and control, there is the waitid(2) system call as well (from Linux 2.6.9):
int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);
The first two parameters will in effect specify the children to wait upon:
waitid(2): 1st parameter: idtype | Second parameter: id |
P_PID | Set to the PID of the child to wait (block) upon |
P_PGID | Wait upon any child whose process group ID (PGID) matches this number |
P_ALL | Wait upon any child (this parameter is ignored) |
The fourth options parameter is similar to how it was used with the waitpid(2), but not identical; there are some additional options that can be passed along; again, it's a bitmask, not an absolute value: the WNOHANG and WCONTINUED options have the same meaning as with the waitpid(2) system call.
Additionally, the following options can be bitwise-ORed:
- WEXITED: Block upon children that have (already) terminated (again, we shall soon make clear why this even exists)
- WSTOPPED: Block upon children that will enter the stopped state (similar to the WUNTRACED option)
- WNOWAIT: Block upon children, but once unblocked, leave them in a waitable state so that they can be waited-upon again with a later wait* API.
The third parameter is a (large) data structure of type siginfo_t; (we shall cover details in Chapter 11, Signaling - Part I). On return of waitid(2), this will get populated by the kernel. Various fields get set by the OS, among them, the PID of the child that changed state (si_pid), si_signo set to SIGCHLD, si_status, si_code. We intend to cover these in a later chapter (for now, please refer to the man page).