Hi everyone
i'm trying to use sigaction() however without success
this is my code:
int main()
{
struct sigaction act, oact;
act.sa_handler = (void *)g;
sigaction(SIGVTALRM,&act,&oact);
struct itimerval tv;
tv.it_value.tv_sec = 2; //time of first timer
tv.it_value.tv_usec = 0; //time of first timer
tv.it_interval.tv_sec = 2; //time of all timers but the first one
tv.it_interval.tv_usec = 0; //time of all timers but the first one
setitimer(ITIMER_VIRTUAL, &tv, NULL);
for (;;);
}
this is g():
void g( void ){
printf("I'M NOT IN G!!");
for (;;);
}
when i run the code i get stuck in the first for(;;) loop without ever getting to g().
why don't i get to g() if i defined it as the function that handles the signal?
thank you
First, you should ensure that the input struct sigaction structure is clean:
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
act.sa_handler = g;
Then, you should suspend the process rather than use a for-loop "spin wait":
sigset_t mask;
sigprocmask(0, NULL, &mask);
sigdelset(&mask, SIGVTALRM);
sigsuspend(&mask);
Lastly, your signal-handler should be defined correctly and not use the printf() function, which is considered unsafe in the presence of signals and shouldn't be used in a signal-handler. Instead, it should set an atomic flag:
static volatile sig_atomic_t g_called;
void g(int sig) {
g_called = 1;
}
The fundamental problem is that you're using an uninitialized sigaction structure. Either initialize it with:
struct sigaction act = {0};
Or use memset to clear it before calling sigaction.
Related
I have a multi-threaded program where I have created a timer in main thread using timer_create() function. Then I set timer using timer_settime() function. When the timer expired after the timer duration it called the registered timer handler function.
Here is my code snippet:
#define CLOCKID CLOCK_REALTIME
#define SIG SIGRTMIN
int ret;
timer_t timerid;
struct sigevent sev;
struct itimerspec its;
sigset_t mask;
struct sigaction sa;
static void handler(int sig, siginfo_t *si, void *uc)
{
}
void *threadA(void *data_)
{
while(1)
{
its.it_value.tv_sec = 0;
its.it_value.tv_nsec = DELAY1;
its.it_interval.tv_sec = 0;
its.it_interval.tv_nsec = 0;
ret = timer_settime(timerid, 0, &its, NULL);
if ( ret < 0 )
perror("timer_settime");
}
}
int main(int argc, char *argv[])
{
sa.sa_flags = SA_RESTART;
sa.sa_sigaction = handler;
sigemptyset(&sa.sa_mask);
err = sigaction(SIG, &sa, NULL);
if (0 != err) {
printf("sigaction failed\n"); }
sev.sigev_notify = SIGEV_SIGNAL;
sev.sigev_signo = SIG;
sev.sigev_value.sival_ptr = &timerid;
ret = timer_create(CLOCKID, &sev, &timerid);
if ( ret < 0 )
perror("timer_create");
}
I want to know which are functions are called in kernel space , when I call timer_create(), timer_settime() function inside my C program.
Also, which kernel function is responsible to call timer handler when timer expires ?
Inside include/linux/posix-clock.h file, I found following definitions, but no definition of those functions.
/**
* struct posix_clock_operations - functional interface to the clock
* #timer_create: Create a new timer
* #timer_settime: Set a timer's initial expiration and interval
*/
struct posix_clock_operations {
struct module *owner;
int (*timer_create) (struct posix_clock *pc, struct k_itimer *kit);
int (*timer_settime)(struct posix_clock *pc,
struct k_itimer *kit, int flags,
struct itimerspec *tsp, struct
timerspec *old);
strace your program and you will see which syscalls are used.
In some cases this may depend on your libc, as kernel often offers multiple ways to achieve something.
hello what i want do is:
thread (pthread.h) need to execute code in a while loop for some period of time that will be defined at run time
after that the thread will finish correctly the last loop and continue for some other work.
right now I am using signals: This is the loop
setTimer(sec);
while(flag)
{
//do some work
}
// continue to run
and i use signal to call for function that will set flag to false:
void setTimer(int sec)
{
struct sigaction sa;
struct itimerval timer;
memset (&sa, 0, sizeof (sa));
sa.sa_handler = &alarm_end_of_loop; // this is the function to change flag to false
sigaction (SIGVTALRM, &sa, NULL);
timer.it_value.tv_sec = sec;
timer.it_value.tv_usec = 0;
timer.it_interval.tv_sec = 0;
timer.it_interval.tv_usec = 0;
setitimer (ITIMER_REAL, &timer, NULL);
}
void alarm_end_of_loop()
{
flag = 0; //flag is global but only one thread will access it
}
My question is there a way to avoid using signals?
Seems to be a timeout pattern.
double get_delta_time_to_now(const time_t timeout_time)
{
time_t now;
time(&now);
return difftime(now, timeout_time);
}
void do_it(int sec)
{
time_t timeout_time;
double diff;
time(&timeout_time);
timeout_time += sec; /* this is not necessarily correct */
diff = get_delta_time_to_now(timeout_time);
while (diff <= 0.0)
{
/* do your stuff */
diff = get_delta_time_to_now(timeout_time);
}
}
We are trying to take control from while(1) loop in three of our functions using sigaction and setitimer and problem that we are facing right now is that only once SIGALRM is generated and for the next time it is not generating ie we are able to take control from while(1) of fun1() but not from while(1) of fun2().
Could you please suggest the ways to over come this problem.Please find the code below.
#define INTERVAL 500
void fun1();
void fun2();
void fun3();
void timer_handler(int );
struct itimerval it_val;
int count=0;
void timer_handler (int signum)
{
L1:
printf(“\nScheduler Called .. Calling Fun1″);
if(count==0){
count++;
fun1();
}
printf(“\nScheduler Called .. Calling Fun2″);
if(count==1){
count++;
fun2();
}
printf(“\nScheduler Called .. Calling Fun3″);
if(count==2){
count++;
fun3();
}
count=0;
goto L1;
}
void fun1()
{
struct sigaction sa;
/* Install timer_handler as the signal handler for SIGVTALRM. */
memset (&sa, 0, sizeof (sa));
sa.sa_handler = &timer_handler;
/* Configure the timer to expire */
it_val.it_value.tv_sec = INTERVAL/1000;
it_val.it_value.tv_usec = (INTERVAL*1000) % 1000000;
it_val.it_interval.tv_sec = INTERVAL/1000;;
it_val.it_interval.tv_usec=(INTERVAL*1000) % 1000000;
/* Start a timer. It counts down whenever this process is*/
sigaction (SIGALRM, &sa, NULL);
setitimer (ITIMER_REAL, &it_val, NULL);
while (1){
printf(“\nfun1″);
}
}
void fun2()
{
struct sigaction sa;
/* Install timer_handler as the signal handler for SIGVTALRM. */
memset (&sa, 0, sizeof (sa));
sa.sa_handler = &timer_handler;
/* Configure the timer to expire */
it_val.it_value.tv_sec = INTERVAL/1000;
it_val.it_value.tv_usec = (INTERVAL*1000) % 1000000;
it_val.it_interval.tv_sec = INTERVAL/1000;;
it_val.it_interval.tv_usec=(INTERVAL*1000) % 1000000;
/* Start a timer. It counts down whenever this process is*/
sigaction (SIGALRM, &sa, NULL);
setitimer (ITIMER_REAL, &it_val, NULL);
while (1){
printf(“\nfun2″);
}
}
void fun3()
{
struct sigaction sa;
/* Install timer_handler as the signal handler for SIGVTALRM. */
memset (&sa, 0, sizeof (sa));
sa.sa_handler = &timer_handler;
/* Configure the timer to expire */
it_val.it_value.tv_sec = INTERVAL/1000;
it_val.it_value.tv_usec = (INTERVAL*1000) % 1000000;
it_val.it_interval.tv_sec = INTERVAL/1000;;
it_val.it_interval.tv_usec=(INTERVAL*1000) % 1000000;
/* Start a timer. It counts down whenever this process is*/
sigaction (SIGALRM, &sa, NULL);
setitimer (ITIMER_REAL, &it_val, NULL);
while (1){
printf(“\nfun3″);
}
}
int main(){
timer_handler(1);
return 0;
}
When a signal is delivered it is automagically masked until the action function returns.
In general you want to your signal action function to do the absolute minimum. What you have written is effectively a recursive action function with most of your program inside it. Even if it did work you would be eating stack until there was none left !
Chapter and verse: from sigaction() for POSIX:
When a signal is caught by a signal-catching function installed by
sigaction(), a new signal mask is calculated and installed for the
duration of the signal-catching function (or until a call to either
sigprocmask() or sigsuspend() is made). This mask is formed by taking
the union of the current signal mask and the value of the sa_mask for
the signal being delivered, and unless SA_NODEFER or SA_RESETHAND is
set, then including the signal being delivered. If and when the user's
signal handler returns normally, the original signal mask is restored.
Read carefully time(7) and signal(7) and signal-safety(7)
A signal handler can do very few things (it should not call, even indirectly, printf or malloc ...) Many signal handlers simply set a volatile sigatomic_t integer variable, which is later tested in the code.
I would suggest having some event loop based upon some multiplexing syscall like poll(2). You could use existing event loop frameworks (like libev, libevent, glib, etc....) or make your own above poll. The Linux specific timerfd_create(2) & signalfd(2) could help a lot.
I'm programming iwth gcc version 4.4.3 on Ubuntu 10.04
I don't know how to catch SIGALRM with sigtimedwait(),sigwait().
If timer handler is set , sigtimedwait(),sigwait() always returns EINTR(4).
If timer handler is not set, SIGALRM never received.
Is there any method to wait until task catch SIGALRM signal in intel arch?
void handler( int signo )
{
...
}
int main( void )
{
timer_t timer_id;
struct sigaction sigact;
struct itimerspec itval;
int ret;
struct timespec pTimeout;
siginfo_t pInfo;
pTimeout.tv_sec = 10;
pTimeout.tv_nsec = 0;
// set signal handler for SIGALRM
sigact.sa_handler = handler;
sigact.sa_flags = 0;
sigemptyset( &sigact.sa_mask );
sigaction( SIGALRM, &sigact, NULL );
// create timer
timer_create( CLOCK_REALTIME, NULL, &timer_id );
itval.it_value.tv_sec = 3;
itval.it_value.tv_nsec = 0;
itval.it_interval.tv_sec = 0;
itval.it_interval.tv_nsec = 250 * 1000 * 1000;
// set timer
timer_settime( timer_id, 0, &itval, NULL );
int count;
for ( count = 0; count < 10; count++ )
{
// wait for SIGALRM
ret = sigtimedwait
(
&sigact.sa_mask, /* the signal mask while suspended */
&pInfo, /* return value */
&pTimeout
);
.....
}
Is this helpful?
do {
ret = sigtimedwait(&sigact.sa_mask, &pInfo, &pTimeout);
} while (ret < 0 && errno == EINTR);
Similar question.
Some of the 'wait until a signal is received' functions are:
pause()
sigsuspend()
sigpause()
The sigpause() function is actually part of a deprecated set of functions; it is best not to use it in new code.
There is also:
sigtimedwait()
which may do what you want more directly.
I use the following code to set an alarm.
struct itimerval timer;
struct sigaction sa;
sa.sa_handler = handler;
sa.sa_flags = SA_RESETHAND;
timer.it_value.tv_usec = 0;
timer.it_value.tv_sec = 1;
timer.it_interval.tv_sec = 0;
timer.it_interval.tv_usec = 0;
sigaction(SIGALRM, &sa, 0);
setitimer(ITIMER_REAL, &timer, 0);
How do I restart the timer after it has exited the handler function and went into the while loop below. Do I need to reinitialize everything or just call setittimer?
while(pause() == -1)
{
// goes in here after handler function.. what needs to go here to restart timer?
}
Singe you use SA_RESETHAND you need to call both sigaction and setitimer again. I suggest you put it in a function so you don't have to write the code to start (or restart) the timer twice or more.