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;
}
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;
}
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 am running the following program which implements a timer. When a thread awake after receiving a signal on condition variable from the previous running thread, it creates a timer and send a signal to the next thread on timer expiration. I want it to run for some time, but the timer stops ticking after some runs.
//Import
#define _POSIX_C_SOURCE 199309
#include <sched.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
#include <signal.h>
#include <errno.h>
#define NUM_THREADS 10
#define CLOCKID CLOCK_REALTIME
#define SIG SIGUSR1
timer_t timerid;
pthread_cond_t condA[NUM_THREADS+1] = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_t tid[NUM_THREADS];
int state = 0;
static void handler(int sig, siginfo_t *si, void *uc)
{
if(si->si_value.sival_ptr != &timerid){
printf("Stray signal\n");
} else {
//printf("Caught signal %d from timer\n", sig);
}
pthread_cond_signal(&condA[state]);
}
void *threadA(void *data_)
{
int i = 0, s;
long int loopNum, j;
int turn = (intptr_t)data_;
struct timeval tval_result;
// Timer's part starts
struct sigevent sev;
struct itimerspec its;
long long freq_nanosecs;
sigset_t mask;
struct sigaction sa;
// TImer'spart ends
while(1)
{
/* Wait for state A */
pthread_mutex_lock(&mutex);
for (;state != turn;)
{
s = pthread_cond_wait(&condA[turn], &mutex);
if (s != 0)
perror("pthread_cond_wait");
// printf("main(): state = %d\n", state);
}
pthread_mutex_unlock(&mutex);
//do stuff
for(j=0;j<10000;j++)
{//some dummy time consuming works}
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = handler;
sigemptyset(&sa.sa_mask);
sigaction(SIG, &sa, NULL);
sev.sigev_notify = SIGEV_SIGNAL;
sev.sigev_signo = SIG;
sev.sigev_value.sival_ptr = &timerid;
timer_create(CLOCKID, &sev, &timerid);
/* Start the timer */
its.it_value.tv_sec = 0;
its.it_value.tv_nsec = 2000;
its.it_interval.tv_sec = 0;
its.it_interval.tv_nsec = 0;
timer_settime(timerid, 0, &its, NULL);
pthread_mutex_lock(&mutex);
state = (state +1)%NUM_THREADS;
//pthread_cond_signal(&condA[state]);
pthread_mutex_unlock(&mutex);
// Timer's code ends
}
}
int main(int argc, char *argv[])
{
int data = 0;
int err;
while(data < NUM_THREADS)
{
//create our threads
err = pthread_create(&tid[data], NULL, threadA, (void *)(intptr_t)data);
if(err != 0)
printf("\ncan't create thread :[%s]", strerror(err));
else
// printf("\n Thread created successfully\n");
data++;
}
pthread_exit(NULL);
}
Although no printf statements are executing, why is it freezing after some time?
If no. of timers are limited, what other strategy should I use to redress this issue?
POSIX says:
It is not safe to use the pthread_cond_signal() function in a signal handler that is invoked asynchronously.
Most likely you end up corrupting the state of pthread_cond_wait/pthread_cond_signal and anything can happen.
Don't mix threads and signal handlers, it leads only to madness. There are very few things you're allowed to do inside a signal handler, even fewer that are thread related, it's very hard to ensure that the right thread ends up handling the right signal, etc.
If you're doing threads anyway implement a timer in one thread that calculates how much time it needs to sleep to deliver the next event (don't just hardcode it to your timer period since that will make your timer drift), sleep that much and call pthread_cond_signal.
Also, it's bad form to have naked pthread_cond_signal calls and most often a bug. You might get unlucky and call it just before the other thread does the pthread_cond_wait and your signal will get lost. The normal thing to do is to set a variable (protected by a mutex, that's why pthread_cond_signal wants a mutex) and then signal that the variable is set.
If you think this is too much work, condition variables are probably not the right mechanism in this case and you should use semaphores instead. Incidentally sem_post is legal to call from a signal handler according to POSIX, but I still think it's a bad idea to mix threads with signals.
I'm trying to use the signal SIGRTMIN, in order to do_stuff when it gives me permission. It's my first time working with signals. The problem is that I'm stuck in
while (go == 0){printf("Waiting\n");}
This is my code:
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
volatile sig_atomic_t go = 0;
void handler (int sig)
{
go = 1;
signal (sig, handler);
}
void do_stuff (void)
{
puts ("Doing stuff while waiting for alarm....");
}
int main (void)
{
int i=0;
signal (SIGRTMIN, handler);
while(i<5){
while (go == 0){printf("Waiting\n");}
do_stuff();
i++;
}
return EXIT_SUCCESS;
}
Can you help? Thanks in advance!
You need to get the SIGRTMIN signals sent from somewhere; it won't respond to the signal until it is sent. The simplest thing is to have it send itself signals, so here's a mildly revised version of your code.
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#ifndef SIGRTMIN
#define SIGRTMIN SIGUSR1
#endif
volatile sig_atomic_t go = 0;
static
void handler(int sig)
{
go = 1;
signal(sig, handler);
}
static
void do_stuff(void)
{
puts("Doing stuff while waiting for alarm....");
go = 0;
}
int main(void)
{
signal(SIGRTMIN, handler);
for (int i = 0; i < 5; i++)
{
while (go == 0)
{
puts("Waiting...");
struct timespec t = { .tv_sec = 0, .tv_nsec = 300000000 };
nanosleep(&t, 0);
kill(getpid(), SIGRTMIN);
}
do_stuff();
}
return EXIT_SUCCESS;
}
Example run:
Waiting...
Doing stuff while waiting for alarm....
Waiting...
Doing stuff while waiting for alarm....
Waiting...
Doing stuff while waiting for alarm....
Waiting...
Doing stuff while waiting for alarm....
Waiting...
Doing stuff while waiting for alarm....
Not very exciting output, but it is at least working. The nanosleep() sleeps for 0.3 seconds.
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).