Ctrl-C eaten by getchar ()

I have been looking for a solution to my problem for a long time, why I am turning to you:

Consider this piece of code:

static char done = 0; static void sigHandler(void) { done = 1; } int user_input() { return (getchar() == 'q') ? 0 : 1; } int main(void) { signal(SIGTERM, sigHandler); signal(SIGINT, sigHandler); while (user_input() != 0 && !done) usleep(1000); printf("exiting\n"); return 0; } 

Expected behavior: The program exits when the user enters q, then enter. If the CTRL + C button is pressed, it is captured by the sigHandler function, which sets the done flag to 1 and exits the program.

Observed Behavior: The CTRL + C character is fed by the getchar () call, and the sigHandler function is never executed. When CTRL + C and then hit is entered, the sigHandler function is called and the program exits.

Can someone with more experience and knowledge help me with this?

Thanks for your input :)

+4
source share
3 answers

There is a way to interrupt a call without resorting to ugly hacks (unlike what Paul R said). You should use sigaction() with sa_flags for 0 instead of signal() .

In addition, the signal manual (2) states:

Avoid using : use sigaction (2) instead.

 #include <stdio.h> #include <signal.h> #include <string.h> #include <errno.h> static char done = 0; static void sigHandler(int signum) { done = 1; } int user_input() { return (getchar() == 'q') ? 0 : 1; } int main(void) { struct sigaction sa; memset(&sa, 0, sizeof(struct sigaction)); sa.sa_handler = sigHandler; sa.sa_flags = 0;// not SA_RESTART!; sigaction(SIGINT, &sa, NULL); sigaction(SIGTERM, &sa, NULL); while (user_input() != 0 && !done) usleep(1000); printf("exiting\n"); return 0; } 

Usually, after detecting and processing the signal, most (I'm not sure, if not all) system calls will be restarted. This way, after processing the sigint signal, your getchar function will continue as if nothing had happened. You can change this behavior by calling sigaction with sa_flags sa_flags=0 .

Thus, after processing SIGINT, getchar will return -1 , and errno will be set to "Interrupted system call" (I do not remember the name of the constant right now).

You will also have to rewrite the user_input () function to handle the case when returning -1. A.

+3
source

The code really works as expected - you don't test the done flag until you return from user_input() , so you need to enter an extra character after the -C control.

If you want to interrupt the getchar call when you receive the C control, you probably have to do something ugly, for example. use setjmp / longjmp .

+6
source

The Ctrl-C character is used by the getchar() call, and the sigHandler function is never executed.

Ctrl-C is not getchar ; this results in a signal and sigHandler . This sets done and returns. Only then getchar called, which eats a new line and after that it checks done so that the program exits.

Btw., The signal handler accepts an int argument, not a void .

+5
source

Source: https://habr.com/ru/post/1379272/


All Articles