LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Newbie (https://www.linuxquestions.org/questions/linux-newbie-8/)
-   -   Use several timers with setitimer() (https://www.linuxquestions.org/questions/linux-newbie-8/use-several-timers-with-setitimer-797509/)

webquinty 03-24-2010 05:39 AM

Use several timers with setitimer()
 
Hello,

I would like to use several timers with setitimer, but I have a problem.
setitimer() with ITIMER_REAL, send always SIGALRM.

Example:

Code:

#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

unsigned int valor1;

void logoff_signal (int i)
{
        struct timeval now;
        gettimeofday(&now, NULL);

        printf("Ejecutado timer logoff %ld seg- %ld usec\n",
                        now.tv_sec, now.tv_usec);
}

void hibernate_signal (int i)
{
        struct timeval now;
        gettimeofday(&now, NULL);

        printf("Ejecutado timer hibernate %ld seg- %ld usec\n",
                        now.tv_sec, now.tv_usec);
        valor1++;
}

int main (void)
{
        valor1 = 0;

        struct timeval now;
        gettimeofday(&now, NULL);

        printf("Prueba de timers Linux. %ld seg- %ld usec\n",
                        now.tv_sec, now.tv_usec);

        struct itimerval logoff, hibernate;

        logoff.it_value.tv_sec = 5;
        logoff.it_value.tv_usec = 0;
        logoff.it_interval.tv_sec = 1;
        logoff.it_interval.tv_usec = 0;

        hibernate.it_value.tv_sec = 5;
        hibernate.it_value.tv_usec = 0;
        hibernate.it_interval.tv_sec = 1;
        hibernate.it_interval.tv_usec = 0;

        setitimer(ITIMER_REAL, &logoff, 0);
        signal(SIGALRM, logoff_signal);

        setitimer(ITIMER_REAL, &hibernate, 0);
        signal(SIGALRM, hibernate_signal);

        while(valor1 < 10);

        printf("Prueba de timers Linux finalizada.\n");

        return 0;
}

In this example, I configure two timers, but setitimer use SIGALRM, so only one timer will execute, the last one (hibernate).

Is there other way to use several timers??

Best reagards.

codedr 04-02-2010 10:34 PM

You can only set one timer with ITIMER_REAL.

What you will need to do is create a linked list with your timer timeout
info inside of it. Like this;

struct timeout {
struct timeout *next, *prev;
int diff; // num of secs til next timeout
void *(func)(); // callback func
};

struct timeout *timerlist = NULL;

void
callback_timeout(int i)
{
// walk items on timerlist
// first item is timer that this popped for
// reset timer for next item in list
// callback func for this timeout
}

int
register_timeout(int when, void *(what)())
// when : in secs to timeout
// what : callback func
{
struct timeout *pto = (struct timeout *) malloc(sizeof(struct timeout));
struct timeout *iter;
pto->diff = when;
pto->func = what;

sigblock(SIGALRM); // don't bother me while i'm adding to the list

if (NULL == timerlist) {
pto->next = pto->prev = pto;
timerlist = pto;
itimer.it_value.tv_sec = pto->diff;
itimer.it_value.tv_usec = 0;

// set timer for first time
setitimer(ITIMER_REAL, &itimer, 0);
signal(SIGALRM, callback_timeout);
sigunblock(SIGALRM);
return 0;
}

iter = timerlist;
do {
if (pto->diff > iter->diff) { // bigger that current
pto->diff = pto->diff - iter->diff;
iter = iter->next;
} else { // eq or less than
// insert at front
// decrement diff from every member in list
pto->prev = iter->prev;
pto->next = iter;
iter = pto->prev->next = pto;
if (iter == timerlist)
timerlist = pto;
iter->diff = iter->diff - pto->diff;

// set timer for new time
itimer.it_value.tv_sec = pto->diff;
itimer.it_value.tv_usec = 0;
setitimer(ITIMER_REAL, &itimer, 0);
signal(SIGALRM, callback_timeout);
sigunblock(SIGALRM);
return 0;
}
} while (iter != timerlist);

// at end of list
pto->diff = pto->diff - timerlist->prev->diff;
timerlist->prev->next = pto;
pto->prev - timerlist->prev;
pto->next = timerlist;

// timer already running
sigunblock(SIGALRM);
return 0;
}


All times are GMT -5. The time now is 09:38 AM.