驱动-Linux定时-timer_list

了解内核定时相关基础知识


简要介绍

硬件为内核提供了一个系统定时器来计算流逝的时间(即基于未来时间点的计时方式, 以当前时刻为计时开始的起点, 以未来的某一时刻为计时的终点) , 内核只有在系统定时器的帮助下才能计算和管理时间, 但是内核定时器的精度并不高, 所以不能作为高精度定时器使用。并且内核定时器的运行没有周期性, 到达计时终点后会自动关闭。 如果要实现周期性定时, 就要在定时处理函数中重新开启定时器。

Linux 内核中使用 timer_list 结构体表示内核定时器, 该结构体定义在“内核源码/include/li
nux/timer.h”文件中, 具体内容如下所示


struct timer_list {
   
   
    struct hlist_node   entry;
    unsigned long       expires;/* 定时器超时时间,单位是节拍数 */
    void            (*function)(struct timer_list *);/* 定时处理函数 */
    u32         flags;

#ifdef CONFIG_LOCKDEP
    struct lockdep_map  lockdep_map;
#endif
    ANDROID_KABI_RESERVE(1);
    ANDROID_KABI_RESERVE(2);
};

timer_list 特点

inux 内核定时器是基于 timer_list 结构的动态定时器,具有以下特点:

  • 不是周期性的,超时后会自动失效

  • 基于内核的 jiffies 计时

  • 在中断上下文执行,因此不能睡眠

  • 精度取决于 HZ 值(通常为 1ms 或 10ms)

API 函数

函数 作用
void add_timer(struct timer_list *timer) 向 Linux 内核注册定时器,使用 add_timer 函数向内核注册定时器以后,定时器就会开始运行
int del_timer(struct timer_list * timer) 删除一个定时器
int mod_timer(struct timer_list *timer,unsigned long expires) 修改定时值,如果定时器还没有激活的话,mod_timer 函数会激活定时器</
#include <linux/module.h> #include <linux/kernel.h> #include <linux/time.h> #include <linux/jiffies.h> #include <linux/kernel_stat.h> static struct timer_list cpu_monitor_timer; static u64 prev_user, prev_nice, prev_system, prev_idle; static u64 prev_iowait, prev_irq, prev_softirq, prev_steal; void cpu_timer_callback(struct timer_list *t) { int cpu_usage = 0; struct kernel_cpustat *kstat = &kcpustat_cpu(0); u64 cur_user = kstat->cpustat[CPUTIME_USER]; u64 cur_nice = kstat->cpustat[CPUTIME_NICE]; u64 cur_system = kstat->cpustat[CPUTIME_SYSTEM]; u64 cur_idle = kstat->cpustat[CPUTIME_IDLE]; u64 cur_iowait = kstat->cpustat[CPUTIME_IOWAIT]; u64 cur_irq = kstat->cpustat[CPUTIME_IRQ]; u64 cur_softirq = kstat->cpustat[CPUTIME_SOFTIRQ]; u64 cur_steal = kstat->cpustat[CPUTIME_STEAL]; u64 prev_total = prev_user + prev_nice + prev_system + prev_idle + prev_iowait + prev_irq + prev_softirq + prev_steal; u64 cur_total = cur_user + cur_nice + cur_system + cur_idle + cur_iowait + cur_irq + cur_softirq + cur_steal; u64 prev_busy = prev_total - prev_idle; u64 cur_busy = cur_total - cur_idle; s64 diff_total = cur_total - prev_total; s64 diff_busy = cur_busy - prev_busy; if (diff_total > 0) { cpu_usage = div64_u64(diff_busy * 100, diff_total); cpu_usage = min(cpu_usage, 100); cpu_usage = max(cpu_usage, 0); printk(KERN_INFO "CPU usage: %d%%\n", cpu_usage); } prev_user = cur_user; prev_nice = cur_nice; prev_system = cur_system; prev_idle = cur_idle; prev_iowait = cur_iowait; prev_irq = cur_irq; prev_softirq = cur_softirq; prev_steal = cur_steal; mod_timer(&cpu_monitor_timer, jiffies + HZ); } static int __init cpu_monitor_init(void) { printk(KERN_INFO “cpu monitor init\n”); struct kernel_cpustat *kstat = &kcpustat_cpu(0); prev_user = kstat->cpustat[CPUTIME_USER]; prev_nice = kstat->cpustat[CPUTIME_NICE]; prev_system = kstat->cpustat[CPUTIME_SYSTEM]; prev_idle = kstat->cpustat[CPUTIME_IDLE]; prev_iowait = kstat->cpustat[CPUTIME_IOWAIT]; prev_irq = kstat->cpustat[CPUTIME_IRQ]; prev_softirq = kstat->cpustat[CPUTIME_SOFTIRQ]; prev_steal = kstat->cpustat[CPUTIME_STEAL]; setup_timer(&cpu_monitor_timer, cpu_timer_callback, 0); mod_timer(&cpu_monitor_timer, jiffies + HZ); return 0; } static void __exit cpu_monitor_exit(void) { printk(KERN_INFO “cpu monitor exit\n”); del_timer(&cpu_monitor_timer); } module_init(cpu_monitor_init); module_exit(cpu_monitor_exit); MODULE_LICENSE(“GPL”); MODULE_AUTHOR(“Cly”); MODULE_DESCRIPTION(“CPU usage monitor”);这个定时器是中断吗
最新发布
09-25
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

野火少年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值