0

When the following C program is executed, and SIGUSR1 is sent to the running process repeatedly, the pclose() call will sometimes return 13. 13 corresponds to SIGPIPE on my system.

Why does this happen?

I am using while true; do kill -SIGUSR1 <process-id>; done to send SIGUSR1 to the program. The program is executed on Ubuntu 14.04.

#include <pthread.h>
#include <signal.h>
#include <unistd.h>
#include <stdio.h>

void handler(int i) {}

void* task(void*)
{
    FILE *s;
    char b [BUFSIZ];
    while (1) {
        if ((s = popen("echo hello", "r")) == NULL) {
            printf("popen() failed\n");
        }
        while (fgets(b, BUFSIZ, s) != NULL) ;
        if (int r = pclose(s)) {
            printf("pclose() failed (%d)\n", r);
        }
    }

    return 0;
}

int main(int argc, char **argv)
{
    struct sigaction action;
    action.sa_handler = handler;
    sigemptyset(&action.sa_mask);
    action.sa_flags = 0;
    sigaction(SIGUSR1, &action, NULL);

    pthread_t tid;
    pthread_create(&tid, 0, task, NULL);
    pthread_join(tid, NULL);
}
Josh Johnson
  • 8,832
  • 4
  • 25
  • 31

1 Answers1

2

This happens when fgets gets interrupted by the signal. The program doesn't read the pipe to the end and closes it. The other program then SIGPIPEs.

The correct pipe reading operation is:

 do {
    while (fgets(b, BUFSIZ, s) != NULL) ;
 } while (errno == EINTR);
n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
  • Thanks. I should have read the `fgets()` documentation closer: "Upon successful completion, fgets() shall return s. If the stream is at end-of-file, the end-of-file indicator for the stream shall be set and fgets() shall return a null pointer. **If a read error occurs, the error indicator for the stream shall be set, fgets() shall return a null pointer, and shall set errno to indicate the error.**" – Josh Johnson Apr 26 '14 at 15:36