linux内核定时器

一、内核定时器简介:

Linux 内核定时器使用很简单,只需要提供超时时间(相当于当前时刻)和定时处理函数即可,当超时时间到了以后设置的定时处理函数就会执行。在使用内核定时器的时候要注意一点,内核定时器并不是周期性运行的,超时以后就会自动关闭,因此如果想要实现周期性定时,那么就需要在定时处理函数中重新开启定时器。

二、几个基础概念

linux系统上,有两个非常重要的时间,墙上时间和系统运行时间。

系统运行时间:自系统启动开始所经过的时间

墙上时间:指当前时刻,可以通过ntp服务器获取,获取后可以结合系统运行时间进行本地更新。

那么linux是怎么计算系统运行时间的呢?

答:由cpu内部定时器提供时钟源,时钟源的频率可以设置,设置好以后就周期性的产生定时中断(这个中断叫做系统定时器中断),每进入一次中断就可以累加一次时间。

note:注意区分系统定时器和内核定时器的概念,内核定时器是依赖于系统定时器的。

1、节拍率:HZ

        系统定时器频率(节拍率)是在<include/asm-generic/param.h>文件中定义的,也就是HZ。

#ifndef __ASM_GENERIC_PARAM_H
#define __ASM_GENERIC_PARAM_H

#ifndef HZ
#define HZ 100
#endif

#ifndef EXEC_PAGESIZE
#define EXEC_PAGESIZE	4096
#endif

#ifndef NOGROUP
#define NOGROUP		(-1)
#endif

#define MAXHOSTNAMELEN	64	/* max length of hostname */

#ifdef __KERNEL__
# undef HZ
# define HZ		CONFIG_HZ	/* CONFIG_HZ是通过menuconfig配置的产物 */
# define USER_HZ	100		/* some user interfaces are */
# define CLOCKS_PER_SEC	(USER_HZ)       /* in "ticks" like times() */
#endif

#endif /* __ASM_GENERIC_PARAM_H */

在系统启动时按照HZ值对硬件进行设置(怎么设置的?)。

一般 ARM 体系结构的节拍率多数都等于 100。在编译 Linux 内核的时候可以通过图形化界面

设置系统节拍率,按照如下路径打开配置界面:

-> Kernel Features
-> Timer frequency (<choice> [=y])

2、jiffies全局变量

全局变量 jiffies 用来记录自系统启动以来产生的节拍的总数。启动时,内核将该变量初始化为 0,此后,每次时钟中断处理程序都会增加该变量的值。因为一秒内时钟中断的次数等于 Hz,所以 jiffes 一秒内增加的值也就为 Hz,系统运行时间以秒为单位计算,就等于 jiffes/Hzjiffes=seconds*HZjiffies 定义在文件include/linux/jiffies.h 中,定义如下:

extern u64 __jiffy_data jiffies_64;
extern unsigned long volatile __jiffy_data jiffies;

因此,在 32 位体系结构上jiffies 是 32 位,在时钟频率为 100 的情况下,497 天后会溢出,如果频率是 100049.7 天后会溢出。溢出后,它的值会回绕到 0。回绕会引起许多问题,下面的宏可以正确的处理节拍计数回绕的情况:

三、相关数据结构和API

1、数据结构

Linux 内核使用 timer_list 结构体表示内核定时器, timer_list 定义在文件include/linux/timer.h 中

struct timer_list {
	/*
	 * All fields that change during normal runtime grouped to the
	 * same cacheline
	 */
	struct list_head entry;
	unsigned long expires;					/* 定时器超时时间,单位是节拍数 */
	struct tvec_base *base;

	void (*function)(unsigned long);		/* 定时处理函数 */
	unsigned long data;						/* 要传递给 function 函数的参数 */

	int slack;

#ifdef CONFIG_TIMER_STATS
	int start_pid;
	void *start_site;
	char start_comm[16];
#endif
#ifdef CONFIG_LOCKDEP
	struct lockdep_map lockdep_map;
#endif
};
  • entry:所有的定时器都会根据到期的时间被分配到一组链表中的一个中,该字段是链表的节点成员。
  • expires:字段指出了该定时器的到期时刻,也就是期望定时器到期时刻的jiffies计数值。这是一个绝对值,不是距离当前时刻再过多少jiffies。
  • function:是一个回调函数指针,定时器到期时,系统将会调用该函数,用于响应该定时器的到期事件。
  • data:要传递给 function 函数的参数

2、API

如果需要在定时器超时前停止定时器,可以使用del_timer()函数,如果定时器还未被激活该函数返回0,否则返回1。不需要为已经超时的定时器使用该函数,因为它们会自动删除。

当删除定时器时,必须注意一个潜在的竞争条件,当del_timer()返回后,可以保证的只有定时器不会再被激活,但是在多处理器机器上定时器中断可能已经在其他处理器上运行了,所以删除定时器时需要等待可能在其他处理器上运行的定时器处理程序都退出,这时就要使用del_timer_sync()函数执行删除工作,和del_timer()函数不同,del_timer_sync()函数不能在中断上下文中使用。

从4.14 Linux内核开始使用带有三个args的timer_setup()替换掉之前的init_timer();

四、简单使用

#include <linux/timer.h>
#include <linux/jiffies.h>

struct timer_list timer; /* 定义定时器 */

/* 定时器回调函数 */
void function(unsigned long arg)
{
	 /*
	 * 定时器处理代码
	 */

    /* 如果需要定时器周期性运行的话就使用 mod_timer 11 * 函数重新设置超时值并且启动定时器。*/ 
    mod_timer(&timer, jiffies + msecs_to_jiffies(2000));
 }
 
 /* 初始化函数 */
void init(void)
{
	 init_timer(&timer); /* 初始化定时器 */
	
	 timer.function = function; /* 设置定时处理函数 */
	 timer.expires=jiffies + msecs_to_jiffies(2000);/* 设置超时时间 2 秒 */
	 //timer.data = arg; /* 给回调函数传入参数 */
	 add_timer(&timer); /* 启动定时器 */
}

/* 退出函数 */
void exit(void)
{
	 del_timer(&timer); /* 删除定时器 */
	 /* 或者使用 */
	 //del_timer_sync(&timer);
}

ref:

Linux 内核定时器 - sudochen - 博客园

Linux内核定时器简介及其简单使用_一只青木呀的博客-CSDN博客_linux 定时器

LInux内核定时器_月如风清的博客-CSDN博客_linux内核定时器实现

linux内核中使用定时器_Legendary_wasper的博客-CSDN博客

内核定时器API之timer_setup | DD'Notes

c - Adaptation from old init_timer to new timer_setup - Stack Overflow

3.10.1. linux内核定时器 — ywg_dev_doc 0.1 文档

源码分析

Linux内核定时器和工作队列的总结和实例 - 简书

linux 内核 定时器(timer)实现机制_老王不让用的博客-CSDN博客_linux timer 内核

  • 0
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值