2

execute

my code

jmp_buf a;

void sig_handler(int signum) {
        if(signum == SIGINT) exit(0);

        printf("In the handler\n");
        sleep(2);
        alarm(3);
        longjmp(a,1);
}
int main(int argc, char *argv[]) {
    int j=0;
    struct sigaction sa;

    memset(&sa, 0, sizeof(struct sigaction));
    sa.sa_handler = sig_handler;
    sigfillset(&sa.sa_mask);
    sa.sa_flags = 0;
    sigaction(SIGALRM, &sa, NULL);

    alarm(2);
    j = setjmp(a);
    while(1){
       printf("In the main\n");
       pause();
        }
    return 0;
}

I thought the result of this code is

In the main. In the handler. In the main. In the handler. In the main. In the handler. In the main. In the handler. . . .

but It didn't work. The alarm function wasn't set in the handler. when I delete setjmp, longjmp, It works well. But I don't want to delete them. Does setjmp affect setting the alarm function? How to solve this.

hkjaaaip
  • 63
  • 1
  • 1
  • 5

1 Answers1

3

The interaction of longjmp and signals is unspecified. Use siglongjmp instead. This code should work:

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

sigjmp_buf a;

void sig_handler(int signum) {
        if(signum == SIGINT) exit(0);

        printf("In the handler\n");
        sleep(2);
        alarm(3);
        siglongjmp(a,1);
}

int main(int argc, char *argv[])
{
    int j=0;
    struct sigaction sa;

    memset(&sa, 0, sizeof(struct sigaction));
    sa.sa_handler = sig_handler;
    sigfillset(&sa.sa_mask);
    sa.sa_flags = SA_NODEFER;
    sigaction(SIGALRM, &sa, NULL);

    alarm(2);
    j = sigsetjmp(a, 1);
    while(1){
       printf("In the main\n");
       pause();
        }
    return 0;
}
David Schwartz
  • 179,497
  • 17
  • 214
  • 278
  • 1
    The behavior is actually specified on Linux, according to the man page: it is System V style and `setjmp/longjmp` don't touch the signal masks. So (more info for @pjlee): in the original program, all signals are blocked when the handler starts (as requested in the mask passed to `sigaction`). If the handler returned, they would be unblocked again, but since you `longjmp` instead, they remain blocked. And so when SIGALRM arrives for the second time, it is still blocked and the handler is not called. [...] – Nate Eldredge May 06 '20 at 18:24
  • 1
    `siglongjmp` ensures that the mask is set back to the way it was when you called `sigsetjmp`, i.e. with SIGALRM unblocked. And that's why it works. – Nate Eldredge May 06 '20 at 18:24