Aditya Jha
Aditya Jha

Reputation: 69

How to implement 2 timers in linux

I m trying to set the flag variable on(working with raspbery pi. I need pin on) for 500 useconds(micro seconds) and flag off for 300 useconds continuously(infinitely until I stop it). I thought of implementing it using 2 timers.

Now In this program i have written for 5 seconds and 3 seconds.

#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include <unistd.h>

struct sigaction sa;
struct itimerval timer1,timer2;
 int count=1;
void timer_handler (int signum)
{
 if(count++%2==1)
    printf("High\n"); //flag=1
 else  
    printf("Low\n");   //flag=0
}

 int main ()
{


 /* Install timer_handler as the signal handler for SIGVTALRM. */
 memset (&sa, 0, sizeof (sa));
 sa.sa_handler = &timer_handler;
 sa.sa_flags = SA_RESTART;
 sigaction (SIGALRM, &sa, NULL);


 int i=0;
 while(1){
    scanf(" %d",&i);
    if(i==1){  // I m starting 2 timers here 
 timer1.it_value.tv_sec = 0;
 timer1.it_value.tv_usec = 1;
 timer1.it_interval.tv_sec = 8; //5+3
 timer1.it_interval.tv_usec = 0;

 timer2.it_value.tv_sec = 5;
 timer2.it_value.tv_usec = 0;
 timer2.it_interval.tv_sec = 8;
 timer2.it_interval.tv_usec = 0;
 setitimer (ITIMER_REAL, &timer1, NULL);
  setitimer (ITIMER_REAL, &timer2, NULL);
 }
 else if(i==2)  // I m stopping here 
 {
    timer1.it_value.tv_sec = 0;
 timer1.it_value.tv_usec = 0;
 timer1.it_interval.tv_sec = 0;
 timer1.it_interval.tv_usec = 0;

 timer2.it_value.tv_sec = 0;
 timer2.it_value.tv_usec = 0;
 timer2.it_interval.tv_sec = 0;
 timer2.it_interval.tv_usec = 0;
 setitimer (ITIMER_REAL, &timer1, NULL);   // 1st timer on
  setitimer (ITIMER_REAL, &timer2, NULL);  //2nd timer on 

 }
}
}

This is code I have written. what actually happening is the second timer is running and first timer is not running. I think its overwritten.

Ps. I dont want to use sleep function as it takes more time. I m using timers as the resolution is microsecond.

1.How do I do this using two timers?
2.Is there any better method to do this task?

Upvotes: 1

Views: 512

Answers (1)

user2371524
user2371524

Reputation:

There is only one ITIMER_REAL, so you must create virtual timers yourself. A simple and reliable possibility if you don't need microsecond precision, is to use a periodic timer with a small interval and implement your virtual timers on top of that (so every "tick" from your periodic timer will decrement your virtual timers).

Following an example how you could implement it:

vtimer.h

#ifndef VTIMER_H
#define VTIMER_H

typedef void (vtimer_timeout)(void *arg);

typedef struct vtimer
{
    int msec;
    int periodic;
    int current;
    vtimer_timeout *timeout;
} vtimer;

#define vtimer_init(m, p, cb) { \
    .msec=(m), .periodic=(p), .current=0, .timeout=cb}

void vtimer_start(vtimer *self, void *timeoutArg);
void vtimer_stop(vtimer *self);

// call this periodically, e.g. after each interrupted library call:
void vtimer_dispatch();

#endif

vtimer.c

#define _POSIX_C_SOURCE 200101L

#include "vtimer.h"

#include <stddef.h>
#include <signal.h>
#include <sys/time.h>

#define NUM_TIMERS 8

static vtimer *timers[NUM_TIMERS] = {0};
static void *timoutArgs[NUM_TIMERS] = {0};

static size_t ntimers = 0;

static volatile sig_atomic_t ticks = 0;

static void tickhandler(int signum)
{
    (void)signum;
    ++ticks;
}

static struct sigaction timerAction = {.sa_handler = tickhandler};
static struct sigaction defaultAction;
static struct itimerval tickTimerval = {{0, 1000}, {0, 1000}};
static struct itimerval disableTimerval = {{0,0},{0,0}};

void vtimer_start(vtimer *self, void *timeoutArg)
{
    int found = 0;
    for (size_t idx = 0; idx < NUM_TIMERS; ++idx)
    {
        if (timers[idx] == self)
        {
            found = 1;
            break;
        }
    }

    if (!found)
    {
        if (ntimers == NUM_TIMERS) return; // or maybe return error
        if (!ntimers++)
        {
            // only start the "ticking" timer when necessary
            sigaction(SIGALRM, &timerAction, &defaultAction);
            setitimer(ITIMER_REAL, &tickTimerval, 0);
        }
        for (size_t idx = 0; idx < NUM_TIMERS; ++idx)
        {
            if (!timers[idx])
            {
                timers[idx] = self;
                timoutArgs[idx] = timeoutArg;
                break;
            }
        }
    }
    self->current = self->msec;
}

void vtimer_stop(vtimer *self)
{
    int found = 0;
    for (size_t idx = 0; idx < NUM_TIMERS; ++idx)
    {
        if (timers[idx] == self)
        {
            timers[idx] = 0;
            found = 1;
            break;
        }
    }

    if (found && !--ntimers)
    {
        // no virtual timers running -> stop ticking timer
        setitimer(ITIMER_REAL, &disableTimerval, 0);
        sigaction(SIGALRM, &defaultAction, 0);
    }
}

void vtimer_dispatch(void)
{
    while (ticks)
    {
        --ticks;
        for (size_t idx = 0; idx < NUM_TIMERS; ++idx)
        {
            if (timers[idx])
            {
                if (!--(timers[idx]->current))
                {
                    timers[idx]->timeout(timoutArgs[idx]);
                    if (timers[idx]->periodic)
                    {
                        timers[idx]->current = timers[idx]->msec;
                    }
                    else vtimer_stop(timers[idx]);
                }
            }
        }
    }
}

Example program using this:

#include "vtimer.h"

#include <stdio.h>
#include <errno.h>

static void timer1_timeout(void *arg)
{
    (void) arg;
    puts("timer 1");
}

static void timer2_timeout(void *arg)
{
    (void) arg;
    puts("timer 2");
}

int main(void)
{
    vtimer timer1 = vtimer_init(5000, 1, timer1_timeout);
    vtimer timer2 = vtimer_init(8000, 1, timer2_timeout);

    vtimer_start(&timer1, 0);
    vtimer_start(&timer2, 0);

    for (;;)
    {
        errno = 0;
        int c = getchar();
        if (c == EOF && errno != EINTR) break;
        if (c == 'q') break;
        vtimer_dispatch();
    }

    vtimer_stop(&timer2);
    vtimer_stop(&timer1);
    return 0;
}

There are a lot of design decisions on the way (e.g. how frequent your ticks should be (here 1ms), having a fixed number of virtual timers vs a dynamic one, using pointers as "timer handles" or maybe integers, and so on), so think about what you need and try to write your own.

Upvotes: 1

Related Questions