1. eventfd/timerfd 简介
目前越来越多的应用程序采用事件驱动的方式实现功能,如何高效的利用系统资源实现通知的管理的送达就愈发变得重要起来。在Linux系统中,eventfd
是一个用来通知事件的文件描述符,timerfd
是定时器事件的文件描述符。二者都是内核向用户空间的应用发送通知的机制,可以有效地被用来实现用户空间的事件/通知驱动的应用程序。
简而言之,就是eventfd用来触发事件通知,timerfd用来触发将来的事件通知。
2. 接口及参数介绍
eventfd:
对于eventfd,只有一个系统调用接口:
int eventfd(unsigned int initval, int flags);
创建一个eventfd对象,或者说打开一个eventfd的文件,类似普通文件的open操作。
该对象是一个内核维护的无符号的64位整型计数器。初始化为initval的值。
flags可以以下三个标志位的OR结果:
- EFD_CLOEXEC:文件被设置成 O_CLOEXEC,创建子进程 (fork) 时不继承父进程的文件描述符。
- EDF_NONBLOCK:文件被设置成 O_NONBLOCK,执行 read/write 操作时,不会阻塞。
- EFD_SEMAPHORE:提供类似信号量语义的 read 操作,简单说就是计数值 count 递减 1。
timerfd:
对于timerfd,有三个涉及的系统调用接口:
//timerfd 创建
int timerfd_create(int clockid, int flags);
//timerfd 设置时间
int timerfd_settime(int fd, int flags,const struct itimerspec *new_value,struct itimerspec *old_value);
//timerfd 获取时间
int timerfd_gettime(int fd, struct itimerspec *curr_value);
timerfd_create
就是用来创建新的timerfd
对象,clockid
可以指定时钟的种类,比较常用的有两种:CLOCK_REALTIME
(实时时钟)或 CLOCK_MONOTONIC
(单调递增时钟)。实时时钟是指系统的时钟,它可以被手工修改。而后者以固定的速率运行,从不进行调整和复位,它不受任何系统time-of-day时钟修改的影响。通常选择后者。而flags的选择,TFD_CLOEXEC
和 TFD_NONBLOCK
的意义就比较直接了。
timerfd_settime:用来启动或关闭有 fd 指定的定时器
struct timespec {
time_t tv_sec; /* Seconds */
long tv_nsec; /* Nanoseconds */
};
struct itimerspec {
struct timespec it_interval; /* Interval for periodic timer */
struct timespec it_value; /* Initial expiration */
};
第二个结构体 itimerspec
就是 timerfd 要设置的超时结构体,它的成员 it_value
表示定时器第一次超时时间,it_interval表示之后的超时时间即每隔多长时间超时。
当定时器超时,read读事件发生即可读,返回超时次数(从上次调用timerfd_settime()启动开始或上次read成功读取开始),它是一个8字节的unit64_t类型整数,如果定时器没有发生超时事件,则read将阻塞若timerfd为阻塞模式,否则返回EAGAIN 错误(O_NONBLOCK模式),如果read时提供的缓冲区小于8字节将以EINVAL错误返回。