Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

epoll with timerfd

Tags:

linux

timer

epoll

I want to use the it_interval of newValue to set the interval of the timeout.
But in my example, I can only print timeout once.
What happened? How can I set the interval?

This is my code:

int main()
{
int efd =epoll_create(256);             
setnonblock(efd);
struct epoll_event ev,events[256];

int tfd;//timer fd

if((tfd= timerfd_create(CLOCK_MONOTONIC,TFD_NONBLOCK)) < 0)
  cout<<"timerfd create error"<<endl;

struct itimerspec newValue;
struct itimerspec oldValue;
bzero(&newValue,sizeof(newValue));  
bzero(&oldValue,sizeof(oldValue));
struct timespec ts;
ts.tv_sec = 5;
ts.tv_nsec = 0;

    //both interval and value have been set
    newValue.it_value = ts; 
    newValue.it_interval = ts;
    if( timerfd_settime(tfd,0,&newValue,&oldValue) <0)
    {
        cout<<"settime error"<<strerror(errno)<<endl;
    }   

    ev.data.fd = tfd;
    ev.events = EPOLLIN | EPOLLET;

    if( epoll_ctl(efd,EPOLL_CTL_ADD,tfd,&ev) < 0)
        cout<<"epoll_ctl error"<<endl;

    int num = 0;
    while(1)
    {
       if((num=epoll_wait(efd,events,256,1000)) > 0)
       {//justice
            for(int i=0;i<num;i++)
            {
                if(events[i].data.fd == tfd)
                {
                    cout<<"timeout"<<endl;
                }
        }       
    }
    }   
return 0;
}
like image 459
Tengchao Avatar asked Aug 24 '12 03:08

Tengchao


People also ask

What is Timerfd?

eventfd file descriptors and timerfd file descriptors have compatible behavior when read is called on them. Thus, one can be substituted for the other without an application knowing, assuming it only calls read .

What is Epoll_wait?

The epoll_wait() system call waits for events on the epoll(7) instance referred to by the file descriptor epfd. The buffer pointed to by events is used to return information from the ready list about file descriptors in the interest list that have some events available. Up to maxevents are returned by epoll_wait().


1 Answers

It is because you are using EPOLLET and not read()ing the data produced into the tfd. The expiration of a timer "writes" 8 bytes of data that need to be read: you really need to read it. Add this when you print "timeout":

uint64_t value;
read(tfd, &value, 8);

In more details: EPOLLET asks for Edge Triggering, which means that epoll_wait() will say only once "data is ready for input" on the file descritor tfd until you read that data. In other words, as long as you didn't read that data, future calls to epoll_wait() will not return the same descriptor again. This behavior is useful with normal sockets, e.g. if you do epoll_wait() in the main thread, notice some data is ready, then fire up another thread to read it. The main thread goes immediately back to epoll_wait(). But we don't want it to wake up immediately again, even though the data from the file descriptor was probably not read yet.

Note that I guess your example without EPOLLET would be wrong too, differently: because you don't read(), the tfd is always readable after the initial delay, and so it would print "timeout" as fast as possible after the initial delay expires.

like image 105
Armin Rigo Avatar answered Sep 22 '22 12:09

Armin Rigo