IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> 【Linux】Linux5.4.70内核定时器的使用 -> 正文阅读

[系统运维]【Linux】Linux5.4.70内核定时器的使用

1. 定时器简介

本篇文章介绍内核定时器是基于内核Linux5.4.70版本,它是内核用来控制再未来某个时间点(基于jiffies)调度执行某个函数的一种机制,代码实现位于include/linux/timer.hkernel/time/timer.c文件中。

定时器数据结构,如下:

struct timer_list {
	/*
	 * All fields that change during normal runtime grouped to the
	 * same cacheline
	 */
	struct hlist_node	entry; // 定时器列表
	unsigned long		expires; // 定时器到期时间(linux的jiffies基准时间)
	void			(*function)(struct timer_list *); // 定时器处理函数
	u32			flags;

#ifdef CONFIG_LOCKDEP
	struct lockdep_map	lockdep_map;
#endif
};

Note:新版本内核对于void (*function)(struct timer_list *)处理函数的参数发生了变化,struct timer_list *定时器地址可以通过from_timer也就是container_of计算出传参进来的结构体首地址,这样来达到传参的目标。使用例子如下:(不完整,只为说明问题。)

#define from_timer(var, callback_timer, timer_fieldname) \
	container_of(callback_timer, typeof(*var), timer_fieldname)

// 为每个key定义了一个timer
struct gpio_key_cfg
{
	int gpio_num;
	int gpio_irq;
	int gpio_flag;
	struct gpio_desc *gpiod;
	struct timer_list key_timer;
};

static void key_timer_expires(struct timer_list *t)
{
	int val;

	/**
	 *这里就是通过struct timer_list *t来获取该gpio key的struct gpio_key_cfg地址。
	 * 这样及知道了是哪个timer expires,还知道了是哪个gpio产生的事件。它就是这样来给timer来传递参数。
	 */
	struct gpio_key_cfg *pGpioKey = from_timer(pGpioKey, t, key_timer);

	val = gpiod_get_value(pGpioKey->gpiod);

	printk("key_timer_expires %d %d\n", pGpioKey->gpio_num, val);
}

timer_setup(&pGpioKeyCfg[i].key_timer, key_timer_expires, 0); // 在probe中,为每一个key创建一个timer
mod_timer(&pGpioKey->key_timer, jiffies + HZ/50);  // key中断发生后,启动timer。

2. Timer相关API介绍

函数说明
timer_setup(timer, callback, flags)初始化定时器,主要是初始化 timer_list 结构体,
设置其中的函数、flags。
DEFINE_TIMER(_name, _function)初始化定时器,主要是定义并初始化 timer_list 结构体,
设置其中的函数、flags默认为0。
void add_timer(struct timer_list *timer)向内核添加定时器。timer->expires 表示超时时间。
当超时时间到达,内核就会调用这个函数:timer->function(timer->data)。
int mod_timer(struct timer_list *timer, unsigned long expires)修改定时器的超时时间
int timer_pending(const struct timer_list * timer)定时器状态查询,如果在系统的定时器列表中则返回1,否则返回0;
int del_timer(struct timer_list * timer)删除定时器。

3. Timer时间单位

在内核的配置中,我们可以看到CONFIG_HZ的配置,如下:
在这里插入图片描述
这表示内核每秒中会发生 100 次系统滴答中断(tick),这就像人类的心跳一样,这是 Linux 系统的心跳。每发生一次 tick 中断,全局变量 jiffies 就会累加 1。

CONFIG_HZ=100 表示每个滴答是 10ms。

定时器的时间就是基于 jiffies ,我们修改超时时间时,一般使用这 2 种方法:

mod_timer(&timer, jiffies + xxx); // xxx 表示多少个滴答后超时,也就是 xxx*10ms
mod_timer(&timer, jiffies + 2*HZ); // HZ 等于 CONFIG_HZ,2*HZ 就相当于 2 秒

4. Timer Demo测试验证

下面Demo使用了2种方法初始化Timer:

  1. 方法一:timer_setup(&test_timer1, kernel_timer_expires, 0);
  2. 方法二:DEFINE_TIMER(test_timer2, kernel_timer_expires);

使用mod_timer修改timer超时间并启动,在不使用的时del_timer删除Timer。

#include <linux/init.h>
#include <linux/module.h>
#include <linux/timer.h>

static void kernel_timer_expires(struct timer_list *t);

static struct timer_list test_timer1;
//初始化timer2
static DEFINE_TIMER(test_timer2, kernel_timer_expires);

static void kernel_timer_expires(struct timer_list *t)
{
	if(t == &test_timer1){
		printk("Timer 1 is coming\r\n");
		mod_timer(&test_timer1, jiffies + 1*HZ); // 重新设置timer1 1s timeout
	}else if(t == &test_timer2){
		printk("Timer 2 is coming\r\n");
		mod_timer(&test_timer2, jiffies + 2*HZ); // 重新设置timer2 2s timeout
	}else{
		printk("Err: timer is unknown!!!\r\n");
	}
}

static int __init kernel_timer_init(void)
{
	printk("Enter timer test...\r\n");

	//初始化timer1
	timer_setup(&test_timer1, kernel_timer_expires, 0);

	//启动timer1、timer2
	mod_timer(&test_timer1, jiffies + 1*HZ); // 1s timeout
	mod_timer(&test_timer2, jiffies + 2*HZ); // 2s timeout
	
	return 0;
}

static void __exit kernel_timer_exit(void)
{	
	printk("Exit timer test!!!\r\n");
	
	del_timer(&test_timer1);	
	del_timer(&test_timer2);
}

module_init(kernel_timer_init);
module_exit(kernel_timer_exit);

编译烧录验证如下:
在这里插入图片描述

5. 定时器内部机制简单分析

定时器就是通过软件中断来实现的,它属于 TIMER_SOFTIRQ 软中断。对于 TIMER_SOFTIRQ 软中断,初始化代码如下:
在这里插入图片描述
当发生硬件中断时,硬件中断处理完后,内核会调用软件中断的处理函数。对于 TIMER_SOFTIRQ,会调用 run_timer_softirq,它的函数如下:

run_timer_softirq
	__run_timers(base);
		while (time_after_eq(jiffies, base->clk)) {
			……
			expire_timers(base, heads + levels);
				fn = timer->function; // 获取当前timer的function函数。
				call_timer_fn(timer, fn, baseclk);
					fn(timer);  // 调用超时timer的function函数。

jiffies 大于或等于 timer->expires 时,该timer 就超时。在 TIMER_SOFTIRQ 的处理函数中,会从链表中把这些超时的 timer 取出来,执行其中的函数。

??????系统是如何产生滴答的 ??????
在IMX6ULL开发板执行命令cat /proc/interrupts,可以看到 CPU0 下有一个数值变化特别快,它就是滴答中断:
在这里插入图片描述

通过上面的截图可以发现滴答中断名字就是“i.MX Timer Tick”,通过名字可以找到对应的源码timer-imx-gpt.c如下:
在这里插入图片描述
mxc_timer_interrupt 就是滴答中断的处理函数,代码如下:
在这里插入图片描述
经过ced->event_handler(ced)整个内核代码搜索发现,它调用的是tick_handle_periodic位于 kernel\time\tick-common.c 中,它里面的调用关系如下:

tick_handle_periodic
	tick_periodic(cpu);
		do_timer(1);
			jiffies_64 += ticks; // jiffies 就是 jiffies_64

jiffies 就是 jiffies_64,因为在 arch\arm\kernel\vmlinux.lds.S 被定义如下:
在这里插入图片描述

6. 参考资料

1:Linux内核定时器和工作队列的总结和实例
https://www.jianshu.com/p/a3ad64ddbd89

2:linux内核定时器使用及原理
https://blog.csdn.net/lizhiguo0532/article/details/6406161

3:Linux定时器的使用
https://wenku.baidu.com/view/cab7028fcc22bcd126ff0c58.html

4:Linux内核定时器
https://www.cnblogs.com/forthetechnology/p/10541364.html

5:Linux内核定时器
https://www.cnblogs.com/yangjiguang/p/7643034.html

6:韦东山资料
《嵌入式Linux应用开发完全手册_韦东山全系列视频文档-IMX6ULL开发板.pdf》

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2021-09-27 14:29:21  更:2021-09-27 14:31:09 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 15:56:39-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码