• kernel 定时数据机构和API


    概述:上一个基于Kernel 定时器,编写简单的demo,接下来看看定时器相关的数据结构和API。

    kernel版本:4.0

    1、timer_list 结构体

    PATH:include/linux/timer.h

    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. };

    此处没有定义“CONFIG_TIMER_STATS” 和 “CONFIG_LOCKDEP”,所以只有最基本的

    1. struct list_head entry; /*内核中timer 链表挂接点,初始化时添加到kernel timer 链表末尾,并将下一个指向NULL */
    2. unsigned long expires; /* timer_list 启动时间间隔,初始化传入一个值,从初始化结束开始计算,如果到达这个时间点,则执行 下面的 function函数。
    3. struct tvec_base *base; */记录该软件时钟所在的 struct tvec_base 变量 */
    4. void (*function)(unsigned long); /* 时间到了的时候的回调函数 */
    5. unsigned long data; /* 回调函数参数 */
    6. int slack; /* 初始化的时候设置为了 -1, 后续的代码暂时未见使用 */

     此时有一个新的结构体出现:

    1. struct tvec_base {
    2. spinlock_t lock; // 同步用的锁
    3. struct timer_list *running_timer; // 该base 指向的 timer_list
    4. unsigned long timer_jiffies; //下述几个都是timer_lsit 的时钟周期
    5. unsigned long next_timer;
    6. unsigned long active_timers;
    7. unsigned long all_timers;
    8. int cpu;
    9. struct tvec_root tv1; //这几个是软件时钟的记录链表
    10. struct tvec tv2;
    11. struct tvec tv3;
    12. struct tvec tv4;
    13. struct tvec tv5;
    14. } ____cacheline_aligned;

    对于 struct tvec 结构体具体怎么使用,暂时还不是特别清楚,后续深入到这部分再进行补充。

    2. 相关的接口函数

    (1).初始化

    1. /*初始化 timer */
    2. setup_timer(&test_timer, timer_test_callback, 0);
    3. /*调用关系如下*/
    4. //1.宏定义
    5. #define setup_timer(timer, fn, data) \
    6. __setup_timer((timer), (fn), (data), 0)
    7. //2. 展开 __setup_timer
    8. #define __setup_timer(_timer, _fn, _data, _flags) \
    9. do { \
    10. __init_timer((_timer), (_flags)); \ /*继续宏定义,做初始化动作*/
    11. (_timer)->function = (_fn); \ /*挂接回调函数*/
    12. (_timer)->data = (_data); \ /*赋值回调函数参数*/
    13. } while (0)
    14. //3.展开 __init_timer
    15. #ifdef #ifdef CONFIG_LOCKDEP
    16. #define __init_timer(_timer, _flags) \
    17. do { \
    18. static struct lock_class_key __key; \
    19. init_timer_key((_timer), (_flags), #_timer, &__key); \
    20. } while (0)
    21. #define __init_timer_on_stack(_timer, _flags) \
    22. do { \
    23. static struct lock_class_key __key; \
    24. init_timer_on_stack_key((_timer), (_flags), #_timer, &__key); \
    25. } while (0)
    26. #else
    27. #define __init_timer(_timer, _flags) \
    28. init_timer_key((_timer), (_flags), NULL, NULL)
    29. #define __init_timer_on_stack(_timer, _flags) \
    30. init_timer_on_stack_key((_timer), (_flags), NULL, NULL)
    31. #endif
    32. #define __init_timer(_timer, _flags) \
    33. do { \
    34. static struct lock_class_key __key; \
    35. init_timer_key((_timer), (_flags), #_timer, &__key); \
    36. } while (0)
    37. #define __init_timer_on_stack(_timer, _flags) \
    38. do { \
    39. static struct lock_class_key __key; \
    40. init_timer_on_stack_key((_timer), (_flags), #_timer, &__key); \
    41. } while (0)
    42. #else //CONFIG_LOCKDEP 未定义,应该定走else
    43. #define __init_timer(_timer, _flags) \
    44. init_timer_key((_timer), (_flags), NULL, NULL)
    45. #define __init_timer_on_stack(_timer, _flags) \
    46. init_timer_on_stack_key((_timer), (_flags), NULL, NULL)
    47. #endif
    48. //4. 展开后,调用的是 init_timer_key() 函数
    49. void init_timer_key(struct timer_list *timer, unsigned int flags,
    50. const char *name, struct lock_class_key *key)
    51. {
    52. debug_init(timer);
    53. do_init_timer(timer, flags, name, key);
    54. }
    55. //5. debug_init() 方法是没有实现的,因为没有配置对应的config
    56. //6. do_init_timer()函数做了真正的初始动作,代码如下
    57. static void do_init_timer(struct timer_list *timer, unsigned int flags,
    58. const char *name, struct lock_class_key *key)
    59. {
    60. struct tvec_base *base = raw_cpu_read(tvec_bases);
    61. timer->entry.next = NULL;
    62. timer->base = (void *)((unsigned long)base | flags);
    63. timer->slack = -1;
    64. #ifdef CONFIG_TIMER_STATS
    65. timer->start_site = NULL;
    66. timer->start_pid = -1;
    67. memset(timer->start_comm, 0, TASK_COMM_LEN);
    68. #endif
    69. lockdep_init_map(&timer->lockdep_map, name, key, 0);
    70. }

    (2).设置超时时间, 超时后调用回调函数

    1. /*更改时间*/
    2. ret = mod_timer(&test_timer, jiffies + msecs_to_jiffies(3000));
    3. //1. 函数原型
    4. int mod_timer(struct timer_list *timer, unsigned long expires)
    5. {
    6. expires = apply_slack(timer, expires);
    7. if (timer_pending(timer) && timer->expires == expires)
    8. return 1;
    9. return __mod_timer(timer, expires, false, TIMER_NOT_PINNED);
    10. }

    (3).删除定时器

    1. del_timer(&test_timer);
    2. //函数原型
    3. int del_timer(struct timer_list *timer)
    4. {
    5. struct tvec_base *base;
    6. unsigned long flags;
    7. int ret = 0;
    8. debug_assert_init(timer);
    9. timer_stats_timer_clear_start_info(timer);
    10. if (timer_pending(timer)) {
    11. base = lock_timer_base(timer, &flags);
    12. ret = detach_if_pending(timer, base, true);
    13. spin_unlock_irqrestore(&base->lock, flags);
    14. }
    15. return ret;
    16. }

     关于 timer 相关的API,也不算多,在 kernle/linux/timer.h中,有如下几个常用的

    1. static inline int timer_pending(const struct timer_list * timer)
    2. {
    3. return timer->entry.next != NULL;
    4. }
    5. extern void add_timer_on(struct timer_list *timer, int cpu);
    6. extern int del_timer(struct timer_list * timer);
    7. extern int mod_timer(struct timer_list *timer, unsigned long expires);
    8. extern int mod_timer_pending(struct timer_list *timer, unsigned long expires);
    9. extern int mod_timer_pinned(struct timer_list *timer, unsigned long expires);
    10. extern void set_timer_slack(struct timer_list *time, int slack_hz);

     struct timer_list 中的“slack” 成员,是对延时进行微调整,但是不能起到完全控制的时间的作用,看如下对比验证:

    验证一: slack 做全部延时时间设置,超时函数中的时间设置为0

    ===》 时间对不上

    验证二:slack不设置,超时时长全部从超时函数设置

    ===> 基本可以对上,和之前的验证一致。

    验证三: 两个都设置

     ==> 准确度偏高

  • 相关阅读:
    30行Python极简代码,10分钟get常用技巧
    Power BI 傻瓜入门 13. 进入仪表板
    Tensorflow笔记——卷积神经网络
    curl语法整理
    calibre部署指南:docker一键部署calibre在线书库
    Abnova丨Abnova mutaFISH 探针研究方案
    SIP会话发起协议 - 先知道是什么(一)
    化工管理杂志化工管理杂志社化工管理编辑部2023年第30期目录
    java计算机毕业设计社区养老服务管理系统源程序+mysql+系统+lw文档+远程调试
    ChatGPT 从零完全上手实操指南!
  • 原文地址:https://blog.csdn.net/qq_20376499/article/details/127570547