Linux的timerfd分析

来源:互联网 发布:淘宝域名注册 编辑:程序博客网 时间:2024/04/28 08:18

timerfd是Linux为用户程序提供的一个定时器接口。这个接口基于文件描述符,所以能够被用于select/poll的应用场景。

1.      使用方法

timerfd提供了如下接口供用户使用

timerfd_create

int timerfd_create(int clockid, int flags);

timerfd_create用于创建一个定时器文件。

参数clockid可以是CLOCK_MONOTONIC或者CLOCK_REALTIME。

参数flags可以是0或者O_CLOEXEC/O_NONBLOCK。

函数返回值是一个文件句柄fd。

timerfd_settime

int timerfd_settime(int ufd, int flags, const struct itimerspec * utmr, struct itimerspec * otmr);

此函数用于设置新的超时时间,并开始计时。

参数ufd是timerfd_create返回的文件句柄。

参数flags为1代表设置的是绝对时间;为0代表相对时间。

参数utmr为需要设置的时间。

参数otmr为定时器这次设置之前的超时时间。

函数返回0代表设置成功。

timerfd_gettime

int timerfd_gettime(int ufd, struct itimerspec * otmr);

此函数用于获得定时器距离下次超时还剩下的时间。如果调用时定时器已经到期,并且该定时器处于循环模式(设置超时时间时struct itimerspec::it_interval不为0),那么调用此函数之后定时器重新开始计时。

read

当timerfd为阻塞方式时,read函数将被阻塞,直到定时器超时。

函数返回值大于0,代表定时器超时;否则,代表没有超时(被信号唤醒,等等)。

poll/close

poll,close与标准文件操作相同。

2.      内核实现

timerfd的内核实现代码在kernel/fs/timerfd.c,它的实现基于Linux的hrtimer。

timerfd_create的实现

SYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags)

l         做一些定时器的初始化工作

l         调用hrtimer_init初始化一个hrtimer

l         调用anon_inode_getfd分配一个dentry,并得到一个文件号fd,同时传入timerfd的文件操作指针struct file_operations timerfd_fops。anno_inode_getfd是文件系统anon_inodefs的一个帮助函数。anon文件系统比较简单,整个文件系统只有一个inode节点,其实现代码可以在fs/anon_inodes.c中找到。

timerfd_settime的实现

timerfd_settime最终会调用hrtimer_start启动定时器,其超时函数被设置为timerfd_tmrproc。

timerfd_tmrproc

timefd_tmrproc是timerfd的定时器超时函数。在timerfd超时时,该函数会设置定时器超时标记位;增加定时器超时次数(在设置定时器循环模式时,可能会出现多次超时没有被处理的情况);唤醒一个等待队列,从而唤醒可能存在的正被阻塞的read、select。

timerfd_fops

static const struct file_operations timerfd_fops = {

       .release    = timerfd_release,

       .poll        = timerfd_poll,

       .read              = timerfd_read,

};

timerfd_read函数是文件操作read的内核实现,读到的是定时器的超时次数。该函数在阻塞模式下会把自身挂到timerfd的等待队列中,等待定时器超时时被唤醒。

timerfd_poll将timerfd的等待队列登记到一个poll_table,从而在定时器超时时能唤醒select系统调用。

timerfd_release

timerfd_release函数释放timerfd_create函数中申请的资源,删除已分配的定时器。


struct timeval 和 struct timespec

timeval

  DESCRIPTION 
  The functions gettimeofday and settimeofday can get and set the time as 
  well as a timezone. The tv argument is a timeval struct, as specified in <sys/time.h>: 

       struct timeval { 
        time_t tv_sec; /* seconds */ 
        suseconds_t tv_usec; /* microseconds */ 
  }; 
        其中返回的timeval值为Epoch(00:00:00 1970-01-01 UTC)到创建struct timeval时的时间,tv_sec为秒数部分,tv_usec为微秒数部分(10的-6次方秒)。比如当前程序运行的tv_sec1244770435tv_usec442388,即当前时间距Epoch时间1244770435秒,442388微秒。

测试代码如下: 
  #include <stdio.h> 
  #include <sys/time.h> 
  #include <time.h> 
  int gettimeofday(struct timeval *tv, struct timezone *tz); 
  int main(int argc,char * argv[]){ 
        struct timeval tv; 
        while(1){ 
              gettimeofday(&tv,NULL); 
                   printf("time %u:%u/n",tv.tv_sec,tv.tv_usec); 
             sleep(2); 
        } 
     return 0; 
   }

运行结果如下:
time 1259471701:970193
time 1259471703:971529
time 1259471705:973225
time 1259471707:974921

timespec
/* POSIX.1b structure for a time value. This is like a `struct timeval' but
   has nanoseconds instead of microseconds. */
struct timespec
{
    __time_t tv_sec;        /* Seconds. */
    long int tv_nsec;       /* Nanoseconds. */
};

 

与struct timeval 不同,将结构体内成员微秒变换成纳秒


0 0