0

I ran into this problem a few hours ago.

Even though I have fixed it, I simply don't understand why this happens.

signal(SIGHUP, sighupHandler);
.
.
.
// sync with child by getting a char written by child
fgetc(pipe_in);
close(pipe_in);
int status;
if(waitpid(initProcessPid, &status, 0) == -1){
    printf("debug: errno is %d\n", errno);
    printf("failed to wait for init process to end\n");
}

Every time a SIGHUP happens during the waitpid() block, waitpid() returns -1 with errno 5.

Although a EINTR should be in errno this case as pointed out by alk, EINTR is 4, not 5.

After a few hours gathering ideas from gdb, since I'm not actually doing anything on SIGHUP currently, I changed my code to:

signal(SIGHUP, SIG_IGN);

Then it works properly, SIGHUP no longer breaks the waitpid() block.

I was working on a linux container that aims to be single file and static. https://github.com/Kethen/minicontainer

Katharine
  • 1
  • 1
  • 1
    https://stackoverflow.com/q/41474299/2371524 –  Aug 14 '17 at 07:15
  • From [`waitpid()`'s POSIX docs](http://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html) (The Linux man page in essence states the same): "***ERRORS** The waitpid() function shall fail if: [...] [EINTR] The function was interrupted by a signal. [...].*" – alk Aug 14 '17 at 07:38
  • 2
    Also, don't use `signal()`, as its semantics vary; always use [`sigaction()`](http://man7.org/linux/man-pages/man2/sigaction.2.html) instead. Also, if you include both `` and ``, you can use `strerror(errno)` to get a human-readable error string. – Nominal Animal Aug 14 '17 at 07:43
  • I see. However my compiled code told me the EINTR is 4, not 5, which confused me earlier... – Katharine Aug 14 '17 at 07:48
  • Please note that `errno` is a global resource, so either log or save it ***immediately** after* the error condition had been detected. Do not call any function which might modify `errno` before its value had either been logged or saved. Just as the code you show does. – alk Aug 14 '17 at 08:26
  • I see, I'll keep that in mind! – Katharine Aug 14 '17 at 10:58
  • ... and the code from your git-repo doesn't! – alk Aug 14 '17 at 11:28
  • Thanks for reminding me! I'll do that in a bit. Thanks everyone for the responses, too! – Katharine Aug 14 '17 at 11:45

1 Answers1

1

As per the wait()/waitpid() POSIX documentaion:

The wait() function shall cause the calling thread to become blocked until status information generated by child process termination is made available to the thread, or until delivery of a signal whose action is either to execute a signal-catching function or to terminate the process, or an error occurs.

If wait() or waitpid() returns due to the delivery of a signal to the calling process, -1 shall be returned and errno set to [EINTR].

Since you've configured SIGHUP to execute a function, it's covered by the emphasised clause above.

This is similar to many other system calls which can return EAGAIN when interrupted by a signal. One way you can handle it is with code similar to:

// Keep waiting while being interrupted.

int rc, err;
do {
    rc = waitpid (initProcessPid, &status, 0);
    err = errno;
} while ((rc == -1) && (err == EINTR));

// Any error other than interruption will be caught here.

if (rc == -1) {
    printf ("debug: errno is %d\n", err);
    printf ("failed to wait for init process to end\n");
}

You're also correct that Linux generally states this should be 4 rather than 5 but that's not always the case. Some systems use vastly different values (such as IBM iSeries, putting those common error codes up somewhere about 3400).

You should be checking against the specific name rather than a fixed value.

Community
  • 1
  • 1
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953