Linux Timer timer

timerfd is a timer interface provided by Linux for user programs. The interface is based on file descriptors, and can be used for epoll/select through time-out notification through readable events of file descriptors. There are three main functions.

Header file: include < sys / timerfd. H >

int timerfd_create(int clockid, int flags)

Function: generate timer and return file descriptor.
clockid: CLOCK_ Mononic or CLOCK_REALTIME, where CLOCK_MONOTONIC indicates that the acquired time is the time from the system restart to the present, and changing the system time has no impact on it. CLOCK_REALTIME indicates the time from January 1, 1970 to the current time. Changing the system time will change the obtained value.
flags: TFD_ Nonblock, TFD_ Cloexec (same as O_CLOEXEC).
return: file descriptor of timer.

int timerfd_settime(int tfd, int flags, const struct itimerspec *newValue, struct itimerspec *oldValue)

Function: used to start or close the specified fd timer.
tfd: timerfd, by timerfd_ The create function returns.
flags: 1 indicates that the absolute time is set; 0 indicates relative time.
newValue: specify a new timeout, if newValue.it_ If value is not 0, start the timer, otherwise close the timer. If newValue.it_ If interval is 0, the timer is timed only once, otherwise it will timeout every set time.
oldValue: if it is not NULL, the timeout time before the timer is set this time is returned.
return: returns - 1 if failed.

struct timespec
{
time_t tv_sec; // second
long tv_nsec; // nanosecond
}
struct itimerspec
{
struct timespec it_interval; // Every it after the first timeout_ Interval timeout once
struct timespec it_value; // First timeout
}

int timerfd_gettime(int fd, struct itimerspec *curValue)

Function: used to obtain the time left until the next timeout. If the timer has expired (i.e. it_value time is exceeded) and the timer is in circular mode (i.e. it_interval is not 0), the timer starts timing again after calling this function.
fd: timerfd, by timerfd_ The create function returns.
curValue: returns the time remaining until the next timeout.
return: return - 1 if failed

Read timerfd

When the timer times out, the timerfd is readable and returns Uint64_ An integer of type T, which is the number of timeouts (the number of timeouts unread). If the timer does not have a timeout event, if timerfd is blocked, read will be blocked. If timerfd is non blocked, EAGAIN error will be returned. If the read yes data is less than 8 bytes, an EINVAL error is returned.


Sample code

#include <sys/timerfd.h>  
#include <sys/epoll.h>
#include <unistd.h>
#include <stdint.h>
#include <iostream>
using namespace std;

const int EPOLL_SIZE = 10;

int main(int argc, char* argv[])
{
    int tfd, epfd, nfds;
    struct epoll_event event;
    struct epoll_event events[EPOLL_SIZE];
        
    //Create timerfd, CLOCK_REALTIME is absolute time, TFD_NONBLOCK is non blocking
    tfd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK);  
    if (tfd < 0)
    {
        cerr << "timerfd_create error!" << endl;
        return -1;
    }   
    struct timespec startTime, intervalTime;
    startTime.tv_sec = 0;    
    startTime.tv_nsec = 1;                                //Equivalent to immediate arrival timeout
    intervalTime.tv_sec = 3;                             //After the first timeout, timeout every three seconds
    intervalTime.tv_nsec = 0;
    struct itimerspec newValue;
    newValue.it_value = startTime;
    newValue.it_interval = intervalTime;
    //Set the timeout, which is a relative time
    if (timerfd_settime(tfd, 0, &newValue, NULL) < 0)
    {
        cerr << "timerfd_settime error!" << endl;
        return -1;
    }
    //Use epoll to listen for descriptors
    epfd = epoll_create(EPOLL_SIZE);
    if (epfd < 0)
    {
        cerr << "epoll_create error!" << endl;
        return -1;
    }

    event.data.fd = tfd;
    event.events = EPOLLIN;
    if (epoll_ctl(epfd, EPOLL_CTL_ADD, tfd, &event) < 0)
    {
        cerr << "epoll_ctl error!" << endl;
        return -1;
    }
    
    uint64_t count = 0;
    while (1)
    {
        //Non blocking wait
        nfds = epoll_wait(epfd, events, EPOLL_SIZE, 0);
        if (nfds == 0) continue;
        for (int i = 0; i < nfds; i++)
        {
            if (events[i].events & EPOLLIN)
            {
                uint64_t data;
                read(events[i].data.fd, &data, sizeof(uint64_t));
                count += data;
                cout << "read: " << data << ", timer count: " << count << endl;
            }
        }
    }
    return 0;
}

Tags: Linux Operation & Maintenance server

Posted on Sun, 31 Oct 2021 07:09:10 -0400 by J-C