Given this code:
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
void sigint_handler(int h)
{
printf("Hey! I caught a SIGINT! :)\n");
}
int main()
{
struct sigaction act;
act.sa_handler = &sigint_handler;
if (0 != sigaction(SIGINT, &act, NULL)) {
perror("unable to setup the SIGINT handler!\n");
return 1;
}
while(1) { }
return 0;
}
compiled with gcc 7.2.0 (kernel 4.13.12) using the following options: -Wall -pedantic -ansi -std=gnu11.
The first signal is always caught, but sometimes, the second one is not caught, and sometimes it is.
I encountered this bug while spamming Ctrl-C at process' startup.
What did I miss to catch all signals?
As Martin James observed in a comment:
Your SIGINT handler has only one line - a call to a function that is not async-signal safe:(
Somewhat later, I observed:
You've no idea what the other fields in the struct sigaction are set to because you didn't initialize act. Maybe you will get better behaviour if you set the documented fields to known values. You can use write() in a POSIX signal handler (not in standard C, but fortunately you're not using standard C). You shouldn't use printf(), though in this context it is unlikely to cause any trouble. One minor advantage of write() — there's no application level buffering to worry about.
The question How to avoid using printf() in a signal handler discusses which functions can be used in a signal handler. Note that the functions from the <string.h> header such as strlen() and strchr() are not listed amongst those that are async-signal safe. I find that omission puzzling, but that's what POSIX (2008 and earlier) says. (This was accurate for POSIX 2008. One of the changes in POSIX 2016 is that a number of signal-safe routines have been added to the list in Signal Concepts, including both strlen() and strchr() — this makes a lot of sense to me.)
I adapted your code like this:
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
static void sigint_handler(int h)
{
char message[] = "Hey! I caught a SIGINT x! :\n";
char *x = message;
while (*x != 'x' && *x != '\0')
x++;
if (*x != '\0')
*x = (h % 10) + '0';
write(1, message, sizeof(message) - 1);
}
int main(void)
{
struct sigaction act = { 0 };
act.sa_handler = &sigint_handler;
if (0 != sigaction(SIGINT, &act, NULL))
{
perror("Unable to setup the SIGINT handler!\n");
return 1;
}
while (1)
{
printf("Pausing for a moment...\n");
pause();
printf("You interrupted my dozing\n");
}
return 0;
}
The code uses pause() rather than spinning in a busy-loop. It's an unusual system call; it never returns normally (the exec*() family of functions never return normally either).
I compile with stringent warning options:
$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes \
> -Wstrict-prototypes sig13.c -o sig13
$
If I didn't use h (the argument to the signal handler), the code wouldn't compile, so I used it. The code avoids using string handling functions (char *x = strchr(message, 'x'); if (x != 0) *x = (h % 10) + '0'; would be clearer). The function is static because it won't be used outside this file — so there isn't a header to declare it.
When executed (on a Mac running macOS High Sierra 10.13.2, using GCC 7.2.0), it produces output like:
$ ./sig13
Pausing for a moment...
^CHey! I caught a SIGINT 2! :
You interrupted my dozing
Pausing for a moment...
^CHey! I caught a SIGINT 2! :
You interrupted my dozing
Pausing for a moment...
^CHey! I caught a SIGINT 2! :
You interrupted my dozing
Pausing for a moment...
^CHey! I caught a SIGINT 2! :
You interrupted my dozing
Pausing for a moment...
^CHey! I caught a SIGINT 2! :
You interrupted my dozing
Pausing for a moment...
^\Quit: 3
$
The main moral to this is "make sure your variables are properly initialized". A secondary moral is to make sure your signal handler is clean.
I had two problems with my code, first of all, as mentionned by #MartinJames and #j31d0, the printf function is not async-signal-safe, so it can't be used inside the signal handler. It can be easily replaced by the write system-call which is async-signal-safe:
char message[255] = "Hey! I caught a SIGINT :)\n";
write(1, message, 255);
Secondly, the variable act was not properly initialized (as mentionned by #JonathanLeffler):
sigset_t mask;
struct sigaction act;
sigemptyset(&mask);
act.sa_handler = &sigint_handler;
act.sa_mask = mask;
act.sa_flags = 0;
Finally, a working code would then be the following:
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
void sigint_handler(int h)
{
char message[255] = "Hey! I caught a SIGINT :)\n";
write(1, message, 255);
}
int main()
{
sigset_t mask;
struct sigaction act;
sigemptyset(&mask);
act.sa_handler = &sigint_handler;
act.sa_mask = mask;
act.sa_flags = 0;
if (0 != sigaction(SIGINT, &act, NULL)) {
perror("unable to setup the SIGINT handler!\n");
return 1;
}
while(1) { }
return 0;
}
Hope this helps!
Related
I have just written the below routine to handle the EINTR error.
The routine is given below,
while((s = sem_wait(&w4compl)) == -1)
{
if (errno == EINTR)
{
perror("call interrupted by sig. handler\n");
continue;
}
else
printf("Other Error Generated\n");
}
SO, here i am not able to see the print "call interrupted by sig. handler\n" statement. How can test this so that it will print the same(How can i execute the part of if (errno == EINTR)).
Install a signal handler, and cause a signal to be delivered (using alarm(), setitimer(), or timer_create()+timer_settime()), so that the delivery of the signal will interrupt the sem_wait() call.
Consider this example program:
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <semaphore.h>
#include <stdio.h>
#include <errno.h>
static void dummy_handler(int signum)
{
}
static int install_dummy_handler(int signum)
{
struct sigaction act;
memset(&act, 0, sizeof act);
sigemptyset(&act.sa_mask);
act.sa_handler = dummy_handler;
act.sa_flags = 0;
return sigaction(signum, &act, NULL);
}
static const char *errname(const int errnum)
{
switch (errnum) {
case EINTR: return "EINTR";
case EINVAL: return "EINVAL";
default: return "(other)";
}
}
int main(void)
{
sem_t s;
if (install_dummy_handler(SIGALRM) == -1) {
fprintf(stderr, "Cannot install ARLM signal handler: %s.\n", strerror(errno));
return EXIT_FAILURE;
}
sem_init(&s, 0, 0);
alarm(1);
if (sem_wait(&s) == -1) {
const int errnum = errno;
printf("sem_wait() failed with errno == %s (%d; %s).\n",
errname(errnum), errnum, strerror(errnum));
} else
printf("sem_wait() succeeded.\n");
return EXIT_SUCCESS;
}
In main(), we install a signal handler for the SIGALRM signal. It does not matter if the signal handler function does anything at all, because it is the delivery of the signal that causes "slow" syscalls to return with EINTR error. (As long as the SA_RESTART flag was not used when that handler was installed. If you look at act.sa_mask in install_dummy_handler(), you'll see we used no flags at all. All the flags and sigaction() usage are described in the man 2 sigaction man page.)
In main(), we first initialize our semaphore, then set an alarm for one second. When the real, wall-clock time has elapsed, the SIGALRM signal is raised.
Do note that although SIGALRM is just fine for this example and similar purposes, you'll probably want to use POSIX per-process interval timers instead.
Next, we simply call sem_wait() on the semaphore, and examine the result. In practice, if you compile and run the above example.c using e.g.
gcc -Wall -O2 example.c -lpthread -o example
./example
the program will output
sem_wait() failed with errno == EINTR (4; Interrupted system call).
after one second.
Just about any system call on Linux can return EINTR if the system call is interrupted.
From the man page (emphasis mine):
sem_wait() decrements (locks) the semaphore pointed to by sem. If
the semaphore's value is greater than zero, then the decrement
proceeds, and the function returns, immediately. If the semaphore
currently has the value zero, then the call blocks until either it
becomes possible to perform the decrement (i.e., the semaphore value
rises above zero), or a signal handler interrupts the call.
To trigger this case, you should make sure that the sem_wait system call is blocked (waiting), and then send a signal (which has a handler) to the thread.
Some psuedo-code:
sigint_handler:
return
thread2:
<Your while loop from the question>
main:
signal(SIGINT, sigint_handler) // Setup signal handler
sem_wait(&w4compl)
t2 = start_thread(thread2)
sleep(5) // Hack to make sure thread2 is blocked
pthread_kill(t2, SIGINT)
Tried my best to figure this out on my own, but I really do not want to continue tampering with things that I do not fully understand. So for a programming assignment I have to do in C, I need to terminate a program upon the user entering CTRL+D key stroke via a terminal. I tried to isolate that functionality in a smaller test function, but now my CTRL+D behaves as my CTRL+C and CTRL+C does not have any effect, even outside of the program when it finishes executing. This is the program that caused this change:
#include <unistd.h>
#include <stdio.h>
#include <termios.h>
#include <signal.h>
#include <stdlib.h>
void ctrlD(int sig){
printf("\n");
signal(SIGINT, SIG_DFL);
exit(0);
}
int main(){
signal(SIGINT, ctrlD);
while(1) {
printf("Hello\n");
sleep(5);
}
}
The line signal(SIGINT, SIG_DFL); was added afterward upon realizing my CTRL+C no longer worked. I thought it would return the keystrokes to their original functionalities, but to no avail. What do I do to get back the original functionalities while also making this program work with CTRL+D?
***EDIT: This question seems to have gone off the rails a bit. I get now that Ctrl+D is not a signal. Nonetheless, I no longer have the functionality of Ctrl+C anymore when attempting to use it in my MAC OS terminal, and instead Ctrl+D seems to have that exact functionality. HOW exactly can I return each to have the functionality that they had before I went on this haphazard journey?
If your intention is to restore signal's default behavior after executing handler then, pass SA_RESETHAND flag to sa_flags while registering signal action. For example.
struct sigaction act;
memset(&act, 0, sizeof(struct sigaction));
act.sa_flags = SA_RESETHAND;
act.sa_handler = some_handler;
sigaction(SIGINT, &act, NULL);
From sigaction() man
SA_RESETHAND
Restore the signal action to the default upon entry to the signal handler. This flag is meaningful only when
establishing a signal handler.
If you write a program to explore signals, it is much better to write it carefully, using proper POSIX interfaces (sigaction() instead of signal()), and avoiding undefined behaviour (using non-async-signal safe functions in a signal handler).
Consider, for example, the following program:
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <stdio.h>
#include <time.h>
#include <errno.h>
static volatile sig_atomic_t sigint_count = 0;
static void catch_sigint(int signum)
{
if (signum == SIGINT)
sigint_count++;
}
static int install_sigint(void)
{
struct sigaction act;
memset(&act, 0, sizeof act);
sigemptyset(&act.sa_mask);
act.sa_handler = catch_sigint;
act.sa_flags = 0;
if (sigaction(SIGINT, &act, NULL) == -1)
return errno;
return 0;
}
static int install_default(const int signum)
{
struct sigaction act;
memset(&act, 0, sizeof act);
sigemptyset(&act.sa_mask);
act.sa_handler = SIG_DFL;
act.sa_flags = 0;
if (sigaction(signum, &act, NULL) == -1)
return errno;
return 0;
}
int main(void)
{
struct timespec duration;
int result;
if (install_sigint()) {
fprintf(stderr, "Cannot install SIGINT handler: %s.\n", strerror(errno));
return EXIT_FAILURE;
}
duration.tv_sec = 5;
duration.tv_nsec = 0; /* 1/1000000000ths of a second. Nine zeroes. */
printf("Sleeping for %d seconds.\n", (int)duration.tv_sec);
fflush(stdout);
while (1) {
result = nanosleep(&duration, &duration);
if (!result)
break;
if (errno != EINTR) {
fprintf(stderr, "nanosleep() failed: %s.\n", strerror(errno));
return EXIT_FAILURE;
}
/* nanosleep was interrupted by a delivery of a signal. */
if (sigint_count >= 3) {
/* Ctrl+C pressed three or more times. */
if (install_default(SIGINT) == -1) {
fprintf(stderr, "Cannot revert SIGINT to the default handler: %s.\n", strerror(errno));
return EXIT_FAILURE;
}
printf("SIGINT has been reverted to the default handler.\n");
fflush(stderr);
}
}
if (sigint_count > 0)
printf("You pressed Ctrl+C %d time%s.\n", (int)sigint_count, (sigint_count > 1) ? "s" : "");
else
printf("You did not press Ctrl+C at all.\n");
return EXIT_SUCCESS;
}
The #define tells your C library (glibc in particular) that you want POSIX.1-2008 (and later) features from it.
The INT signal handler only increments a volatile sig_atomic_t counter. Note that this type may have a very small range it can represent; 0 to 127, inclusive, should be safe.
The main program waits using the POSIX nanosleep() function. On some systems, sleep() may be implemented via the SIGALRM function, so it is better avoided when using signals otherwise; nanosleep() does not interfere with signals like that at all. Plus, nanosleep() can return the amount of time remaining, if it is interrupted by a signal delivery.
In the main loop, nanosleep() will return 0, if it has slept the entire interval (but note that it may not update the remaining time to 0 in this case). If it is interrupted by the delivery of a signal, it will return -1 with errno == EINTR, and the remaining time updated. (The first pointer is to the duration of the sleep, and the second is to where the remaining time should be stored. You can use the same structure for both.)
Normally, the main loop does only one iteration. It can do more than one iteration, if it is interrupted by the delivery of a signal.
When the main loop detects that sigint_count is at least three, i.e. it has received at least three INT signals, it resets the signal handler back to default.
(Note that both the memset() and the sigemptyset() are important when clearing the struct sigaction structure. The memset() ensures that future code is backwards compatible with older code, by ensuring even padding fields are cleared. And sigemptyset() is the safe way to clear the signal mask (set of signals blocked while the handler runs).)
(In theory, memset() is not async-signal-safe, while both sigemptyset() and sigaction() are. This is why I reset the signal handler in the main program, and not in the signal handler.)
If you want to print from a signal handler, you need to use low-level I/O, because <stdio.h> functions are not async-signal safe. For example, you can use the following function to print strings to standard output:
static int wrerr(const char *p)
{
const int saved_errno = errno;
int retval = 0;
if (p) {
const char *q = p;
ssize_t n;
while (*q)
q++;
while (p < q) {
n = write(STDERR_FILENO, p, (size_t)(q - p));
if (n > 0)
p += n;
else
if (n != -1) {
retval = EIO;
break;
} else
if (errno != EINTR) {
retval = errno;
break;
}
}
}
errno = saved_errno;
return retval;
}
The above wrerr() function is async-signal safe (because it only uses async-signal safe functions itself), and it even keeps errno unchanged. (Many guides forget to mention that it is quite important for a signal handler to keep errno unchanged. Otherwise, when a function is interrupted by a signal handler, and that signal handler modifies errno, the original function will return -1 to indicate an error, but then errno is no longer EINTR!)
You can just use wrerr("INT signal!\n") if you want. The return value from wrerr() is zero if the write was successful, and an errno error code otherwise. It ignores interrupts itself.
Do note that you should not mix stderr output via fprintf() or other <stdio.h> functions with the above (except perhaps for printing error messages when the program aborts). Mixing them is not undefined behaviour, it just may yield surprising results, like wrerr() output appearing in the midst of a fprintf(stderr,...) output.
Its because of exit(0) statement in the handler, when SIGINT is raised, handler strlD gets called and you might thinking why signal(SIGINT,SIG_DFL) didn't work ? Actually it works. But your main process a.out get terminated successfully there itself by calling exit(0). remove exit(0) if you want to restore the behavior of SIGINT.
#include <unistd.h>
#include <stdio.h>
#include <termios.h>
#include <signal.h>
#include <stdlib.h>
void ctrlD(int sig){
//printf("CTRL+C pressed\n");/* just to observe I added one printf
statement, Ideally there shouldn't be any printf here */
signal(SIGINT, SIG_DFL);/*restoring back to original action */
}
int main(){
signal(SIGINT, ctrlD);/*1st time when CTRL+C pressed, handler ctrlD gets called */
while(1) {
printf("Hello\n");
sleep(5);
}
return 0;
}
Also its advisable to use sigaction() instead of signal() as told here What is the difference between sigaction and signal? . Read man 2 sigaction and man 2 exit to check what exit(0) means.
Also this How to avoid using printf in a signal handler?
Edit :
void ctrlD(int sig){
/* printf("CTRL+C pressed \n"); */
signal(SIGINT, SIG_DFL); /* only one time CTRL+C works
after that SIG_DFL will terminate whole process */
}
int main(){
signal(SIGINT, ctrlD); /* if you press CTRL+C then it will go to handler
and terminate */
int ch;
while( ((ch = getchar())!=EOF) ) { /* wait or read char until CTrl+D is not pressed */
printf("Hello : %d \n",ch);/* ASCII equivalent of char */
}
return 0;
}
Thank you everyone who contributed to this question. The resources provided/linked were tremendously helpful in learning more about signals (and that EOF isn't a signal), among the other wealth of information provided.
After some more research, I found out that somehow, either through some accidental bash command gone awry, or perhaps the program posted in my original question itself, I had altered the key mappings for my terminal's stty settings. If anyone finds themselves in this oddly specific situation in the future, I hope this can be of help, as it is what fixed my problem:
Enter the command $ stty -a to see all of your terminals settings, specifically the "cchars" section.
I then saw the reversal, and fixed it like so:
$ stty intr ^C
$ stty eof ^D
Then you can run $ stty -a once again to see that the changes have properly taken effect. Once again, thanks everyone.
static void AlarmHandler(int sig) ;
int i=0;
jmp_buf mark;
int main(int argc, char * argv[]){
setjmp(mark);
signal(SIGALRM, AlarmHandler);
alarm(2);
while(1);
return 0;
}
static void AlarmHandler(int sig) {
signal(SIGALRM, SIG_IGN);
printf("I am in AlarmHandler: %d \n",i);
i++;
longjmp(mark, 0);
}
When I run this code the program goes through the AlarmHandler only once and then it just stays trapped inside the while loop. Can someone explain why?
Your program might work as you expected on some POSIXy operating systems -- in fact, it does work as you expected on the computer I'm typing this on. However, it relies on a bunch of unspecified behavior relating to signals, and I think you've tripped over one of them: I think that on your computer, a signal is "blocked" — it can't be delivered again — while its handler is executing, and also, jumping out of the handler with longjmp does not unblock the signal. So you go around the loop once and then the second SIGALRM is never delivered because it's blocked. There are several other, related problems.
You can nail down all of the unspecified behavior and make the program reliable on all POSIXy operating systems, but you have to use different functions to set things up: sigsetjmp and sigaction. You should also get rid of the busy-waiting by using sigsuspend instead. A corrected program would look something like this:
#define _XOPEN_SOURCE 700
#include <signal.h>
#include <setjmp.h>
#include <stdio.h>
#include <unistd.h>
static jmp_buf mark;
static void
handle_SIGALRM(int sig)
{
static int signal_count;
signal_count++;
printf("SIGALRM #%u\n", signal_count);
siglongjmp(mark, signal_count);
}
int
main(void)
{
sigset_t mask, omask;
sigemptyset(&mask);
sigaddset(&mask, SIGALRM);
if (sigprocmask(SIG_BLOCK, &mask, &omask)) {
perror("sigprocmask");
return 1;
}
struct sigaction sa;
sigfillset(&sa.sa_mask);
sa.sa_flags = 0; // DO interrupt blocking system calls
sa.sa_handler = handle_SIGALRM;
if (sigaction(SIGALRM, &sa, 0)) {
perror("sigaction");
return 1;
}
if (sigsetjmp(mark, 1) >= 4)
return 0;
alarm(1);
sigsuspend(&omask);
perror("shouldn't ever get here");
return 1;
}
I should probably say a few words about signal safety: In this program, it is safe to call printf and siglongjmp from the signal handler, because I have arranged for the SIGALRM only to be deliverable while the main thread of execution is blocked on sigsuspend. (That's what the call to sigprocmask up top does.) If you had anything to do in your main thread of execution besides sleep waiting for the signal to arrive, you would have to be much more careful about what you did in the signal handler, and I would advocate for using pselect and/or the self-pipe trick instead of jumping out of the handler, if at all possible.
I have a server application which I want to protect from being stopped by any signal which I can ignore. Is there a way to ignore all possible signals at once, without setting them one by one?
Yes:
#include <signal.h>
sigset_t mask;
sigfillset(&mask);
sigprocmask(SIG_SETMASK, &mask, NULL);
This does not exactly ignore the signals, but blocks them; which in practice is the same effect.
I guess there's no need to mention that SIGKILL and SIGSTOP cannot be blocked nor ignored in any way.
For more detailed semantics, like mask inheritance rules and the like, check the man page
Blocking signals is NOT the same as ignoring them.
When you block signals as suggested by C2H5OH, it gets added to a pending signal queue and will be delivered to the process as soon as you unblock it.
Unblocking can be done using
#include <signal.h>
sigset_t mask;
sigemptyset(&mask);
sigprocmask(SIG_SETMASK, &mask, NULL);
To answer your question on how to ignore signals, it has to be handled by a Signal Handler which is a user-defined function which executes whenever a signal is delivered to the process
static void foo (int bar)
{
/*some code here. In your case, nothing*/
}
then register this function by using
signal(SIGINT,foo); //or whatever signal you want to ignore
If you want to ignore all signals
int i;
for(i = 1; i <=31 ; i++)
{
signal(i,foo);
}
This code will take all the signals delivered to the process and ignore them instead of blocking them.
NOTE:
According to man pages , it is not the recommended way, instead sigaction is suggested. Do check out man sigaction
Solutions based on sigprocmask() and pthread_sigmask() have not worked for me.
Here's what I found to work:
#include <signal.h>
#include <unistd.h>
#include <assert.h>
int main() {
struct sigaction act;
act.sa_handler = SIG_IGN;
for(int i = 1 ; i < 65 ; i++) {
printf("i = %d\n", i);
// 9 and 19 cannot be caught or ignored
// 32 and 33 do not exist
if((i != SIGKILL) && (i != SIGSTOP) && (i != 32) && (i != 33)) {
assert(sigaction(i, &act, NULL) == 0);
}
}
sleep(10000);
return 0;
}
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.
The Ctrl-C character is eaten by the getchar() call, and the sigHandler function is never executed.
Ctrl-C is not eaten by getchar; it results in a signal being delivered and sigHandler being run. This sets done and returns. Only then is getchar called, which eats the newline and after that, done is checked so the program exits.
Btw., a signal handler takes an int argument, not void.