Linux内核中设置一个定时器的方法及示例

在 Linux 内核中,定时器通常通过 timer_list 结构体和相关 API 实现。以下是设置定时器的步骤及示例:


方法步骤

  1. 包含头文件

    1
    2
    #include <linux/timer.h>
    #include <linux/jiffies.h>
  2. 定义定时器结构体

    1
    static struct timer_list my_timer;
  3. 初始化定时器

    • 旧内核版本(4.14 之前):
      1
      2
      3
      init_timer(&my_timer);
      my_timer.function = my_timer_callback;
      my_timer.data = (unsigned long)dev; // 传递给回调函数的数据
    • 新内核版本(4.15+):
      1
      timer_setup(&my_timer, my_timer_callback, 0);
  4. 设置超时时间

    1
    mod_timer(&my_timer, jiffies + msecs_to_jiffies(delay_ms));
    • jiffies 是内核时间单位,delay_ms 是毫秒级延迟。
  5. 编写回调函数

    1
    2
    3
    4
    5
    void my_timer_callback(struct timer_list *timer) {
    printk(KERN_INFO "Timer expired!\n");
    // 如需周期性触发,在此重新设置定时器
    mod_timer(&my_timer, jiffies + msecs_to_jiffies(1000));
    }
  6. 激活定时器

    • 若未使用 mod_timer,可用:
      1
      add_timer(&my_timer);
  7. 删除定时器

    1
    2
    del_timer(&my_timer);          // 非安全删除
    del_timer_sync(&my_timer); // 安全删除(防止竞争)

完整示例(新内核 API)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/timer.h>

static struct timer_list my_timer;

void my_timer_callback(struct timer_list *timer) {
printk(KERN_INFO "Timer callback called!\n");
// 重新激活定时器(周期触发)
mod_timer(&my_timer, jiffies + msecs_to_jiffies(2000));
}

static int __init my_module_init(void) {
// 初始化定时器
timer_setup(&my_timer, my_timer_callback, 0);
// 设置 2 秒后触发
mod_timer(&my_timer, jiffies + msecs_to_jiffies(2000));
printk(KERN_INFO "Timer started\n");
return 0;
}

static void __exit my_module_exit(void) {
del_timer_sync(&my_timer);
printk(KERN_INFO "Timer removed\n");
}

module_init(my_module_init);
module_exit(my_module_exit);
MODULE_LICENSE("GPL");

关键注意事项

  1. 定时器上下文:回调函数在中断上下文执行,禁止使用可能休眠的函数(如 kmalloc, mutex_lock)。
  2. 单次触发:默认触发一次,需在回调中调用 mod_timer 实现周期性触发。
  3. 资源释放:模块退出时务必使用 del_timer_sync 确保定时器已停止。
  4. 时间精度:内核定时器并非实时,可能存在微小延迟。

旧内核兼容示例(已弃用)

1
2
3
4
5
6
7
8
9
10
11
12
13
// 旧版初始化方式(内核 <4.15)
void my_timer_callback(unsigned long data) {
printk(KERN_INFO "Old timer callback\n");
}

static int __init my_module_init(void) {
init_timer(&my_timer);
my_timer.function = my_timer_callback;
my_timer.data = 0;
my_timer.expires = jiffies + HZ; // 1 秒后触发(HZ = 1秒的jiffies数)
add_timer(&my_timer);
return 0;
}

通过上述方法,可以在内核模块中灵活实现单次或周期性定时任务。