UPGRADE YOUR BROWSER

We have detected your current browser version is not the latest one. Xilinx.com uses the latest web technologies to bring you the best online experience possible. Please upgrade to a Xilinx.com supported browser:Chrome, Firefox, Internet Explorer 11, Safari. Thank you!

cancel
Showing results for 
Search instead for 
Did you mean: 
Explorer
Explorer
5,377 Views
Registered: ‎02-18-2014

Linux Timer's

Hey all,

 

This is more a linux question then a xilinx question. I am attempting to run the linux timers that have been suggested for me because my application requires a few wakeup calls every 10-20ish ms. The application does not need to be real time but needs to be accurate enough to be within a 60ms window. I've been pointed to timerfd and select as strong canidates to fullfill this requirement. I wrote the below code to test having 2 seperate timers running independently but it doesn't appear to work as i intended. Any ideas what little thing im doing wrong?

 

A brief description of what i want to happen is every 10ms timer1 to increment count. Then every 2 seconds timer2 to print out the value of count. Unfortunatly what appears to be happening is every time timer1 increments, then timer2 prints out 'count: 1". Timer2 doesn't wait the 2seconds. Also is there anything in the build image i need to include to support this functionality? Im using 2014.1 sdk on a zc702 dev board.

 

Thanks!

 

#include <sys/timerfd.h>
#include <sys/select.h>
#include <stdint.h> //u64
#include <assert.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h> //bzero

void fd_timer();

int max_fd = 10;
unsigned int count = 0;

int main()
{
    fd_timer();

    return 0;
}

int
safe_fd_set(int fd, fd_set* fds, int* max_fd)
{
    assert(max_fd != NULL);

    FD_SET(fd, fds);
    if (fd > *max_fd) {
        *max_fd = fd;
    }
    return 0;
}


void handle_timer_1()
{
    count++;
}

void handle_timer_2()
{
    printf("count: %d\n", count);
    count = 0;
}

void fd_timer()
{
    printf("timer test\n");

    int timerfd = timerfd_create(CLOCK_MONOTONIC,0);
    int timerfd2 = timerfd_create(CLOCK_MONOTONIC,0);

    struct timeval timeout;
    timeout.tv_sec = 10;
    timeout.tv_usec = 0;

    struct itimerspec timspec;
    bzero(&timspec, sizeof(timspec));
    timspec.it_interval.tv_sec = 0;
    timspec.it_interval.tv_nsec = 10000000;
    timspec.it_value.tv_sec = 0;
    timspec.it_value.tv_nsec = 1;

    struct itimerspec timespec2;
    bzero(&timespec2, sizeof(timespec2));
    timespec2.it_interval.tv_sec = 2;
    timespec2.it_interval.tv_nsec = 0;
    timespec2.it_value.tv_sec = 1;
    timespec2.it_value.tv_nsec = 1;

    timerfd_settime(timerfd, 0, &timspec, 0);
    timerfd_settime(timerfd2, 0, &timespec2, 0);

    fd_set master; // create master fd list
    FD_ZERO(&master); // clear out current master fd list

    safe_fd_set(timerfd2, &master, &max_fd);
    safe_fd_set(timerfd, &master, &max_fd);

    int select_val = 0;

    while (1)
    {
        select_val = select(max_fd+1, &master, NULL, NULL, &timeout);

        if (select_val <= 0)
        {
            printf("select timed out\n");
            break;
        }


        int index;
        for (index = 0; index <= max_fd; index++)
        {
            if (FD_ISSET(index, &master))
            {
                if (index == timerfd2)
                {
                    handle_timer_2();
                }
                if (index == timerfd)
                {
                    handle_timer_1();
                }
            }
        }
    }
}

0 Kudos
2 Replies
Scholar milosoftware
Scholar
5,351 Views
Registered: ‎10-26-2012

Re: Linux Timer's

What an interesting way to implement a timer, never seen it before.

 

If your program already has a select (or poll) loop, you can use the "timeout" argument of that call to implement any number of timers you need. That is what GUI frameworks tend to do. It's much more resource friendly too.

 

Just retrieve the current time, calculate the time left to the next timer event, and use that as your timeout argument. Alternatively, you could use condition_timed_wait to do the wait-for-event-or-timeout implementation.

0 Kudos
Explorer
Explorer
5,345 Views
Registered: ‎02-18-2014

Re: Linux Timer's

Thanks Milo for the response,

 

I finally got the timer's to work dependably. Below was the solution that i found:

 

#include <sys/timerfd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/epoll.h>
#include <fcntl.h>


#define MAXPOLLSIZE 64
unsigned int count = 0;

int main()
{
        int epoll_fd; //
        int timer_fd;
        int timer_fd2;
        struct epoll_event epoll_events[MAXPOLLSIZE]; // master list of events

        int i;
        struct itimerspec timer_value;
        struct itimerspec timer_value2;
        uint64_t expirations;

        /* Creates an epoll instance.   */
        epoll_fd=epoll_create(MAXPOLLSIZE);

        /* Return file descriptor for new interval timer instance.         */
        timer_fd=timerfd_create(CLOCK_MONOTONIC, 0);
        timer_fd2=timerfd_create(CLOCK_MONOTONIC, 0);

        /*****************Add timer1 to epoll event array**********************/
        static struct epoll_event ev_timer1;
        ev_timer1.events=EPOLLIN;
        ev_timer1.data.fd=timer_fd;
        epoll_ctl(epoll_fd, EPOLL_CTL_ADD, timer_fd, &ev_timer1);
        /**********************************************************************/

        /*****************Add timer2 to epoll event array**********************/
        static struct epoll_event ev_timer2;
        ev_timer2.events=EPOLLIN;
        ev_timer2.data.fd=timer_fd2;
        epoll_ctl(epoll_fd, EPOLL_CTL_ADD, timer_fd2, &ev_timer2);
        /**********************************************************************/


        //initialize timer timeout
        timer_value.it_value.tv_sec = 5; // ( 5s periodic timeout)
        timer_value.it_value.tv_nsec = 0;
        timer_value.it_interval.tv_sec = 5; // (5s initial timeout) - if both initial values are set to 0 this disables the timer
        timer_value.it_interval.tv_nsec = 0;

        timer_value2.it_value.tv_sec = 0;
        timer_value2.it_value.tv_nsec = 10000000; // (10ms periodic timeout)
        timer_value2.it_interval.tv_sec = 0;
        timer_value2.it_interval.tv_nsec = 10000000; // (10ms initial timeout)

        timerfd_settime(timer_fd, 0, &timer_value, NULL);
        timerfd_settime(timer_fd2, 0, &timer_value2, NULL);

        int fd;
        int number_of_fds; // represents the number of fd's currently being monitored

        while (1)
        {
            /*
             * \brief epoll_wait: waits for I/O events, blocking the calling thread if no events are currently available
             */
            number_of_fds=epoll_wait(epoll_fd, epoll_events, MAXPOLLSIZE, -1);

            for (i=0; i<number_of_fds; i++)
            {
                // returns fd referencing to current event
                fd=epoll_events[i].data.fd;

                // Is the fd for current event this timer?
                if ( fd == timer_fd )
                {
                    read(timer_fd, &expirations, sizeof(uint64_t));
                    fprintf(stdout, "count: %d\n", count);
                    count = 0;
                }
                if (fd == timer_fd2)
                {
                    read(timer_fd2, &expirations, sizeof(uint64_t));
                    count++;
                }
            }
        }
        return 0;
}

0 Kudos