0

Here is my code:

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

void sighandler(int signum);
jmp_buf buf;
void main(){
    signal(SIGINT,sighandler);

    if(!setjmp(buf))
        printf("welcome to this game\n");
    
    int a = 1;
    printf("raw value of a is %d\n",a);
    printf("modify a:");
    scanf("%d",&a);
    printf("new value of a is %d\n",a);
}
void sighandler(int signum){
    if(signum == SIGINT){
        printf("\nyou can't quit this game by ctrl+C,now we will restart it\n");
        longjmp(buf,1);
    }
}

and I ran it on ubuntu,result like below:

welcome to this game
raw value of a is 1
input num to modify a:^C
you can't quit this game by ctrl+C,now we will restrat it
raw value of a is 1
input num to modify a:^C

It seems signal() only capture the SIGINT for the first time. I read some answers on site such as:

"when a signal is delivered, it is also blocked during execution of the handler (no SIGINT will be delivered while execution is in sigint_handler if it is called from SIGINT delivery);"

BUT I don't get it since my signal_handler function should exit quickly. I don't know why is blocked.And is there any ways to make it work second or thrid time ? Thx

pilcrow
  • 56,591
  • 13
  • 94
  • 135
C.C
  • 89
  • 11
  • 2
    Remove the call to `longjmp` – selbie Apr 24 '21 at 05:19
  • 1
    If you're running on Ubuntu, the compiler should be complaining about `void main()` — the correct return type for `main()` is `int` on Unix-based systems such as (Ubuntu) Linux. If the compiler isn't complaining, you aren't using enough warning options. Start with `-Wall -Wextra -Werror` — you can get more stringent later. – Jonathan Leffler Apr 24 '21 at 05:21
  • 2
    With the `signal()` function, the classic behaviour was that the signal handling was reset to `SIG_DFL` when the handler is called, so the first thing the handler should do is reinstate the signal handling: `signal(signum, sighandler);`. It's better to use `sigaction()` — you have more control. However, try resetting the signal handler and see whether it works for you. – Jonathan Leffler Apr 24 '21 at 05:23
  • 1
    See also [How to avoid using `printf()` in a signal handler](https://stackoverflow.com/q/16891019/15168); it is not safe to call `printf()` — or a large number of other functions — from within a signal handler. See also [What is the difference between `sigaction()` and `signal()`?](https://stackoverflow.com/q/231912/15168) – Jonathan Leffler Apr 24 '21 at 05:24

2 Answers2

1

Inside your signal handler, SIGINT is blocked, that is, it is added to your process’ signal mask. (1)

When you leave the signal handler with longjmp, a non-local goto, the signal mask is untouched. Thus, when you resume execution at the setjmp point, you retain the signal mask set by your handler. (2)

sigsetjmp and siglongjmp address this issue by saving and restoring the signal mask.

However, I’d recommend reworking your code to avoid non-local gotos altogether. They can be used safely, but are easy to misuse and difficult to reason about.

Notes:

  1. This behavior of signal is common, but not universal, which is one good reason to prefer the standardized sigaction to signal.
  2. If you returned normally from your handler, the system would reset the mask for you.
pilcrow
  • 56,591
  • 13
  • 94
  • 135
0

You aren't actually returning from the signal handler (sure, you exit it, but you don't return from it -- you just jump to another context). If you let the signal handler return, your code will continue execution where it left off and it'll intercept any subsequent SIGINT signals the way you intend for it to.

mmiron
  • 164
  • 5