My signal handler sample is not working - c

1.I have written a piece of sample code and that will catch SIGALRM signal exit the main process.
#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
#include<sys/signal.h>
static int sig_flag=0;
static void mysignal(int sig)
{
sig_flag=1;
}
void installsignal(int sig,void( *signalhandler)(int))
{
struct sigaction action={0};
action.sa_handler=signalhandler;
action.sa_flags=0;
sigemptyset(&action.sa_mask);
if(sigaction(sig,&action,NULL)<0)
{
printf("can not catch signal signum:%d\n",sig);
}
}
main()
{
installsignal(SIGALRM,mysignal);
if(sig_flag==1)
{
printf("\n Signal has been caought\n");
exit(0);
}
while(1)
{
printf("\nHello world\n");
sleep(1);
}
exit(0);
}
2.When i have changed my program as given below then its works:-
#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
#include<sys/signal.h>
static int sig_flag=0;
static void mysignal(int sig)
{
sig_flag=1;
}
void installsignal(int sig,void( *signalhandler)(int))
{
struct sigaction action={0};
action.sa_handler=signalhandler;
action.sa_flags=0;
sigemptyset(&action.sa_mask);
if(sigaction(sig,&action,NULL)<0)
{
printf("can not catch signal signum:%d\n",sig);
}
}
main()
{
installsignal(SIGALRM,mysignal);
while(1)
{
printf("\nHello world\n");
if(sig_flag==1)
{
printf("\n Signal has been caought\n");
exit(0);
}
sleep(1);
}
exit(0);
}
Why first one sample code is not working

You got the control loop wrong. You never ask for the flag inside, so how would you want that you notice that the signal has been caught.
Besides that Basile is correct, only use sig_atomic_t for communication with a signal handler.

You should define
static volatile sig_atomic_t sig_flag=0;
Read about volatile variables and sig_atomic_t and read carefully signal(7)
Of course you need to test sig_flag inside your loop or use pause(2) or sigsuspend(2). Maybe you want an event loop using poll(2). Read Advanced Linux Programming, time(7), and about the Linux specific signalfd(2) and timerfd_create(2)....

Related

C Language - Fail to reset SIGINT to default

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
SIGINT is masked (blocked) during execution of your signal handler, and remains masked when you longjmp out of it. That's why you don't see subsequent SIGINTs — the signal mask prevents their delivery.
The fix is three-fold.
First, use sigsetjmp(buf, 1) to save the calling mask and siglongjmp make the jump. That will restore the signal mask to its expected value at that point in execution.
Second, use sigaction rather than signal. sigaction will force you to explicitly choose behavior like masking out signals during handler execution. signal, on the other hand, does not mandate consistent behavior across platforms.
Third, don't use (sig)longjmp at all. You got into this trouble because you are issuing a non-local goto from within asynchronously executed user code (your handler). It's very easy to make mistakes when reasoning about that kind of code.

Capturing signals in C

I'm struggling to implement the ability to capture signals in a process using C language.
Can anyone help-me with a working example?
Thanks.
You'll need to use the signal.h library.
Here's a working example in which I capture SIGINT and print a message to STDOUT:
#include<stdio.h>
#include<signal.h>
void sig_handler(int signo)
{
if (signo == SIGINT)
write(0, "Hello\n", 6);
}
int main(void)
{
signal(SIGINT, sig_handler);
// Just to testing purposes
while(1)
sleep(1);
return 0;
}

Counter in C Programming

I am trying to set up a counter for my programme to count how many times a signal was sent. I am trying to achieve the program to exit after ctrl +c was pressed twice. I have most of the code but just don't know how to link the counter to the if section. Here is my code.
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
// user-defined signal handler for alarm.
int cnt=0;
void my_handler(int signo)
{
while ( cnt < 2){
if (signo == SIGINT)
{
printf("Press ctrl c to stop\n");
exit(0);
}
}
}
int main(void)
{
signal(SIGINT,my_handler);
while(1){
printf(" I am running into infinite loop.., stop me if you dear..\n");
sleep(1); /* wait until alarm goes off */
}
} /* main */
I tried out the above code and it seems that the counter will stay at 0 forever and the programme exit immediately as soon as ctrl+c was pressed.
You can't do much safely in a signal handler, and definitely no I/O. For maximum portability, there are really only a handful of things a signal handler can do to affect global state:
Assign to a volatile sig_atomic_t variable
Make calls to signal
abort, exit, etc. on error
You can't do I/O safely. The safe thing to do is set a flag that the main thread can check and do your printing for you. If printing isn't necessary, the first call to your handler could just unregister itself, restoring the default behavior with SIG_DFL (or registering a new "second Ctrl-C" handler if you need to do something special) so the second Ctrl-C kills as normal.
Replace the while statement with an if one. If cnt is lower than 2, then print your message and count by using cnt++; else do something else
Signals are a little more involved to get right.
You should either use sigaction or a custom sigaction wrapper as signal doesn't have clearly defined semantics. Registering the handler may fail.
If you want to set a flag, it should be volatile sigatomic_t, you shouldn't do buffered IO in the handler.
With the wrapper and flag approach, you could do something like:
typedef void (Sigfunc)(int);
Sigfunc* reliableSignal(int signo, Sigfunc *func);
// user-defined signal handler for alarm.
volatile sig_atomic_t cnt=0;
void my_handler(int signo){
if(cnt++ == 1)
exit(0);
}
int main(void) {
if(reliableSignal(SIGINT,my_handler)<0){ perror("Signal"); exit(1); }
while(1){
printf(" I am running into infinite loop.., stop me if you dear..\n");
sleep(1); /* wait until alarm goes off */
}
} /* main */
Sigfunc* reliableSignal(int signo, Sigfunc *func)
{
struct sigaction act, oact;
act.sa_handler = func;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
if (signo == SIGALRM) {
#ifdef SA_INTERRUPT
act.sa_flags |= SA_INTERRUPT;
#endif
} else {
act.sa_flags |= SA_RESTART;
}
if (sigaction(signo, &act, &oact) < 0)
return(SIG_ERR);
return(oact.sa_handler);
}
In this example you must press twice Ctrl-C within 300ms.
So if you keep Ctrl-C pressed the program will stop otherwise not.
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
int ctrlcs=0;
void cchandler(int signum){
printf("Press again to quit.\n");
ctrlcs+=1;
if (ctrlcs==2) {
signal(SIGINT, SIG_DFL);
}
usleep(300000); // delay for the second Ctrl-C
}
int main(){
signal(SIGINT, cchandler);
while(1) {
printf(" I am running into infinite loop.., stop me if you dare..\n");
sleep (5);
ctrlcs=0;
}
}

How to avoid scanf after my signal handler function in C?

I have this code:
#include <stdio.h>
#include <signal.h>
void signal_handler(int signal) {
printf("Caught signal in CHILD.\n");
}
int main(void) {
int s;
signal(SIGTSTP, signal_handler);
while(1){
printf("%s#%s/# ",getlogin(),get_current_dir_name());
scanf("%d",&s);
}
return 0;
}
when i run the code it prints:
something: ^ZCaught signal in CHILD.
As far i understand that the scanf doesn't execute when i press the ctr-z. Although after the printf inside my function it goes straight to the scanf, waits for input and then starts the loop again.Is there any way to avoid scanf when i press ctr-z and start the while loop again? I tried something like that
void signal_handler(int signal) {
printf("Caught signal in CHILD.\n");
printf("%s#%s/# ",getlogin(),get_current_dir_name());
}
but it didn't work. After the second printf goes straight to the scanf, waits for input and then starts the loop again. Can i, somehow, start the loop again?
The signal handler is interrupting scanf during its read of STDIN. However, because of the way you set signal disposition, the read system call restarts immediately upon return of the signal handler. That's why you are "stuck" in the scanf rather than back at the top of your loop.
One important thing you can do is to use sigaction rather than signal. This will force you to specify the behavior of interrupted calls: restart them or not?
The next thing to do is to limit your signal handlers to functions that are async-signal-safe, lest you risk misery.
As an aside, another change to make is to give us all the required includes (<unistd.h>?) and defines (_GNU_SOURCE ?) to make your program work.
As commented the worst solution should be:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
void signal_handler(int signal) {
printf("Caught signal in CHILD.\n");
exit(1);
}
int main(void) {
int s;
signal(SIGTSTP, signal_handler);
while(1){
printf("test\n");
scanf("%d",&s);
}
return 0;
}
Better solution
#include <stdio.h>
#include <signal.h>
static volatile int keepRunning = 1;
void signal_handler(int signal) {
printf("Caught signal in CHILD.\n");
keepRunning = 0;
}
int main(void) {
int s;
signal(SIGTSTP, signal_handler);
while(keepRunning){
printf("test\n");
scanf("%d",&s);
}
return 0;
}
EDIT after comments
#include <stdio.h>
#include <signal.h>
static volatile int skipPrintf= 1;
void signal_handler(int signal) {
printf("Caught signal in CHILD.\n");
skipPrintf= 1;
}
int main(void) {
int s;
signal(SIGTSTP, signal_handler);
while(1){
if (skipPrintf == 0)
{
printf("test\n");
}
else
{
skipPrintf = 0;
}
scanf("%d",&s);
}
return 0;
}

Signal handler is not getting called in main function

I am trying to study how signal handlers work. I have written code where i cause an alarm signal to raise once in every 100us. But, the signal is not raised. Here is the code :
#include <signal.h>
#include <ucontext.h>
#include <sys/time.h>
#include<unistd.h>
#include<setjmp.h>
#include<stdio.h>
void handler(int signum, siginfo_t *ptr, ucontext_t *old_context)
{
printf("inside handler");
}
int main()
{
struct itimerval itv;
struct sigaction act;
act.sa_handler = handler;
act.sa_flags=SA_RESTART|SA_SIGINFO;
sigaction(SIGVTALRM, &act, 0);
itv.it_interval.tv_sec=0;
itv.it_interval.tv_usec=100;
itv.it_value.tv_sec = 0;
itv.it_value.tv_usec = 100;
setitimer(ITIMER_VIRTUAL, &itv, NULL); //engage timer
int i=0;
while(i<=100)
{
printf("main\n");
i++;
}
}
can some one explain what i am doing wrong?
Thanks
Your loop is probably taking less than 100us to run, try this:
volatile int i=0;
while(i<=100000000)
{
//printf("main\n");
i++;
}
I removed the printf so the output is not flooded, and made i volatile so the compiler won't optimize the loop.

Resources