#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
/* A signal handling function that simply prints
a message to standard error. */
void handler(int code) {
fprintf(stderr, "Signal %d caught\n", code);
}
int main() {
// Declare a struct to be used by the sigaction function:
struct sigaction newact;
// Specify that we want the handler function to handle the
// signal:
newact.sa_handler = handler;
// Use default flags:
newact.sa_flags = 0;
// Specify that we don't want any signals to be blocked during
// execution of handler:
sigemptyset(&newact.sa_mask);
// Modify the signal table so that handler is called when
// signal SIGINT is received:
sigaction(SIGINT, &newact, NULL);
// Keep the program executing long enough for users to send
// a signal:
int i = 0;
for (;;) {
if ((i++ % 50000000) == 0) {
fprintf(stderr, ".");
}
}
return 0;
}
When I press ctrl-c, I want my program to print "Signal %d caught\n" message then exit normally as it would when pressing ctrl-c.
./test
..............................^CSignal 2 caught
.................^CSignal 2 caught
..........................................^Z
[2]+ Stopped ./test
Right now it just prints the message but doesn't exit the program right after.
That is because the default behavior of ctrl+c is to exit the program. But by using sigaction() you are managing the behavior yourself. So if you want the program to end, you can add an exit() call.
void handler(int code) {
fprintf(stderr, "Signal %d caught\n", code);
exit(code);
}
Related
I have a program that runs a loop, each time at the end of the loop, the process should sleep for some seconds(the number of seconds is not constant and is calculated at each loop) or until the process receives SIGINT, I used alarm() and sigwait() to do this but it's blocking the ctrl+c signal(i.e SIGINT) which I don't want, I want SIGINT to be received and acted upon normally, sample code below (note that somefunction() below is just an example, in the original code it does real calculation instead of using rand())
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <sys/time.h>
#include <unistd.h>
sigset_t sigs;
void setup_alarm()
{
printf("setting up signals\n");
sigemptyset(&sigs);
sigaddset(&sigs, SIGALRM);
sigprocmask(SIG_BLOCK, &sigs, NULL);
}
void wait_for_alarm(int interval)
{
printf("setting up alarm for %d seconds\n", interval);
alarm(interval);
printf("waiting for signal\n");
int sig_num = sigwait(&sigs, NULL);
// sigwaitinfo()
if (sig_num == 0)
{
printf("I received the alarm signal, breaking the wait\n");
}
else if (sig_num == EINVAL)
{
printf("some other error occurred");
perror("signal wait failed unexpectedly");
exit(1);
}
}
int somefunction()
{
srand(time(NULL));
return (rand() % 4) + 1;
}
int main(int argc, char *argv[])
{
int alarm_wait = 0;
setup_alarm();
while (1)
{
// do somework here
alarm_wait = somefunction();
// sleep for $alarm_wait or untill we receive SIGALARM
wait_for_alarm(alarm_wait);
}
return 0;
}
The results I'm getting is that when the execution reaches sigwait and I send the SIGINT signal(through ctrl-c) the program is not interrupted instead it keeps waiting until $alarm_wait has elapsed or until I send SIGALRM, what I want to do is have the logic only handles SIGALRM and every other signal should be handled normally(i.e SIGINT should interrupt the program even while it's waiting for SIGALRM signal)
Thanks to #Shawn for pointing out the second argument of sigwait I was able to solve my issue by also blocking SIGINT and using the second argument of sigwait to determine if the signal is SIGINT then execute exit(0)
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <sys/time.h>
#include <unistd.h>
sigset_t sigs;
void setup_alarm()
{
printf("setting up signals\n");
sigemptyset(&sigs);
sigaddset(&sigs, SIGALRM);
sigaddset(&sigs, SIGINT);
sigprocmask(SIG_BLOCK, &sigs, NULL);
}
void wait_for_alarm(int interval)
{
printf("setting up alarm for %d seconds\n", interval);
alarm(interval);
printf("waiting for signal\n");
int sig;
int sig_num = sigwait(&sigs, &sig);
if(sig == SIGINT)
exit(0);
if (sig_num == 0)
{
printf("I received the alarm signal, breaking the wait\n");
}
else if (sig_num == EINVAL)
{
printf("some other error occurred");
perror("signal wait failed unexpectedly");
exit(1);
}
}
int somefunction()
{
srand(time(NULL));
return (rand() % 4) + 1;
}
int main(int argc, char *argv[])
{
int alarm_wait = 0;
setup_alarm();
while (1)
{
// do somework here
alarm_wait = somefunction();
// sleep for $alarm_wait or untill we receive SIGALARM
wait_for_alarm(alarm_wait);
}
return 0;
}
The code now works as i would expect, i'm not sure if this is the best solution since i'm only handling two signals and don't know how the rest of the signals are being handled(maybe some of these signals are important for the init system for example).
I will leave my answer unaccepted for sometime incase someone has a better solution.
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;
}
}
I'm writing code that have process who have to handle with any signal i gave him. I read that i should do something like that
void signalHandler(int sig_num)
{
// some stuff
}
//My process
int i;
for (i = 1; i <= 64; i++)
signal(i, signalHandler);
Is this correct solution ??
Although #Dylan's solution seems good and it is but it poses the a common problem and that is compatibility issue with signal function. It is hence recommended that you use sigaction always. Here is an example
#include <stdio.h>
#include <signal.h>
static void handler(int signo){
write(stdout, &signo, sizeof(int));
}
int main() {
struct sigaction sa;
sa.sa_handler = handler;
int i;
for (i = 1; i <= 64; i++) {
sigaction(i, &sa, NULL);
}
while(1);
return 0;
}
Try to avoid the use of signal as much as possible
Never use any function which are not Reentrant or not Async-signal-safe functions in signal handler like printf
Check the list of allowed functions in signal handler from here
POSIX.1-2004 (also known as POSIX.1-2001 Technical Corrigendum 2)
requires an implementation to guarantee that the following functions
can be safely called inside a signal handler:
You are on the right track if you want to handle signals 1 through 64 with the same signal handler. This test program will handle signals 1 through 64 by printing out its number.
#include <stdio.h>
#include <signal.h>
void signalHandler(int sig_num)
{
printf("Signal %d caught!\n", sig_num);
}
int main(int argc, char const *argv[])
{
//My process
int i;
for (i = 1; i <= 64; i++) {
signal(i, signalHandler);
}
while (1);
return 0;
}
For example, when you press CTRL+C while this program is running. The kernel sends signal 2 SIGINT to the program, and calls signalHandler(2). This program prints "Signal 2 caught!"
Post-Facepalm edit: this program obviously needs to be terminated with a kill -9 command........
I am using the open signals SIGUSR1 and SIGUSR2 to call a user-defined function. I have tried two function prototype for my signal handling function. Both of which runs without any compilation error. What exactly happens when open signals call a function? How is the function supposed to be implemented?
prototype1:
/***********************************************************/
/*** Sample program demonstrating the sending of signals ***/
/*** Written by Abhijit Das, 17-Jan-2014 ***/
/***********************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
/* The signal handler for the child process */
void childSigHandler (int sig)
{
//int sig;
if (sig == SIGUSR1) {
printf("+++ Child : Received signal SIGUSR1 from parent...\n");
sleep(1);
} else if (sig == SIGUSR2) {
printf("+++ Child : Received signal SIGUSR2 from parent...\n");
sleep(5);
}
exit(0);
}
int main ()
{
int pid;
pid = fork(); /* Spawn the child process */
if (pid) {
/* Parent process */
int t;
srand((unsigned int)time(NULL));
t = 2 + rand() % 4;
printf("+++ Parent: Going to sleep for %d seconds\n", t);
sleep(t); /* Sleep for some time before sending a signal to child */
t = 1 + rand() % 2;
printf("+++ Parent: Going to send signal SIGUSR%d to child\n", t);
kill(pid, (t == 1) ? SIGUSR1 : SIGUSR2); /* Send signal to child */
wait(NULL); /* Wait for child to exit */
printf("+++ Parent: Child exited\n");
} else {
/* Child process */
signal(SIGUSR1, childSigHandler); /* Register SIGUSR1 handler */
signal(SIGUSR2, childSigHandler); /* Register SIGUSR2 handler */
while (1) sleep(1); /* Sleep until a signal is received from parent */
}
exit(0);
}
prototype2:
/***********************************************************/
/*** Sample program demonstrating the sending of signals ***/
/*** Written by Abhijit Das, 17-Jan-2014 ***/
/***********************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
/* The signal handler for the child process */
void childSigHandler ()
{
int sig;
if (sig == SIGUSR1) {
printf("+++ Child : Received signal SIGUSR1 from parent...\n");
sleep(1);
} else if (sig == SIGUSR2) {
printf("+++ Child : Received signal SIGUSR2 from parent...\n");
sleep(5);
}
exit(0);
}
int main ()
{
int pid;
pid = fork(); /* Spawn the child process */
if (pid) {
/* Parent process */
int t;
srand((unsigned int)time(NULL));
t = 2 + rand() % 4;
printf("+++ Parent: Going to sleep for %d seconds\n", t);
sleep(t); /* Sleep for some time before sending a signal to child */
t = 1 + rand() % 2;
printf("+++ Parent: Going to send signal SIGUSR%d to child\n", t);
kill(pid, (t == 1) ? SIGUSR1 : SIGUSR2); /* Send signal to child */
wait(NULL); /* Wait for child to exit */
printf("+++ Parent: Child exited\n");
} else {
/* Child process */
signal(SIGUSR1, childSigHandler); /* Register SIGUSR1 handler */
signal(SIGUSR2, childSigHandler); /* Register SIGUSR2 handler */
while (1) sleep(1); /* Sleep until a signal is received from parent */
}
exit(0);
}
See the documentation.
The signature for a signal handler is:
typedef void (*sighandler_t)(int);
Your first example uses an empty parameter list, which basically doesn't declare any expected arguments. The compiler is probably generating boiler-plate to handle "any" arguments being passed, in that case.
If you enable all warnings, you might get something from your compiler. Also note that you can make the handler static since you're passing the pointer to the library anyway, it doesn't have to be visible from the outside.
Read this:
http://www.gnu.org/software/libc/manual/html_node/Basic-Signal-Handling.html
In the first 10 lines of this page, you have your answer.
Since our good frien alk here thinks I'm not being explicit enough, I'll copy-paste them for you :
The signal function provides a simple interface for establishing an action for a particular signal. The function and associated macros are declared in the header file signal.h.
— Data Type: sighandler_t
This is the type of signal handler functions. Signal handlers take one integer argument specifying the signal number, and have return type void. So, you should define handler functions like this:
void handler (int signum) { ... }
The name sighandler_t for this data type is a GNU extension.
— Function: sighandler_t signal (int signum, sighandler_t action)
The signal function establishes action as the action for the signal signum.
For more information about defining signal handler functions, see Defining Handlers.
Or even better, google this:
signal handler function
Or even better yet, read a textbook about signal handling first.
If you are not familiar with C basic mechanisms, it is a bit early to tackle signal handling, in my opinion.
Here i have one sample code for signal Handling and copy process.
Here i want to call one timer using signal action, for every second.
Its working fine here but when i add my copy process code in between start and stop timer function that time my copy process will be killed when first time signal raised means after 1 second.
Here i tried with these SIGRTMAX ,SIGUSR1, SIGALRM signals but they all give same results.
Why my copy process stops when signal raised.?
Code :
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <signal.h>
#include <sys/time.h>
#include <unistd.h>
#define SIGTIMER SIGRTMAX
timer_t KeepAliveTimerId;
void stopKeepAlive()
{
if(KeepAliveTimerId != NULL)
{
timer_delete(KeepAliveTimerId);
printf("timer delete\n");
}
}
void signalHandler(int signo, siginfo_t* info, void* context)
{
if (signo == SIGTIMER)
{
printf("Signal Raised\n");
}
}
int startKeepAlive()
{
struct sigevent sigev; //signal event struct
struct itimerspec itval;
struct itimerspec oitval;
struct sigaction sigact;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = SA_SIGINFO;
sigact.sa_sigaction = signalHandler;
// set up sigaction to catch signal
if (sigaction(SIGTIMER, &sigact, NULL) == -1)
{
printf("time_settime error \n");
return -1;
}
//Create the POSIX timer to generate signo
sigev.sigev_notify = SIGEV_SIGNAL;
sigev.sigev_signo = SIGTIMER;
sigev.sigev_value.sival_int = 2;
if (timer_create(CLOCK_REALTIME, &sigev, &KeepAliveTimerId) == 0)
{
itval.it_value.tv_sec = 1;
itval.it_value.tv_nsec = 0L;
itval.it_interval.tv_sec = itval.it_value.tv_sec;
itval.it_interval.tv_nsec = itval.it_value.tv_nsec;
if (timer_settime(KeepAliveTimerId, 0, &itval, &oitval) != 0)
{
printf("Error in set time \n");
return -2;
}
}
else
{
printf("Error in creating timer \n");
return -3;
}
return 0;
}
int main()
{
int result;
// Start Timer
startKeepAlive();
result = system("cp /mnt/bct/package.QuipC /Download/ 2>&1");
if (result == 0)
{
printf("result is %d\n",result);
//stop timer
stopKeepAlive();
return EXIT_SUCCESS;
}
printf("result is %d\n",result);
// Stop Timer
stopKeepAlive();
return EXIT_FAILURE;
}
You use real-time signals, from http://www.kernel.org/doc/man-pages/online/pages/man7/signal.7.html:
...
The default action for an unhandled real-time signal is to terminate
the receiving process ...
So it seems that calling system(...) somehow affects your signal handler. I would suggest (as wildplasser already mentioned) getting rid of obvious mistake (printf in signal handler). Under above link you also have nice list of functions that can be used in signal handler (paragraph Async-signal-safe functions). After you do it please tell us if it made any difference.
Just to be sure I added this:
#include <stdarg.h>
int zprintf(char *fmt, ...);
int zprintf(char *fmt, ...)
{
int rc;
char buff[100];
va_list aaa;
va_start(aaa, fmt);
rc = sprintf(buff, fmt, aaa);
va_end(aaa);
rc = write(2, buff, rc);
return rc;
}
And replaced the signal handler by:
void signalHandler(int signo, siginfo_t* info, void* context)
{
if (signo == SIGTIMER)
{
zprintf("Signal Raised\n");
}
else
{
zprintf("Signal %d Raised\n", signo);
}
}
... and replaced the system() string like:
result = system("cp ../wakker/megahal-9.1.1.dld/tele/megahal.brn /tmp/ 2>&1");
And it worked:
$ ./a.out
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
result is 0
timer delete
Could be coincidence. (But Undefined Behavior is also coincidence!)
I compiled this code (trivial variation on the original — added explicit void argument lists, and #define _XOPEN_SOURCE 700 to get the timer_t declarations, simplified the signal handler, and linked and tested on Linux (RHEL 5) with -lrt because Mac OS X doesn't have timer_t in any header under /usr/include — with a simpler command to execute (echo, sleep, echo), and got the plausible looking output:
Started
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Done
result is 0
timer delete
I infer from this that the timing signals do not affect the command run by system(), as indeed they should not.
gcc -Wall -Wextra -g -O3 -std=c99 sau.c -o sau -lrt
The -std=c99 option probably accounts for me needing to specify _XOPEN_SOURCE. If I could be bothered to compile with -std=gnu99, it probably would not be needed.
Code
#define _XOPEN_SOURCE 700
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <signal.h>
#include <sys/time.h>
#include <unistd.h>
#define SIGTIMER SIGRTMAX
timer_t KeepAliveTimerId;
void stopKeepAlive(void)
{
if(KeepAliveTimerId != NULL)
{
timer_delete(KeepAliveTimerId);
printf("timer delete\n");
}
}
void signalHandler(int signo)
{
if (signo == SIGTIMER)
{
printf("Signal Raised\n");
}
}
int startKeepAlive(void)
{
struct sigevent sigev; //signal event struct
struct itimerspec itval;
struct itimerspec oitval;
struct sigaction sigact;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = 0;
sigact.sa_handler = signalHandler;
// set up sigaction to catch signal
if (sigaction(SIGTIMER, &sigact, NULL) == -1)
{
printf("time_settime error \n");
return -1;
}
//Create the POSIX timer to generate signo
sigev.sigev_notify = SIGEV_SIGNAL;
sigev.sigev_signo = SIGTIMER;
sigev.sigev_value.sival_int = 2;
if (timer_create(CLOCK_REALTIME, &sigev, &KeepAliveTimerId) == 0)
{
itval.it_value.tv_sec = 1;
itval.it_value.tv_nsec = 0L;
itval.it_interval.tv_sec = itval.it_value.tv_sec;
itval.it_interval.tv_nsec = itval.it_value.tv_nsec;
if (timer_settime(KeepAliveTimerId, 0, &itval, &oitval) != 0)
{
printf("Error in set time \n");
return -2;
}
}
else
{
printf("Error in creating timer \n");
return -3;
}
return 0;
}
int main(void)
{
int result;
// Start Timer
startKeepAlive();
result = system("echo Started; sleep 10; echo Done");
if (result == 0)
{
printf("result is %d\n",result);
//stop timer
stopKeepAlive();
return EXIT_SUCCESS;
}
printf("result is %d\n",result);
// Stop Timer
stopKeepAlive();
return EXIT_FAILURE;
}