You should use select()
to check if data is available before reading from stdin:
void handler (int arg) {
// handle signal
}
int main (void) {
char buf[100];
signal(SIGINT, handler);
do {
fd_set f;
FD_ZERO(&f);
FD_SET(fileno(stdin), &f);
int st = select(fileno(stdin)+1, &f, NULL, NULL, NULL);
if (st == 1) {
fgets(buf, sizeof(buf), stdin);
// Handle input
}
} while (st >= 0);
exit(EXIT_SUCCESS);
}
select()
will return with -1
(errno EINTR) after returning from the signal handler whereas the read()
(invoked by (f)gets) would be automatically resumed.
With linux, there is another possibility using sigaction()
:
void handler (int arg) {
// handle signal
}
int main (void) {
char buf[100], *p;
struct sigaction sa = { .sa_handler = handler, .sa_flags = 0, .sa_mask = 0 };
sigaction(SIGINT, &sa, NULL);
do {
p = fgets(buf, sizeof(buf), stdin);
// handle input
} while (p);
printf("Byebye\n");
exit(EXIT_SUCCESS);
}
Since the flag SA_RESTART
is not specified in the sa_flags
for the signal handler, a read()
on a slow device (i.e. terminals, pipes, sockets) will return with -1 (EINTR)
, too (see also signal(7)).
While being a bit simpler, the behaviour may vary between the different unix-flavors (and even kernel-versions), so the first version is a safer and more portable/reliable way.