Search code examples
cfgetsalarmsigaction

Why does alarm() cause fgets() to stop waiting?


I am playing around with signals in C. My main function basically asks for some input using fgets(name, 30, stdin), and then sits there and waits. I set an alarm with alarm(3), and I reassigned SIGALRM to call a function myalarm that simply calls system("say PAY ATTENTION"). But after the alarm goes off, fgets() stops waiting for input and my main fn continues on. This happens even if I change myalarm to just set some variable and do nothing with it.

void myalarm(int sig) {
    //system("say PAY ATTENTION");
    int x = 0;
}

int catch_signal(int sig, void (*handler)(int)) { // when a signal comes in, "catch" it and "handle it" in the way you want
    struct sigaction action;  // create a new sigaction
    action.sa_handler = handler;  // set it's sa_handler attribute to the function specified in the header
    sigemptyset(&action.sa_mask);  // "turn all the signals in the sa_mask off?" "set the sa_mask to contian no signals, i.e. nothing is masked?"
    action.sa_flags = 0; // not sure, looks like we aren't using any of the available flags, whatever they may be

    return sigaction(sig, &action, NULL);  // here is where you actually reassign- now when sig is received, it'll do what action tells it
}

int main() {

    if(catch_signal(SIGINT, diediedie)== -1) {
        fprintf(stderr, "Can't map the SIGINT handler");
        exit(2);
    }

    if(catch_signal(SIGALRM, myalarm) == -1) {
        fprintf(stderr, "Can't map the SIGALAM handler\n");
        exit(2);
    }

    alarm(3);

    char name[30];
    printf("Enter your name: ");
    fgets(name, 30, stdin);

    printf("Hello, %s\n", name);

    return 0;

}

Why does alarm() make fgets() stop waiting for input?

Edit: Added code for my catch_signal function, and, as per one of the comments, used sigaction instead of signal, but the issue persisted.


Solution

  • The answer is most likely going to be OS/system specific.

    (As stated by Retr0spectrum) The fgets() function often makes system calls, such as read(). System calls can terminate if a signal is detected. In the case of this question, the fgets() function has made a system call (likely the read() system call) to read a character from stdin. The SIGALRM causes the system call to terminate, and set errno to EINTR. This also causes the fgets() function to terminate, without reading any characters.

    This is not unusual. It's just how the OS implements signals.

    To avoid this problem, I will often wrap fgets() function in a loop like this:

    do {
       errno=0;
       fgets(name, 30, stdin);
       } while(EINTR == errno);
    

    It will require that you: #include <stdio.h>

    (As suggested by TonyB).