I am learning concepts of signals in the C language and met a problem when building a program for practices.
In the codes below, I am trying to reset SIGINT
each time after the user press "ctrl-c" and to record how many times the user press "ctrl-c".
#include<stdio.h>
#include<signal.h>
#include<unistd.h>
#include<setjmp.h>
void handler(int signo);
jmp_buf buf;
int int_counting = 1;
void handler(int signo)
{
signal(SIGINT, SIG_DFL);
int_counting++;
// just tried to add another "signal(SIGINT, handler)" here
// but saw the same result
longjmp(buf, 1);
}
int main()
{
if ((signal(SIGINT, handler) == SIG_ERR))
{
printf("Fail to catch the signal\n");
}
if (!setjmp(buf))
{
printf("Waiting for any signals ... \n");
}
else
{
if (!setjmp(buf)){} // to reset "setjmp" to zero
printf("Pressed 'ctrl-c' for %d times\n", int_counting);
printf("Waiting for another signal\n");
signal(SIGINT, handler);
}
while (int_counting <= 5)
{
sleep(1);
printf("Processing ...\n");
}
}
However, after the first signal no other signals can be sent to handler
and the output looks like:
Could you anyone explains the reason?
Below are examples where it seems like the signal will not be masked.
// Examples for SIGALRM
#include<stdio.h>
#include<signal.h>
#include<unistd.h>
int counting = 0;
void handler(int signo)
{
printf("%d\n", counting);
while (counting < 5)
{
signal(SIGALRM, handler);
printf("%d\n", beeps);
counting++
alarm(1);
}
}
void main(void)
{
if (signal(SIGALRM, handler) == SIG_ERR)
{
printf("cannot catch SIGALRM\n");
}
alarm(1);
while (counting < 5)
{
pause();
}
return;
}
// Example for SIGQUIT
#include<stdio.h>
#include<signal.h>
#include<unistd.h>
#include<setjmp.h>
jump_buf buf;
void handler(int signo)
{
signal(SIQQUIT, handler);
longjmp(buf, 1);
}
int main()
{
signal(SIQQUIT, handler);
if (!setjmp(buf))
{
printf("begin ...\n");
}
else
{
print("restart ...\n");
}
while (1)
{
sleep(1);
printf("waiting for sinals ...\n");
}
}
Although my original question is answered but if any further explanation about why those signals will not be masked (or please tell me that is how they work in C), it would be greatly helpful.
You need to save the signal mask and therefore use siglongjmp()
and sigsetjmp()
.
This works as expected:
#include<stdio.h>
#include<signal.h>
#include<unistd.h>
#include<setjmp.h>
void handler(int signo);
sigjmp_buf buf;
int int_counting = 0;
void handler(int signo)
{
signal(SIGINT, SIG_DFL);
int_counting++;
// just tried to add another "signal(SIGINT, handler)" here
// but saw the same result
siglongjmp(buf, 1); // 1: "fake" return value
}
int main()
{
if ((signal(SIGINT, handler) == SIG_ERR))
{
printf("Fail to catch the signal\n");
}
if (!sigsetjmp(buf, 1)) // 1 (or any non-zero value): save sigmask
{
printf("Waiting for any signals ... \n");
}
else // this code is executed when the "fake" return value of sigsetjmp is non-zero
{
printf("Pressed 'ctrl-c' for %d times\n", int_counting);
printf("Waiting for another signal\n");
signal(SIGINT, handler);
}
while (int_counting <= 5)
{
sleep(1);
printf("Processing ...\n");
}
}
It is described in the man-page e.g. man setjmp
:
sigsetjmp() and siglongjmp() also perform nonlocal gotos, but provide predictable handling of the process signal mask