Linux驱动 | Linux高分辨率定时器hrtimer(实操代码编写)

本文详细介绍了Linux内核中的高精度定时器(hrtimer)原理与应用,包括ktime_t结构、hrtimer结构及函数。通过具体实例,展示了如何使用hrtimer设置定时任务,每10ms生成一个UUID并记录时间,最后通过proc文件系统展示结果。

ktime_t结构

相对timer定时器,hrtimer是以ktime_t来定义时间的。ktime_t的结构如下所示:

  union ktime {
   
   
  	s64 tv64;
  };
  typedef union ktime ktime_t;        /* Kill this */

ktime_t是一个64位的数,针对ktime_t有如下的一些函数(更多的代码请查看include/linux/ktime.h)

ktime_t ktime_set(secs, nsecs) : 初始化一个ktime_t对象
ktime_t ktime_get() : 获取系统自启动以来的相对时间
ktime_t ktime_get_real() : 获取系统真实时间
struct timeval ktime_to_timeval(ktime_t kt) 
struct timespec ktime_to_timespec(ktime_t kt) 
ktime_equal(const ktime_t cmp1, const ktime_t cmp2)
ktime_compare(const ktime_t cmp1, const ktime_t cmp2)
ktime_after(const ktime_t cmp1, const ktime_t cmp2)
ktime_before(const ktime_t cmp1, const ktime_t cmp2)

hrtimer结构体

  struct hrtimer {
   
   
      ....
      enum hrtimer_restart        (*function)(struct hrtimer *);
      ....
  };

hrtimer结构体中对驱动开发者有用的成员为function,通过function成员指定hrtimer定时器函数,其返回为枚举值hrtimer_restart,如果在定时器函数中重新设置定时器,实现延时或者循环,可以返回HRTIMER_RESTART告诉内核重启定时器。

  /*  
   * Return values for the callback function
   */
  enum hrtimer_restart {
   
   
      HRTIMER_NORESTART,  /* Timer is not restarted */
      HRTIMER_RESTART,    /* Timer must be restarted */
  };

hrtimer定时器常用函数

//hrtimer_init初始化一个hrtimer,clock_id是时钟类型,CLOCK_MONOTONIC表示自系统开机以来的单调递增时间,
//mode是时间模式,HRTIMER_MODE_ABS表绝对时间,HRTIMER_MODE_REL表相对时间
hrtimer_init(struct hrtimer *timer, clockid_t clock_id , enum hrtimer_mode mode)
//初始化之后就可以调用以下两个函数开始定时器,
//hrtimer_forward_now设置的时间为距离当前的interval个时间后
hrtimer_start(struct hrtimer *timer, ktime_t tim, const enum hrtimer_mode mode)
hrtimer_forward_now(struct hrtimer *timer,ktime_t interval)
//取消函数
hrtimer_cancel(struct hrtimer *timer)

hrtimer实践

纸上谈兵没用,本萌觉得学习驱动,可能最好的方法是多写,多搞点乱七八糟的需求让自己去学着实现,将这些文绉绉的知识变为实实在在的代码,在不知道怎么写的时候,在内核源代码中都有相应的实现。好记性不如烂笔头嘛,自己安慰自己,哈哈哈。

需求

①设置定时器时间为10ms
②驱动每10ms生成一个uuid,并保存定时器函数被调用的ktime_t时间,一共生成5个uuid,即要设置5次定时器。
③通过cat /proc/test_proc可以查看到相应的uuid和ktime_t时间,生成ktime_t时间是为了通过实验查看定时器调用的精度。
④通过seq_file接口,实现其中的start,next,show,stop方法,使用链表组织以上的uuid数据和ktime_t时间。
最终效果如下图(可以看到该高精度计时器有一定误差)
在这里插入图片描述

代码说明

可以跳到最后看代码,本萌希望求得各位大佬的批评意见,这里写代码说明,一是为了防止遗忘,一是为了讲述代码的实现过程。
其实,之所以要刻意用链表把数据组织起来,是因为我的上一篇文章写timer定时器的时候,将所有数据直接扔到内存页中,简单粗暴但空间浪费得有点多。所以这里我想总结下链表的用法(毕竟这篇文章是写给我自己看的嘛)。

//链表初始化:
#define LIST_HEAD(name) \
      struct list_head name = LIST_HEAD_INIT(name)
      
//链表的插入(有两个函数list_add和list_add_tail),本质上都是调用_list_add方法
//__list_add(new, A, B);
//查看代码发现_list_add就是将新的节点插入到A和B节点之间
//list_add将new插入到head和head->next之间,即新插入的节点
<think>嗯,用户现在想找关于在Linux内核驱动中使用高精度定时器hrtimer实现微秒级延时函数delay_us的代码示例。我需要先回顾之前的对话,确保这次回答符合用户的需求。 用户之前的问题是关于如何在Linux内核中使用_IOW宏定义字节类型的数据,我给出了详细的实现方法和代码示例,还附带了相关问题。现在用户的新问题是关于hrtimer实现微秒延时的代码示例,所以需要重点讲解hrtimer的使用步骤和注意事项。 首先,用户的需求是微秒级延时,而hrtimer正是高精度定时器,适合这个场景。我需要解释hrtimer的基本用法,比如如何初始化定时器、设置回调函数、启动和取消定时器等。同时,用户可能需要一个具体的代码示例,展示如何封装一个delay_us函数。 接下来,考虑用户可能的背景。他们可能正在开发内核驱动,需要精确的延时控制,比如在硬件操作或实时任务中。因此,除了代码示例,还需要强调使用hrtimer的优势,比如相比传统的定时器hrtimer提供更高的精度和更低的延迟。 然后,我需要检查之前的引用文献。用户提到了引用[1],其中提到ioctl接口将内核API映射到用户空间,这可能与当前的hrtimer问题没有直接关系,但可能需要考虑用户空间与内核的交互。不过当前问题集中在内核内部的定时器实现,所以重点应放在内核模块的代码结构上。 用户可能还会关心如何确保延时的准确性,以及如何处理定时器回调函数中的上下文。比如,hrtimer的回调函数是在中断上下文中执行的,不能进行可能导致睡眠的操作。这一点需要明确指出,避免用户在使用时犯错。 另外,需要提到hrtimer的不同模式,比如HRTIMER_MODE_REL(相对时间)和HRTIMER_MODE_ABS(绝对时间),在示例中使用相对时间模式更符合延时的需求。 在代码示例中,应该包括模块的初始化、定时器的设置、回调函数的实现,以及如何启动和停止定时器。同时,需要展示如何将hrtimer封装成delay_us函数,可能需要使用完成量(completion)或者等待队列来让调用线程等待定时器完成。 还要注意内核版本的兼容性,因为hrtimer的API在不同版本中可能有变化。需要建议用户查阅他们使用的内核版本的文档,或者确认示例代码的适用性。 最后,用户可能想知道如何处理多线程环境下的并发问题,或者如何测试这个延时函数的准确性。不过,用户当前的问题主要是代码示例,因此这些可以作为相关问题的补充。 总结下来,回答的结构应包括实现步骤、代码示例、关键注意事项和相关问题。需要确保代码正确使用hrtimer的API,并解释每个部分的作用,帮助用户理解如何集成到他们的驱动中。</think>### Linux内核hrtimer实现微秒级延时函数`delay_us()`代码示例 #### 一、核心实现原理 高精度定时器hrtimer)通过`hrtimer_init()`初始化定时器结构体,使用`hrtimer_start()`设置延时时间,通过`wait_for_completion()`实现同步等待[^1]。关键实现步骤如下: ```c #include <linux/hrtimer.h> #include <linux/completion.h> static struct hrtimer delay_timer; static struct completion delay_complete; // 定时器回调函数 static enum hrtimer_restart delay_callback(struct hrtimer *timer) { complete(&delay_completion); // 唤醒等待线程 return HRTIMER_NORESTART; // 单次触发模式 } // 微秒级延时函数 void delay_us(unsigned long microseconds) { ktime_t delay_time = ktime_set(0, microseconds * NSEC_PER_USEC); hrtimer_init(&delay_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); delay_timer.function = delay_callback; init_completion(&delay_completion); hrtimer_start(&delay_timer, delay_time, HRTIMER_MODE_REL); wait_for_completion(&delay_completion); } ``` #### 二、代码实现细节 ##### 1. **定时器初始化** ```c hrtimer_init(&delay_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); ``` - `CLOCK_MONOTONIC`:使用单调递增时钟,避免系统时间调整影响 - `HRTIMER_MODE_REL`:相对时间模式 ##### 2. **时间单位转换 ```c ktime_t delay_time = ktime_set(0, microseconds * NSEC_PER_USEC); ``` - 将微秒转换为纳秒(1μs = 1000ns) - `ktime_set(secs, nsecs)`创建时间对象 ##### 3. **同步等待机制 ```c init_completion(&delay_completion); wait_for_completion(&delay_completion); ``` - 使用完成量实现线程阻塞/唤醒 - 避免忙等待(busy-loop)造成的CPU资源浪费 #### 三、优化改进方案 ##### 1. 中断上下文安全版 ```c void delay_us_atomic(unsigned long usec) { ktime_t delay = ktime_set(0, usec * NSEC_PER_USEC); hrtimer_init_on_stack(&delay_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); hrtimer_start(&delay_timer, delay, HRTIMER_MODE_REL); while (hrtimer_active(&delay_timer)) cpu_relax(); // 适用于中断上下文 } ``` - 使用`hrtimer_active()`检测定时器状态 - `cpu_relax()`降低CPU占用(需配合`CONFIG_PREEMPT`配置) ##### 2. 批量延时优化 ```c void delay_us_batch(unsigned long total_us, unsigned int batch_size) { unsigned long cycles = total_us / batch_size; ktime_t batch_delay = ktime_set(0, batch_size * NSEC_PER_USEC); for (int i = 0; i < cycles; i++) { hrtimer_start(&delay_timer, batch_delay, HRTIMER_MODE_REL); wait_for_completion(&delay_completion); reinit_completion(&delay_completion); } } ``` #### 四、关键注意事项 1. **精度范围** hrtimer理论最小精度为1ns,实际受以下因素影响: ```text +------------------------+-----------------+ | 影响因素 | 典型误差范围 | +------------------------+-----------------+ | 硬件时钟源 | ±50ns | | 内核配置(CONFIG_HZ) | 100-1000μs | | 中断延迟 | 1-50μs | +------------------------+-----------------+ ``` 2. **上下文限制** - 在**中断上下文**中禁止使用`wait_for_completion()` - 原子版本需使用`hrtimer_init_on_stack()`避免内存分配 3. **资源释放** ```c void cleanup_delay(void) { hrtimer_cancel(&delay_timer); destroy_completion(&delay_completion); } ``` #### 五、性能测试方法 使用`ktime_get()`测量实际延时: ```c ktime_t start = ktime_get(); delay_us(100); // 测试100μs延时 ktime_t end = ktime_get(); s64 actual_delay = ktime_to_ns(end - start); ``` --- ### 相关问题 1. 如何选择hrtimer和传统的timer_list定时器? 2. 在实时内核(PREEMPT_RT)中使用hrtimer有什么特别注意事项? 3. 如何通过ftrace分析hrtimer的实际触发延迟? [^1]: Linux内核文档:`Documentation/timers/hrtimers.txt` [^2]: 《Linux Kernel Development》第11章 "Timers and Time Management"
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值