Linux 驱动之内核定时器

1、定时器

之前说过两类跟时间相关的内核结构。

1、延时:通过忙等待或者睡眠机制实现延时。

2、tasklet和工作队列,通过某种机制使工作推后执行,但不知道执行的具体时间。

接下来要介绍的定时器,能够使工作在指定的时间点上执行,而且不需要使用忙等待这类的延时方法。通过定义一个定时器,告之内核在哪个时间需要执行什么函数就可以了,等时间一到,内核会就执行指定的函数。

2、使用定时器

定时器的使用很简单,只需要三部:

1、定义定时器结构体timer_list。

2、设置超时时间,定义定时器处理函数和传参。

3、激活定时器

代码

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

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

#if 0  //定义并初始化定时器结构体timer_list。
/*include/linux/timer.h*/
struct timer_list {
	struct list_head entry;
	unsigned long expires; //设置在执行定时器处理函数的时间

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

	struct tvec_base *base;

	#ifdef CONFIG_TIMER_STATS
		void *start_site;
		char start_comm[16];
		int start_pid;
	#endif

};
#endif

struct timer_list my_timer; //1.定义定时器结构体timer_list

void timer_func(unsigned long data) //2.定义定时器处理函数
{
	printk("time out![%d] [%s]\n", (int)data, current->comm); //打印当前进程
}

static int __init test_init(void) //模块初始化函数
{
	 init_timer(&my_timer); //1.初始化timer_list结构

	 my_timer.expires = jiffies + 5*HZ; //2.设定定时器处理函数触发时间为5秒
	 my_timer.function = timer_func; //2.给结构体指定定时器处理函数
	 my_timer.data = (unsigned long)99; //2.设定定时器处理函数的传参

	 add_timer(&my_timer); //3.激活定时器
	 printk("hello timer,current->comm[%s]\n", current->comm);
	 return 0;
 }

static void __exit test_exit(void) //模块卸载函数
{
	printk("good bye timer\n");
}

三、定时器的删除和修改

上面说了,激活定时器后只能执行一遍,如果要实现隔指定时间又重复执行,那就要修改一下代码。

在定时器处理函数中加上两条代码:

my_timer.expires = jiffies + 2*HZ; //重新设定时间,在两秒后再执行

add_timer(&my_timer); //再次激活定时器

这样的话,每个2秒就会再次执行定时器处理函数。

这两条代码也相当与一下的函数:

mod_timer(&my_timer, jiffies + 2*HZ);

/*kernel/timer.c*/

int mod_timer(struct timer_list *timer, unsigned long expires)

这是改变定时器超时时间的函数,如果在指定的定时器(timer)没超时前调用,超时时间会更新为新的新的超时时间(expires)。如果在定时器超时后调用,那就相当于重新指定超时时间并再次激活定时器。

如果想在定时器没有超时前取消定时器,可以调用以下函数:

/*kernel/timer.c*/

int del_timer(struct timer_list *timer)

该函数用来删除还没超时的定时器。

时间: 2024-08-10 14:59:45

Linux 驱动之内核定时器的相关文章

【驱动】内核定时器的使用

链接:https://blog.csdn.net/jidonghui/article/details/7449546 LINUX内核定时器是内核用来控制在未来某个时间点(基于jiffies)调度执行某个函数的一种机制,其实现位于 <linux/timer.h> 和 kernel/timer.c 文件中.被调度的函数肯定是异步执行的,它类似于一种"软件中断",而且是处于非进程的上下文中,所以调度函数必须遵守以下规则: 1) 没有 current 指针.不允许访问用户空间.因为

驱动笔记 - 内核定时器

#include <linux/timer.h> struct timer_list{ struct list_head entry; 内核使用 unsigned long expires; 超时的jiffies值 void (*function)(unsigned long); 超时处理函数 unsigned long data; 超时处理函数参数 struct tvec_base *base; 内核使用} void init_timer(struct timer_list *timer);

linux驱动之内核多线程(二)

本文摘自http://www.cnblogs.com/zhuyp1015/archive/2012/06/11/2545702.html 内核多线程是在项目中使用到,自己也不熟悉,遇到一个很囧的问题,导致cpu运行100%. 这是写的第一个内核线程程序,通过全局变量来实现两个内核线程之间的通信.但是这里遇到致命错误,就是:每当 wait_event_interruptible()被wake_up_interruptible 唤醒之后线程就进入死循环.后面发现是线程不会主动的自己调度,需要显式的通

linux驱动之内核多线程(一)

本文摘自http://www.cnblogs.com/zhuyp1015/archive/2012/06/11/2545624.html Linux内核可以看作一个服务进程(管理软硬件资源,响应用户进程的种种合理以及不合理的请求).内核需要多个执行流并行,为了防止可能的阻塞,支持多线程是必要的.内核线程就是内核的分身,一个分身可以处理一件特定事情.内核线程的调度由内核负责,一个内核线程处于阻塞状态时不影响其他的内核线程,因为其是调度的基本单位.这与用户线程是不一样的.因为内核线程只运行在内核态,

linux驱动之内核多线程(三)

本文摘自 http://www.cnblogs.com/zhuyp1015/archive/2012/06/13/2548458.html 接上 一篇文章 ,这里介绍另一种线程间通信的方式:completion机制.Completion机制是线程间通信的一种轻量级机制:允许一个线程告诉另一个线程工作已经完成.为使用 completion, 需要包含头文件 <linux/completion.h>. 可以通过以下方式来创建一个 completion : DECLARE_COMPLETION(my

Linux 驱动开发索引

1.嵌入开发环境搭建 Telnet 在 mini2440 上的移植 Opencv-2.4.9 在 mini2440 上的移植 搭建嵌入式开发环境总结 2.Linux 设备驱动 Linux 驱动程序头文件 一步一步学习Linux驱动之驱动模块MakeFile解析 一步一步学习 Linux 驱动之(Kconfig.Makefile) 一步一步学习 Linux 驱动之字符设备 LED 静态编译进 Linux 内核 内核怎么通过主设备号找驱动.次设备号找设备 Linux 驱动之内核空间分配内存 一步一步

Linux驱动开发常用头文件

头文件目录中总共有32个.h头文件.其中主目录下有13个,asm子目录中有4个,linux子目录中有10个,sys子目录中有5个.这些头文件各自的功能如下: 1.主目录 <a.out.h>:a.out头文件,定义了a.out执行文件格式和一些宏.<const.h>:常数符号头文件,目前仅定义了i节点中i_mode字段的各标志位.<ctype.h>:字符类型头文件,定义了一些有关字符类型判断和转换的宏.<errno.h>:错误号头文件,包含系统中各种出错号.(

编写linux驱动所用到的头文件(转)

转自:http://blog.csdn.net/lufeiop02/article/details/6448497 关于linux驱动(应用)程序头文件使用 收藏 驱动程序: #include <linux/***.h> 是在linux-2.6.29/include/linux下面寻找源文件.#include <asm/***.h> 是在linux-2.6.29/arch/arm/include/asm下面寻找源文件.#include <mach/***.h> 是在li

disk磁盘管理与Linux驱动编写

磁盘管理 一.关于硬盘接口 安装linux red hat系统,到分区时发现硬盘驱动器设备 /dev/sda             #sata接口设备名 /dev/sda1 #sda对应的物理分区 /dev/sda2 /dev/sda3 而又的安装时硬盘驱动设备名为 /dev/hda #IDE接口设备目录 /dev/hda1 sda和hda有什么区别那? HDA是使用了ide接口的硬盘的名称.SDA是sata接口的硬盘的名称.在最新的2.6.19内核里,所有的硬盘都叫SDA了. GERUB里填