I am trying to have a signal handler stop a timer without exiting my program. How should I go about. I want StopTimer to handle the signal to stop the timer
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <sys/time.h>
#include <signal.h>
#include <unistd.h>
#define INTERVAL 2 // number of seconds to go off
int main(int argc, char* argv[]) {
TimerSet(INTERVAL);
while(1)
{
// do stuff
}
return 0;
}
void TimerSet(int interval)
{
printf("starting timer\n");
struct itimerval it_val;
// interval value
it_val.it_value.tv_sec = interval;
it_val.it_interval = it_val.it_value;
// on SIGALRM, close window
if (signal(SIGALRM, TimerStop) == SIG_ERR)
{
perror("Unable to catch SIGALRM");
exit(1);
}
// set interval timer, returns SIGALRM on expiration
if (setitimer(ITIMER_REAL, &it_val, NULL) == -1)
{
perror("error calling setitimer()");
exit(1);
}
}
void TimerStop(int signum)
{
printf("Timer ran out! Stopping timer\n");
exit(signum);
}
I tried to set the setitimer interval to 0, but I am not sure how to use the same timer within the TimerStop signal handler function
Just set it_interval to zero, and you'll get a one-shot timer. You don't need to do anything with it in your handler.
For instance, with this:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <sys/time.h>
#include <signal.h>
#include <unistd.h>
#define INTERVAL 2 // number of seconds to go off
void TimerStop(int signum) {
printf("Timer ran out! Stopping timer\n");
}
void TimerSet(int interval) {
printf("starting timer\n");
struct itimerval it_val;
it_val.it_value.tv_sec = interval;
it_val.it_value.tv_usec = 0;
it_val.it_interval.tv_sec = 0;
it_val.it_interval.tv_usec = 0;
if (signal(SIGALRM, TimerStop) == SIG_ERR) {
perror("Unable to catch SIGALRM");
exit(1);
}
if (setitimer(ITIMER_REAL, &it_val, NULL) == -1) {
perror("error calling setitimer()");
exit(1);
}
}
int main(int argc, char *argv[]) {
TimerSet(INTERVAL);
while (1) {
// do stuff
}
return 0;
}
the message "Timer ran out! Stopping timer" will appear only once, and your timer will stop without you doing anything.
Note that you need to fill in the tv_usec members of your struct itimerval, which your current code does not do. If you don't, it_interval is highly unlikely to be zero, and your timer will never stop.
printf(), along with the other standard IO functions, is not really safe to call from a signal handler, although in this particular case it won't cause you any problems, since the main code is just sitting in a loop and not doing anything.
Also, presume you're calling signal() on purpose - sigaction() is the recommended way for setting handlers. setitimer() is also obsolete, now, and timer_settime() is recommended.
According to manual:
Timers decrement from it_value to zero, generate a signal, and reset to
it_interval. A timer which is set to zero (it_value is zero or the timer
expires and it_interval is zero) stops.
Both tv_sec and tv_usec are significant in determining the duration of a
timer.
So timer can be set to run only once if interval is set to zero before setitimer() call (thanks to Duck's comment).
Related
This is probably a very basic question, but I'm using the code below to run a simple alarm. It works as I want it to, but I'm wondering if it's at all possible to run multiple alarms simultaneously that each trigger a different function when complete. Is there a way to do that?
#include <signal.h>
#include <sys/time.h>
#include <stdio.h>
#include <time.h>
void alarm_handler(int signum){
printf("five seconds passed!!\n");
}
int main(){
signal(SIGALRM, alarm_handler);
alarm(5);
pause();
return 0;
}
No. According to this source:
Alarm requests are not stacked; only one SIGALRM generation can be scheduled in this manner. If the SIGALRM signal has not yet been generated, the call shall result in rescheduling the time at which the SIGALRM signal is generated.
One alternative is to create a priority queue in which you put your tasks and then always schedule your alarm for the time difference between the current time and the task at the top of the queue.
But be sure to look at this SO question: you're limited in the kinds of things you can do inside your signal handler.
Not with alarm(2), however, you can use POSIX timers to achieve your goal.
Either you can set each timer to run a different signal when it expires or you can use a single signal and pass a pointer to the timer with it via siginfo_t, based on which you can then decide what to do in the handler.
Example:
#include <signal.h>
#include <stdio.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
static timer_t tmid0, tmid1;
static void hndlr(int Sig, siginfo_t *Info, void *Ptr)
{
if(Info->si_value.sival_ptr == &tmid0)
write(2, "tmid0\n", 6);
else{
write(2, "tmid1\n", 6);
_exit(0);
}
}
int main()
{
int r = EXIT_SUCCESS;
sigaction(SIGALRM, &(struct sigaction){ .sa_sigaction = hndlr, .sa_flags=SA_SIGINFO }, 0);
printf("%p %p\n", (void*)&tmid0, (void*)&tmid1);
struct sigevent sev = { .sigev_notify = SIGEV_SIGNAL, .sigev_signo = SIGALRM };
sev.sigev_value.sival_ptr = &tmid0;
if(0>timer_create(CLOCK_REALTIME,&sev,&tmid0))
{ r=EXIT_FAILURE; goto out; }
sev.sigev_value.sival_ptr = &tmid1;
if(0>timer_create(CLOCK_REALTIME,&sev,&tmid1))
{ r=EXIT_FAILURE; goto out; }
if(0>timer_settime(tmid0, 0, &(struct itimerspec const){ .it_value={1,0} } , NULL) )
{ r=EXIT_FAILURE; goto out; }
//tmid0 expires after 1 second
if(0>timer_settime(tmid1, 0, &(struct itimerspec const){ .it_value={3,0} } , NULL) )
{ r=EXIT_FAILURE; goto out; }
//tmid1 expires after 3 seconds
for(;;)
pause();
out:
if(r)
perror(0);
return r;
}
Hi I'm trying to learn more about signals and I wrote a simple code that supposed to just print "bye" everything the alarm signal is send. I am using sigaction to set this. However, I keep returning NULL in my error checking could someone tell me what I'm doing wrong. Thanks in Advance!
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/time.h> /* for setitimer */
#include <unistd.h> /* for pause */
#include <signal.h> /* for signal */
#define INTERVAL 500 /* number of milliseconds to go off */
/* function prototype */
void DoStuff();
int main(int argc, char *argv[]) {
struct itimerval it_val; /* for setting itimer */
struct sigaction sa;
sa.sa_handler = &DoStuff;
/* Upon SIGALRM, call DoStuff().
* Set interval timer. We want frequency in ms,
* but the setitimer call needs seconds and useconds. */
if (sigaction(SIGALRM,&sa,NULL) < 0) { /*set the signal to be enabled if this action occurs*/
perror("Unable to catch SIGALRM");
exit(1);
}
it_val.it_interval = it_val.it_value;
it_val.it_value.tv_sec = INTERVAL/1000;
it_val.it_value.tv_usec = (INTERVAL*1000) % 1000000;
it_val.it_interval = it_val.it_value;
if (setitimer(ITIMER_REAL, &it_val, NULL) == -1) { /*set the timer to send the alarm command*/
perror("error calling setitimer()");
exit(1);
}
while(1)
{
pause();
}
}
void DoStuff() {
printf("bye\n");
}
sigaction cannot return null, since it returns an integer. I'm assuming it's returning -1. You're not correctly initializing the sigaction structure. It has many fields, but you're allowing them to be undefined. Fix the structure definition and try again. See:
http://man7.org/linux/man-pages/man2/sigaction.2.html
This is probably a very basic question, but I'm using the code below to run a simple alarm. It works as I want it to, but I'm wondering if it's at all possible to run multiple alarms simultaneously that each trigger a different function when complete. Is there a way to do that?
#include <signal.h>
#include <sys/time.h>
#include <stdio.h>
#include <time.h>
void alarm_handler(int signum){
printf("five seconds passed!!\n");
}
int main(){
signal(SIGALRM, alarm_handler);
alarm(5);
pause();
return 0;
}
No. According to this source:
Alarm requests are not stacked; only one SIGALRM generation can be scheduled in this manner. If the SIGALRM signal has not yet been generated, the call shall result in rescheduling the time at which the SIGALRM signal is generated.
One alternative is to create a priority queue in which you put your tasks and then always schedule your alarm for the time difference between the current time and the task at the top of the queue.
But be sure to look at this SO question: you're limited in the kinds of things you can do inside your signal handler.
Not with alarm(2), however, you can use POSIX timers to achieve your goal.
Either you can set each timer to run a different signal when it expires or you can use a single signal and pass a pointer to the timer with it via siginfo_t, based on which you can then decide what to do in the handler.
Example:
#include <signal.h>
#include <stdio.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
static timer_t tmid0, tmid1;
static void hndlr(int Sig, siginfo_t *Info, void *Ptr)
{
if(Info->si_value.sival_ptr == &tmid0)
write(2, "tmid0\n", 6);
else{
write(2, "tmid1\n", 6);
_exit(0);
}
}
int main()
{
int r = EXIT_SUCCESS;
sigaction(SIGALRM, &(struct sigaction){ .sa_sigaction = hndlr, .sa_flags=SA_SIGINFO }, 0);
printf("%p %p\n", (void*)&tmid0, (void*)&tmid1);
struct sigevent sev = { .sigev_notify = SIGEV_SIGNAL, .sigev_signo = SIGALRM };
sev.sigev_value.sival_ptr = &tmid0;
if(0>timer_create(CLOCK_REALTIME,&sev,&tmid0))
{ r=EXIT_FAILURE; goto out; }
sev.sigev_value.sival_ptr = &tmid1;
if(0>timer_create(CLOCK_REALTIME,&sev,&tmid1))
{ r=EXIT_FAILURE; goto out; }
if(0>timer_settime(tmid0, 0, &(struct itimerspec const){ .it_value={1,0} } , NULL) )
{ r=EXIT_FAILURE; goto out; }
//tmid0 expires after 1 second
if(0>timer_settime(tmid1, 0, &(struct itimerspec const){ .it_value={3,0} } , NULL) )
{ r=EXIT_FAILURE; goto out; }
//tmid1 expires after 3 seconds
for(;;)
pause();
out:
if(r)
perror(0);
return r;
}
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 want to set a runtime limit (in hours) to my algorithm in C, so that when it reaches the limit, the algorithm stops (for example, at 12 hours). Does anyone have any suggestions how to do this?
You can use time() to obtain the time at start, and time at each iteration in your algorithm. You can use difftime() to calculate the difference and terminate the algorithm when it exceeds a certain value.
Assuming, your algorithm is iterative, here is a sample code that terminates the loop after 5 seconds.
#include <stdio.h>
#include <time.h>
int main(int argc, char **argv)
{
time_t start_time;
time_t now_time;
time(&start_time);
while (1) {
/* Your algorithm goes here */
/* Time check code */
time(&now_time);
if (difftime(now_time, start_time) >= 5) {
break;
}
}
return 0;
}
This is a very simple solution that works for many cases where you know that your time check code would be called often during the execution of the algorithm. If you are unable to find a good spot where you can place the time check code such that it is called often during the execution of the algorithm, an alternate approach would be to run your algorithm in a thread and kill it when the limit exceeds.
#include <stdio.h>
#include <time.h>
#include <pthread.h>
void *algo(void *arg)
{
while (1) {
printf("I AM THE ALGO!!\n");
}
return NULL;
}
int main(int argc, char **argv)
{
time_t start_time;
time_t now_time;
pthread_t algo_thread;
int ret = pthread_create(&algo_thread, NULL, algo, NULL);
time(&start_time);
/* Time check loop */
while (1) {
time(&now_time);
if (difftime(now_time, start_time) >= 5) {
break;
}
}
return 0;
}
Since this is Linux, you might find it handy to use alarm() (provided your algorithm doesn't need any calls that might interfere with, such as sleep()). Then you can register a handler for SIGALRM using sigaction(). When the alarm pops, you'll handle the signal however you handle timeouts. Here's a minimal example how you might use it:
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
void timeout_handler (int signum) {
fprintf(stderr, "Timed out (signal:%d)!\n", signum);
exit(1);
}
int main (void) {
struct sigaction sa = { 0 };
sa.sa_handler = timeout_handler;
sigaction(SIGALRM, &sa, NULL);
alarm(5);
for (;;);
return 0;
}
This waits 5s time timeout and exit in the code above. If you want to do something other than exit, you could for example set a global value to indicate that the algorithm should exit (obviously be mindful if you're using threads).