I've been searching for a solution to my problem for a long time now that's why i'm 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 user inputs q then enter. If CTRL+C is pressed, it is caught by the sigHandler function which sets the flag 'done' to 1 and exits the program.
Observed behavior: The CTRL+C character is eaten by the getchar() call, and the sigHandler function is never executed. When CTRL+C and then enter is pressed, the sigHandler function is called and the program exits.
Could someone with more experience and knowledge help me on that one?
Thanks for your input :)
There IS a way to abort the call without resorting to ugly hacks (contrarily to what Paul R said). You should use sigaction()
with sa_flags
set to 0
instead of signal()
.
Besides, the signal(2) manual says:
Avoid its use: 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;
}
Normally, after catching and handling a signal, most (I'm not sure if not all) syscalls will be restarted. This way, after handling the sigint signal, your getchar function will continue as if nothing happened.
You can change this behavior by calling sigaction with sa_flags=0
.
This way, after handling SIGINT, getchar
will return -1
and errno will be set to "Interrupted system call" (I don't remember the constant name right now).
You would also have to rewrite your user_input() function to handle the case when returning -1.
The code is actually working as expected - you are not testing the done
flag until after you return from user_input()
, which is why you need to enter an additional character after the control-C.
If you want to abort the call to getchar
when you get a control-C then you'll probably have to do something ugly, e.g. use setjmp
/longjmp
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With