hanfeisun hanfeisun - 5 months ago 44
Linux Question

Is waitpid() an atomic operation in Linux?

For example, in the parent process, I forked a child process and wait on the child process:

int main() {
setSignal(SIGCHLD, sigchld_handler)
while(1) {
// fork some child processes
myForkFunction()

waitpid(-1, &status, 0)
}
}


Moreover, I have a SIGCHLD signal handler:

void
sigchld_handler(int sig) {
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
// Reap zombie processes
}
}


As can be seen,
waitpid()
appears both in the
main()
function and in the
sigchld_handler()
function. I was wondering whether
waitpid
can be interrupted by
SIGCHLD
. If it can be interrupted by
SIGCHLD
, what will happen then?

Does anyone have any ideas about this?

Answer

The POSIX specification for waitpid() says in part:

If _POSIX_REALTIME_SIGNALS is defined, and the implementation queues the SIGCHLD signal, then if wait() or waitpid() returns because the status of a child process is available, any pending SIGCHLD signal associated with the process ID of the child process shall be discarded. Any other pending SIGCHLD signals shall remain pending.

Otherwise, if SIGCHLD is blocked, if wait() or waitpid() return because the status of a child process is available, any pending SIGCHLD signal shall be cleared unless the status of another child process is available.

For all other conditions, it is unspecified whether child status will be available when a SIGCHLD signal is delivered.

The third of the quoted paragraphs seems to imply that you're treading on thin ice. It doesn't mention 'implementation defined' or similar — unspecified means that the standard says nothing about what shall happen and you may or may not get any information from the implementation-specific documentation.

There is a lot of (very densely worded) information in the POSIX specification. There are also some examples, and a rationale — which mentions sigwait() and sigwaitinfo(). It is worth reading the whole of the waipid() page. You should probably also read about Signal concepts too — more dense reading. (One of these days, I'll do it, too — when I need to know about bits of signals that I haven't covered before.)


Why are you using WUNTRACED instead of 0 or WNOHANG? WUNTRACED is a very specialized condition — POSIX says:

WUNTRACED
The status of any child processes specified by pid that are stopped, and whose status has not yet been reported since they stopped, shall also be reported to the requesting process.

Similar comments apply to WCONTINUED. Those two flags are useful when you need them, but you very seldom need them.

I suggest you should normally use either 0 or WNOHANG in the third argument to waitpid().