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;
}
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 descriptor 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.