Search code examples
clinuxsignalsfgets

How to stop reading from keyboard once a signal is handled?


I'm writing a program where the SIGINT signal is handled the first time it is sent, but set to default after that. So, for example, I have this:

static volatile int stop_terminating = 1;

void handler(int dummy) {
    stop_terminating = 0;
}

int main(){
    signal(SIGINT, handler);
    char input[256];
    while(1){
        if(stop_terminating == 0){
            // reset the action of the signal to default
            signal(SIGINT, SIG_DFL);
            printf("Message sent.\n");
            // increment counter so it doesn't enter this condition again
            stop_terminating++;
        }
        printf("User input:\n");
        fgets(input, sizeof(input), stdin);
        // In this stage, I wanna press CTRL+C and print a message, stopping the fgets
        // but what happens is: I press CTRL+C, the signal is catched, but fgets
        // is still asking for an input, and after I send something, the my message is printed
        // because it looped through the while(1) again.
    }
}

How can I stop fgets from asking for an input and just print the message and then ask again for an input?


Solution

  • The Linux manual page for signals says that

    Interruption of system calls and library functions by signal handlers

    If a signal handler is invoked while a system call or library function call is blocked, then either:

    • the call is automatically restarted after the signal handler returns; or

    • the call fails with the error EINTR.

    Which of these two behaviors occurs depends on the interface and whether or not the signal handler was established using the SA_RESTART flag (see sigaction(2)).

    You may use either the siginterrupt() function together with signal(), or use sigaction() instead of signal() for registering your signal handler, in order to disable restarting a read() system call after a signal.

    Note however that fgets() from the C library might call read() multiple times until a newline character is found, therefore you may also need to switch to using the lower-level functions instead of stdio.h APIs.