当前位置:   article > 正文

linux内核定时器:timer_list_struct timer_list

struct timer_list

前言

        头文件:

#include <linux/timer.h>

     一 内核定时器 timer_list

        软件意义上的定时器最终依赖硬件定时器来实现,内核在时钟中断发生后检测各定时器是否到期,到期后的定时器处理函数将作为软中断在底半部执行。实质上,时钟中断处理程序会唤起TIMER_SOFTIRQ软中断,运行当前处理器上到期的所有定时器。

        在Linux设备驱动编程中,可以利用Linux内核中提供的一组函数和数据结构来完成定时触发工作或者完成某周期性的事务。这组函数和数据结构使得驱动工程师在多数情况下不用关心具体的软件定时器究竟对应着怎样的内核和硬件行为。

        Linux内核所提供的用于操作定时器的数据结构和函数如下。

1.timer_list

在Linux内核中,timer_list结构体的一个实例对应一个定时器,如下

  1. struct timer_list {
  2. /*
  3. * All fields that change during normal runtime grouped to the
  4. * same cacheline
  5. */
  6. struct list_head entry;
  7. unsigned long expires;
  8. struct tvec_base *base;
  9. void (*function)(unsigned long);
  10. unsigned long data;
  11. int slack;
  12. #ifdef CONFIG_TIMER_STATS
  13. int start_pid;
  14. void *start_site;
  15. char start_comm[16];
  16. #endif
  17. #ifdef CONFIG_LOCKDEP
  18. struct lockdep_map lockdep_map;
  19. #endif
  20. }

        当定时器期满后,其中第10行的function()成员将被执行,而data成员则是传入其中的参数,expires则是定时器到期的时间(jiffies)。如下代码定义一个名为my_timer的定时器:

struct timer_list my_timer;

2.初始化定时器

init_timer是一个宏,它的原型如下:timer是一个指针,例如:struct timer_list * timer。

  1. #define init_timer(timer) \
  2. __init_timer((timer), 0)

        上述init_timer()函数初始化timer_list的entry的next为NULL,并给base指针赋值。TIMER_INITIALIZER(_function,_expires,_data)宏用于赋值定时器结构体的function、expires、data和base成员,这个宏原型:

  1. #define TIMER_INITIALIZER(_function, _expires, _data) \
  2. __TIMER_INITIALIZER((_function), (_expires), (_data), 0)
  1. #define __TIMER_INITIALIZER(_function, _expires, _data, _flags) { \
  2. .entry = { .prev = TIMER_ENTRY_STATIC }, \
  3. .function = (_function), \
  4. .expires = (_expires), \
  5. .data = (_data), \
  6. .base = (void *)((unsigned long)&boot_tvec_bases + (_flags)), \
  7. .slack = -1, \
  8. __TIMER_LOCKDEP_MAP_INITIALIZER( \
  9. __FILE__ ":" __stringify(__LINE__)) \
  10. }

        DEFINE_TIMER(_name,_function,_expires,_data)宏是定义并初始化定时器成员的“快捷方式”,这个宏定义为:

  1. #define DEFINE_TIMER(_name, _function, _expires, _data) \
  2. struct timer_list _name = \
  3. TIMER_INITIALIZER(_function, _expires, _data)

此外,setup_timer()也可用于初始化定时器并赋值其成员,其源代码为:

  1. #define setup_timer(timer, fn, data) \
  2. __setup_timer((timer), (fn), (data), 0)
  1. #define __setup_timer(_timer, _fn, _data, _flags) \
  2. do { \
  3. __init_timer((_timer), (_flags)); \
  4. (_timer)->function = (_fn); \
  5. (_timer)->data = (_data); \
  6. } while (0)

3.增加定时器add_timer

        从函数原型可知add_timer是通过调用mod_timer实现的。所以啊,就不要拼命计较用add_timer还是用mod_timer啦。

  1. extern void add_timer(struct timer_list *timer);
  2. /**
  3. * add_timer - start a timer
  4. * @timer: the timer to be added
  5. *
  6. * The kernel will do a ->function(->data) callback from the
  7. * timer interrupt at the ->expires point in the future. The
  8. * current time is 'jiffies'.
  9. *
  10. * The timer's ->expires, ->function (and if the handler uses it, ->data)
  11. * fields must be set prior calling this function.
  12. *
  13. * Timers with an ->expires field in the past will be executed in the next
  14. * timer tick.
  15. */
  16. void add_timer(struct timer_list *timer)
  17. {
  18. BUG_ON(timer_pending(timer));
  19. mod_timer(timer, timer->expires);
  20. }

4.删除定时器del_timer

  1. /**
  2. * del_timer - deactive a timer.
  3. * @timer: the timer to be deactivated
  4. *
  5. * del_timer() deactivates a timer - this works on both active and inactive
  6. * timers.
  7. *
  8. * The function returns whether it has deactivated a pending timer or not.
  9. * (ie. del_timer() of an inactive timer returns 0, del_timer() of an
  10. * active timer returns 1.)
  11. */
  12. int del_timer(struct timer_list *timer)
  13. {
  14. struct tvec_base *base;
  15. unsigned long flags;
  16. int ret = 0;
  17. debug_assert_init(timer);
  18. timer_stats_timer_clear_start_info(timer);
  19. if (timer_pending(timer)) {
  20. base = lock_timer_base(timer, &flags);
  21. ret = detach_if_pending(timer, base, true);
  22. spin_unlock_irqrestore(&base->lock, flags);
  23. }
  24. return ret;
  25. }

        del_timer函数用于删除定时器。del_timer_sync()是del_timer()的同步版,在删除一个定时器时需等待其被处理完,因此该函数的调用不能发生在中断上下文中。

5.修改定时器的expir:mod_timer

        函数mod_timer用于修改定时器的到期时间,在新的被传入的expires到来后才会执行定时器函数。

  1. /**
  2. * mod_timer - modify a timer's timeout
  3. * @timer: the timer to be modified
  4. * @expires: new timeout in jiffies
  5. *
  6. * mod_timer() is a more efficient way to update the expire field of an
  7. * active timer (if the timer is inactive it will be activated)
  8. *
  9. * mod_timer(timer, expires) is equivalent to:
  10. *
  11. * del_timer(timer); timer->expires = expires; add_timer(timer);
  12. *
  13. * Note that if there are multiple unserialized concurrent users of the
  14. * same timer, then mod_timer() is the only safe way to modify the timeout,
  15. * since add_timer() cannot modify an already running timer.
  16. *
  17. * The function returns whether it has modified a pending timer or not.
  18. * (ie. mod_timer() of an inactive timer returns 0, mod_timer() of an
  19. * active timer returns 1.)
  20. */
  21. int mod_timer(struct timer_list *timer, unsigned long expires)
  22. {
  23. expires = apply_slack(timer, expires);
  24. /*
  25. * This is a common optimization triggered by the
  26. * networking code - if the timer is re-modified
  27. * to be the same thing then just return:
  28. */
  29. if (timer_pending(timer) && timer->expires == expires)
  30. return 1;
  31. return __mod_timer(timer, expires, false, TIMER_NOT_PINNED);
  32. }
  1. static inline int
  2. __mod_timer(struct timer_list *timer, unsigned long expires,
  3. bool pending_only, int pinned)
  4. {
  5. struct tvec_base *base, *new_base;
  6. unsigned long flags;
  7. int ret = 0 , cpu;
  8. timer_stats_timer_set_start_info(timer);
  9. BUG_ON(!timer->function);
  10. base = lock_timer_base(timer, &flags);
  11. ret = detach_if_pending(timer, base, false);
  12. if (!ret && pending_only)
  13. goto out_unlock;
  14. debug_activate(timer, expires);
  15. cpu = get_nohz_timer_target(pinned);
  16. new_base = per_cpu(tvec_bases, cpu);
  17. if (base != new_base) {
  18. /*
  19. * We are trying to schedule the timer on the local CPU.
  20. * However we can't change timer's base while it is running,
  21. * otherwise del_timer_sync() can't detect that the timer's
  22. * handler yet has not finished. This also guarantees that
  23. * the timer is serialized wrt itself.
  24. */
  25. if (likely(base->running_timer != timer)) {
  26. /* See the comment in lock_timer_base() */
  27. timer_set_base(timer, NULL);
  28. spin_unlock(&base->lock);
  29. base = new_base;
  30. spin_lock(&base->lock);
  31. timer_set_base(timer, base);
  32. }
  33. }
  34. timer->expires = expires;
  35. internal_add_timer(base, timer);
  36. out_unlock:
  37. spin_unlock_irqrestore(&base->lock, flags);
  38. return ret;
  39. }

二 测试实例

1 定时器到期时间设置方法

        1)延时一秒expires = jiffies + Hz;

  1. unsigned long expires = jiffies + Hz;
  2. mod_timer(&timer,expires);

        2)延时 100毫秒        

  1. unsigned long expires = jiffies + msecs_to_jiffies(100);
  2. mod_timer(&timer,expires);

2 测试代码:csi_timer.c

  1. #include <linux/init.h>
  2. #include <linux/module.h>
  3. #include <linux/types.h>
  4. #include <linux/kernel.h>
  5. #include <linux/slab.h>
  6. #include <linux/timer.h>
  7. #define DEBUG_CT(format,...)\
  8. printk("%s:%s:%d: "format"\n",\
  9. __FILE__,__func__,__LINE__,\
  10. ##__VA_ARGS__)
  11. struct ct_dev_{
  12. struct timer_list ct_timer;
  13. int count;
  14. };
  15. struct ct_dev_ *ct_dev;
  16. static void ct_timer_function(unsigned long data)
  17. {
  18. struct ct_dev_ *p = (struct ct_dev_ *)data;
  19. DEBUG_CT("%d",p->count++);
  20. if(p->count < 5){
  21. DEBUG_CT("HZ=%d,msecs_to_jiffies(1000)=%lu",HZ,msecs_to_jiffies(1000));
  22. mod_timer(&p->ct_timer,jiffies + HZ);
  23. }
  24. }
  25. static int __init ct_init(void)
  26. {
  27. struct ct_dev_ *p = NULL;
  28. ct_dev = (struct ct_dev_ *)kmalloc(sizeof(struct ct_dev_),GFP_KERNEL);
  29. if(IS_ERR(ct_dev)){
  30. DEBUG_CT("kmalloc error");
  31. return -ENOMEM;
  32. }
  33. p = ct_dev;
  34. setup_timer(&p->ct_timer,ct_timer_function,(unsigned long)p);
  35. p->count = 0;
  36. mod_timer(&p->ct_timer,HZ);
  37. DEBUG_CT("init ok");
  38. return 0;
  39. }
  40. static void __exit ct_exit(void)
  41. {
  42. struct ct_dev_ *p = ct_dev;
  43. if(IS_ERR(p)){
  44. return;
  45. }
  46. del_timer_sync(&p->ct_timer);
  47. kfree(p);
  48. DEBUG_CT("exit ok");
  49. }
  50. module_init(ct_init);
  51. module_exit(ct_exit);
  52. MODULE_LICENSE("GPL");

3 Makefile文件:

  1. export ARCH=arm
  2. export CROSS_COMPILE=arm-linux-gnueabihf-
  3. KERNELDIR := /home/lkmao/imx/linux/linux-imx
  4. CURRENT_PATH := $(shell pwd)
  5. FILE_NAME=csi_timer
  6. obj-m := $(FILE_NAME).o
  7. build: kernel_modules
  8. kernel_modules:
  9. $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules
  10. sudo cp $(FILE_NAME).ko /big/nfsroot/jiaocheng_rootfs/home/root/
  11. clean:
  12. $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean

4 执行结果

        从输出结果可知当前HZ的值是100。这意味着什么,暂时还不用考虑。知道它放在这里表示1秒就行,msecs_to_jiffies(1000)=100也等于100,100个jiffies单位。表示1000毫秒。

  1. root@hehe:~# insmod csi_timer.ko
  2. [ 5426.520022] /big/csi_driver/csi_timer/csi_timer.c:ct_init:40: init ok
  3. [ 5426.526598] /big/csi_driver/csi_timer/csi_timer.c:ct_timer_function:21: 0
  4. [ 5426.526606] /big/csi_driver/csi_timer/csi_timer.c:ct_timer_function:23: HZ=100,msecs_to_jiffies(1000)=100
  5. root@hehe:~# [ 5427.523293] /big/csi_driver/csi_timer/csi_timer.c:ct_timer_function:21: 1
  6. [ 5427.530110] /big/csi_driver/csi_timer/csi_timer.c:ct_timer_function:23: HZ=100,msecs_to_jiffies(1000)=100
  7. [ 5428.523293] /big/csi_driver/csi_timer/csi_timer.c:ct_timer_function:21: 2
  8. [ 5428.530110] /big/csi_driver/csi_timer/csi_timer.c:ct_timer_function:23: HZ=100,msecs_to_jiffies(1000)=100
  9. [ 5429.523295] /big/csi_driver/csi_timer/csi_timer.c:ct_timer_function:21: 3
  10. [ 5429.530113] /big/csi_driver/csi_timer/csi_timer.c:ct_timer_function:23: HZ=100,msecs_to_jiffies(1000)=100
  11. [ 5430.523298] /big/csi_driver/csi_timer/csi_timer.c:ct_timer_function:21: 4

结束

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号