0

My program is supposed to print a number every second from 0 to 10 and never higher than 10. I put that in my main loop with While(1) to do it forever.

I have a SIGINT handler to increment the number 1 or -1 for SIGINT and SIGTERM respectively.

I am trying to implement a second handler to capture a second SIGINT signal within one second of the first to quit the program, but my second handler (sig_handler_2) is never reached. What am I doing wrong?

Source Code:

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

int number = 0;

void sig_handler_2(int sig) {
    printf("Exiting the program now \n");
    signal(SIGINT, SIG_DFL);
}

void sig_handler_1(int sig) {
    signal(SIGINT, sig_handler_2);
    if (sig == SIGINT) {
        if (number > 9) {
        printf(" SIGINT received but number is > 9, cannot increment \n");
        }
      else {
          printf(" SIGINT received: Increment is now %d \n", number);
      }
    }
    if (sig == SIGTERM) {
      if (number <= 0) {
          printf(" SIGTERM received but number <= 0, cannot increment \n");
      }
      else {
          number --;
          printf(" SIGTERM received: Increment is now %d \n", number);
          printf("%d \n", number);
      }
    }
}

int main() {
    while (1) {
        signal(SIGINT, sig_handler_1);
        signal(SIGTERM, sig_handler_1);
        if (number > 9) {
            printf("%d \n", number);
            number = 0;
        }
        else {
            printf("%d \n", number);
            number ++;
        }
        sleep(1);
    }
}`
pilcrow
  • 56,591
  • 13
  • 94
  • 135
  • You are installing `sig_handler_1` for both signals in the loop. Is that intentional? The purpose of installing `sig_handler_2` in `sig_handler_1` (which will get reset right in main ) is also unclear... – P.P Feb 23 '20 at 22:41

1 Answers1

0

The immediate problem is that your main loop always resets the signal handler, and you are not fast enough when generating that second signal before your code resets the SIGINT disposition to handler1.

step  what
----  ----------------------------------------
  0   main/set SIGINT disposition -> handler1
  1   main/sleep(1) -> ...
  2   <SIGINT>
  3   handler1/set SIGINT disposition -> handler2  // Note: SIGINT delivery is probably
                                                   //       blocked during handler1()
  4   <return to main>
  5   main/sleep() -> EINTR
  6   main/set SIGINT disposition -> handler1      // Another SIGINT will now do the same
                                                   // as before
  7   main/sleep(1) -> ...

That's why, as you remark elsewhere, a sleep() inside the first signal handler works: it gives you enough time to generate an INT while that signal's disposition is set to handler2.

Now, there are a number of things I suggest you change about this implementation.

Pull the signal() calls out of your main loop. It's not clear that behavior makes sense in the logic of your program.

Please use sigaction() and not signal(). sigaction() is more complex, and it forces you to specify important things like: will sleep() resume after a signal (SA_RESTART)? Will your handler allow signals to interrupt itself (sa_mask, SA_NODEFER)? How much do you want to know about the generated signal (SA_SIGINFO)? Do you want a "one-shot" handler (SA_RESETHAND)?

Any use of signal() must answer all these questions implicitly, and the unfortunate historical reality is that different platforms had different answers for these questions. Use sigaction().

You'll also want to remove printf() from your signal handlers.

Purists will also recommend that you manipulate a volatile sig_atomic_t variable inside the handler, rather than a plain int.

pilcrow
  • 56,591
  • 13
  • 94
  • 135