Linux定时器

简介: 内核中使用jiffies进行时间计数,计数的频率由HZ来决定

内核定时器:


定时触发定时器中断,执行定时器中断处理函数 <linux/timer.h>


定时器数据类型是:


struct timer_list {
unsigned long expires; //定时器计数时间值
void (*function)(unsigned long); //定时器处理函数
unsigned long data; //私有数据 };
/定义并初始化定时器/ #define DEFINE_TIMER(_name, _function, _expires, _data) \ struct timer_list _name = { \ .entry = { .prev = TIMER_ENTRY_STATIC }, \ .function = (_function), \ .expires = (_expires), \ .data = (_data), \ .base = &boot_tvec_bases, \ .slack = -1, \ __TIMER_LOCKDEP_MAP_INITIALIZER( \ FILE “:” __stringify(LINE)) \ }


内核中使用jiffies进行时间计数,计数的频率由HZ来决定


如果expires的值和jiffies值相等,就会触发定时器中断


expires = jiffies + HZ; //定时多长时间? 定时1Sexpires = jiffies + n*HZ //定时n秒
init_timer(struct timer_list * timer) //初始化定时器的函数宏
void add_timer(struct timer_list *timer); //添加定时器int del_timer(struct timer_list * timer); //删除定时器
修改定时器时间,再次触发定时器中断
int mod_timer(struct timer_list *timer, unsigned long expires);功能:修改定时器时间参数: @timer 定时器结构体指针 @expires 定时器定时时间


在2.4版本内核下用链表和信号实现定时器


1. setitimer 的原型
#include <sys/time.h>   int setitimer(int which, const struct itimerval *new_value,struct itimerval *old_value);
setitimer 能够在 Timer 到期之后,自动再次启动自己,因此,用它来解决 Single-Shot Timer 和 Repeating Timer 的问题显得很简单。该函数可以工作于 3 种模式:ITIMER_REAL    以实时时间 (real time) 递减,在到期之后发送 SIGALRM 信号ITIMER_VIRTUAL 仅进程在用户空间执行时递减,在到期之后发送 SIGVTALRM 信号ITIMER_PROF    进程在用户空间执行以及内核为该进程服务时 ( 典型如完成一个系统调用 ) 都会递减,与 ITIMER_VIRTUAL 共用时可度量该应用在内核空间和用户空间的时间消耗情况,在到期之后发送 SIGPROF 信号
2. setitimer 定时器的值定义
struct itimerval {  struct timeval it_interval; /* next value */  struct timeval it_value;     /* current value */  };   struct timeval {         long tv_sec;                /* seconds */         long tv_usec;               /* microseconds */  };
setitimer() 以 new_value 设置特定的定时器,如果 old_value 非空,则它返回 which 类型时间间隔定时器的前一个值。定时器从 it_value 递减到零,然后产生一个信号,并重新设置为 it_interval,如果此时 it_interval 为零,则该定时器停止。任何时候,只要 it_value 设置为零,该定时器就会停止。由于 setitimer() 不支持在同一进程中同时使用多次以支持多个定时器,因此,如果需要同时支持多个定时实例的话,需要由实现者来管理所有的实例。用 setitimer() 和链表,可以构造一个在进程环境下支持多个定时器实例的 Timer,在一般的实现中的 PerTickBookkeeping 时,会递增每个定时器的 elapse 值,直到该值递增到最初设定的 interval 则表示定时器到期。
3. 基于链表的定时器定义
typedef int timer_id;   /**  * The type of callback function to be called by timer scheduler when a timer  * has expired.  *  * @param id                The timer id.  * @param user_data        The user data.  * $param len               The length of user data.  */  typedef int timer_expiry(timer_id id, void *user_data, int len);   /**  * The type of the timer  */  struct timer {         LIST_ENTRY(timer) entries;/**< list entry               */          timer_id id;                /**< timer id                  */          int interval;               /**< timer interval(second) */         int elapse;                 /**< 0 -> interval             */          timer_expiry *cb;          /**< call if expiry            */         void *user_data;           /**< callback arg               */         int len;                        /**< user_data length          */  };
4. 定时器链表
/**  * The timer list  */  struct timer_list {         LIST_HEAD(listheader, timer) header;  /**< list header         */         int num;                                       /**< timer entry number */         int max_num;                               /**< max entry number    */          void (*old_sigfunc)(int);                /**< save previous signal handler */         void (*new_sigfunc)(int);                /**< our signal handler              */          struct itimerval ovalue;                 /**< old timer value */         struct itimerval value;                  /**< our internal timer value */  };
5. 定时器链表的创建和 Destroy
/**  * Create a timer list.  *  * @param count  The maximum number of timer entries to be supported initially.  *  * @return        0 means ok, the other means fail.  */  int init_timer(int count)  {         int ret = 0;          if(count <=0 || count > MAX_TIMER_NUM) {                printf("the timer max number MUST less than %d.\n", MAX_TIMER_NUM);                return -1;         }          memset(&timer_list, 0, sizeof(struct timer_list));         LIST_INIT(&timer_list.header);         timer_list.max_num = count;          /* Register our internal signal handler and store old signal handler */         if ((timer_list.old_sigfunc = signal(SIGALRM, sig_func)) == SIG_ERR) {                 return -1;         }         timer_list.new_sigfunc = sig_func;       /*Setting our interval timer for driver our mutil-timer and store old timer value*/         timer_list.value.it_value.tv_sec = TIMER_START;         timer_list.value.it_value.tv_usec = 0;         timer_list.value.it_interval.tv_sec = TIMER_TICK;         timer_list.value.it_interval.tv_usec = 0;         ret = setitimer(ITIMER_REAL, &timer_list.value, &timer_list.ovalue);          return ret;  }    /**  * Destroy the timer list.  *  * @return          0 means ok, the other means fail.  */  int destroy_timer(void)  {         struct timer *node = NULL;          if ((signal(SIGALRM, timer_list.old_sigfunc)) == SIG_ERR) {                 return -1;         }          if((setitimer(ITIMER_REAL, &timer_list.ovalue, &timer_list.value)) < 0) {                 return -1;         }          while (!LIST_EMPTY(&timer_list.header)) {     /* Delete. */          node = LIST_FIRST(&timer_list.header);                 LIST_REMOVE(node, entries);                 /* Free node */          printf("Remove id %d\n", node->id);                 free(node->user_data);                 free(node);         }          memset(&timer_list, 0, sizeof(struct timer_list));          return 0;  }
6. 向定时器链表中添加定时器
/**  * Add a timer to timer list.  *  * @param interval  The timer interval(second).  * @param cb        When cb!= NULL and timer expiry, call it.  * @param user_data Callback's param.  * @param len       The length of the user_data.  *  * @return          The timer ID, if == INVALID_TIMER_ID, add timer fail.  */  timer_id  add_timer(int interval, timer_expiry *cb, void *user_data, int len)  {         struct timer *node = NULL;          if (cb == NULL || interval <= 0) {                 return INVALID_TIMER_ID;         }       if(timer_list.num < timer_list.max_num) {          timer_list.num++;      } else {          return INVALID_TIMER_ID;      }       if((node = malloc(sizeof(struct timer))) == NULL) {          return INVALID_TIMER_ID;      }      if(user_data != NULL || len != 0) {          node->user_data = malloc(len);          memcpy(node->user_data, user_data, len);          node->len = len;      }       node->cb = cb;      node->interval = interval;      node->elapse = 0;      node->id = timer_list.num;       LIST_INSERT_HEAD(&timer_list.header, node, entries);      return node->id;  }
7. 信号处理函数驱动定时器
/* Tick Bookkeeping */  static void sig_func(int signo)  {         struct timer *node = timer_list.header.lh_first;         for ( ; node != NULL; node = node->entries.le_next) {                 node->elapse++;                 if(node->elapse >= node->interval) {                         node->elapse = 0;                         node->cb(node->id, node->user_data, node->len);                 }         }  }


相关文章
|
23天前
|
监控 Linux 编译器
Linux C++ 定时器任务接口深度解析: 从理论到实践
Linux C++ 定时器任务接口深度解析: 从理论到实践
67 2
|
7月前
|
Linux
手把手教你写Linux设备驱动---定时器(一)(基于友善之臂4412开发板)
手把手教你写Linux设备驱动---定时器(一)(基于友善之臂4412开发板)
85 0
|
7月前
|
Linux
Linux驱动中断与时间篇——高精度定时器hrtimer
Linux驱动中断与时间篇——高精度定时器hrtimer
|
7月前
|
Linux
Linux驱动中断与时间篇——低分辨率定时器
Linux驱动中断与时间篇——低分辨率定时器
|
存储 Linux 调度
Linux驱动开发——定时器
Linux驱动开发——定时器
138 0
Linux驱动开发——定时器
|
Linux 芯片
Linux系统中裸机定时器的基本原理
大家好,今天的话主要和大家聊一聊,如何使用定时器,完成精准的定时功能实现​。
138 0
Linux系统中裸机定时器的基本原理
|
编解码 安全 Linux
Linux内核开发基础-低精度timer_list和高精度hrtimer定时器
上篇文章讲解了如何正确的使用内核延时函数,在进行驱动开发时,可能会经常用到精确地延时操作。除此之外,如果要实现一个定时任务,那就需要用到定时器。作为一项基础功能需求,Linux内核提供了定时器相关的实现。下面就具体看一下,Linux内核所提供的定时器实现。
958 0
|
数据采集 前端开发 JavaScript
【Linux】好用的定时器
【Linux】好用的定时器
102 0
【Linux】好用的定时器
Linux内核定时器--timer_list
Linux内核定时器--timer_list
|
Linux 调度 移动开发
全志 A64开发板Linux内核定时器编程
开发平台 芯灵思Sinlinx A64内存: 1GB 存储: 4GB 开发板详细参数 https://m.tb.cn/h.3wMaSKm开发板交流群 641395230 Linux 内核定时器是内核用来控制在未来某个时间点(基于jiffies)调度执行某个函数的一种机制,其实现位于 和 kernel/timer.c 文件中。
1178 0