Search code examples
cerrno

C poll() returns ECHILD


Just encountered an undocumented error. The call to poll() returned ECHILD.

I have a very simple code, almost directly from the man:

struct pollfd fds[] = { fd, POLLIN, 0 };
while(should_continue) {
  int rc=poll(fds, 1, 1000);
  if(rc==0) {
     // exit by timeout, repeat waiting
     continue;
  } else if(rc<0) {
     printf("poll error %d\n", errno);
     exit(1);
  }
  // read from fd
}

This code suddenly exited with "poll error 10". But man 2 poll does not even mention ECHILD as possible error. What could be the cause?


Solution

  • I suspect that you have a signal handler that clobbers errno. Specifically, a SIGCHLD handler that calls wait until it returns -1.

    What happens is this:

    1. You call poll and it blocks.
    2. A child exits.
    3. poll returns error EINTR to allow your signal handler a chance to run.
    4. Your SIGCHLD handler is called.
    5. It calls wait repeatedly to reap every child waiting to be reaped.
    6. The last call to wait, having nothing left to reap, returns error ECHILD.
    7. Your SIGCHLD handler returns without restoring errno.
    8. poll appears to have returned error ECHILD when it really returned error EINTR.

    Fix:

    • Save errno when your signal handler is called, and restore it before exiting.
    • Restart poll when it returns error EINTR, or make it so it's automatically restarted after signal processing by setting up your signal handler using sigaction and passing the appropriate flags.

    Very few things return error ECHILD, so the possible explanations are very limited. As such, I'm pretty confident in my guess.


    Notes:

    • "Returns error EXXX" is used as shorthand for "returns -1 after setting errno to EXXX".