linux 内核定时器

linux内核中有大量的函数需要时间管理,硬件提供时钟源,时钟源的频率可以设置,设置好以后产生周期性中断,系统通过中断计时。

1.节拍率(tick rate)

系统周期中断频率,可通过menuconfig设置,可设置 100、200、250、300、500、1000hz。

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

设置后,在 ./config 文件内生成 CONFIG_HZ = xxx

动态系统时钟参数,驱动代码可使用宏定义 HZ 定时使用。
/include/asm-generic/param.c

# undef HZ
# define HZ		CONFIG_HZ	/* Internal kernel timer frequency */
# define USER_HZ	100		/* some user interfaces are */
# define CLOCKS_PER_SEC	(USER_HZ)       /* in "ticks" like times() */
#endif /* __ASM_GENERIC_PARAM_H */

2.jiffies

记录系统节拍率
/include/linux/jiffies.h

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

jiffies_64用于64位系统,jiffies用于32位系统。jiffies结构图,图中jiffies_64和jiffies本质一样。
在这里插入图片描述
系统连续运行,jiffies存在溢出上限,linux定义了几个函数处理jiffies的绕回。
/include/linux/jiffies.h

#define time_after(a,b)	//returns true if the time a is after time b.
#define time_before(a,b)	time_after(b,a)
#define time_after_eq(a,b)
#define time_before_eq(a,b)	time_after_eq(b,a)

a通常为jiffies, b为对比值。

代码实现:

unsigned long timeout;
timeout = jiffies + ( 3 *  HZ); /* 延时3s*/
/*判断函数*/
if(time_after(jiffies, timeout)){
	/*超时发生*/
}else{
	/*超时没发生*/
};

为了方便开发,linux定义了一些jiffies 与时间的转换函数:

extern unsigned int jiffies_to_msecs(const unsigned long j);
extern unsigned int jiffies_to_usecs(const unsigned long j);
static inline u64 jiffies_to_nsecs(const unsigned long j)
extern unsigned long msecs_to_jiffies(const unsigned int m);
extern unsigned long usecs_to_jiffies(const unsigned int u);
extern unsigned long timespec_to_jiffies(const struct timespec *value);

便于阅读,上述代码可改为:

unsigned long timeout;
timeout = jiffies + msecs_to_jiffies(3000);
/*判断函数*/
if(time_after(jiffies, timeout)){  /* 延时3s*/
	/*超时发生*/
}else{
	/*超时没发生*/
};

3.内核定时器

定时器结构体
/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;	/*定时器传递参数*/

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

定时器使用流程:

  1. 定义定时器结构体。
  2. 初始化结构体。void init_timer(struct timer_list *timer)
  3. 注册定时器到内核。void add_timer(struct timer_list *timer)
  4. 由于定时器使用一次后自动关闭,重启定时器。int mod_timer(struct timer_list *timer, unsigned long expires)
  5. 关闭定时器。int del_timer_sync(struct timer_list *timer)

代码流程:

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

/* 定时器回调函数 */
void function(unsigned long arg)
{
/*
* 定时器处理代码
*/
/* 如果需要定时器周期性运行的话就使用 mod_timer
* 函数重新设置超时值并且启动定时器。
*/
	mod_timer(&dev->timertest, jiffies + msecs_to_jiffies(2));
}

/* 初始化函数 */
void init(void)
{
	init_timer(&timer); /* 初始化定时器 */
	timer.function = function; /* 设置定时处理函数 */
	timer.expires=jffies + msecs_to_jiffies(2);/* 超时时间 2 秒 */
	timer.data = (unsigned long)&dev; /* 将设备结构体作为参数 */
	add_timer(&timer); /* 启动定时器 */
}

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

4. DEMO

驱动:
https://github.com/Jiongyu/linux_driver_example/blob/master/12_timer/timer.c
测试
https://github.com/Jiongyu/linux_driver_example/blob/master/12_timer/timerApp.c

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值