Linux内核定时器timer_list的使用

内核定时器:

定时器(优势也称为动态地上那个时期或内核定时器)是管理内核流逝时间放的基础。内核经常需要推后执行某些代码,如中断的下半部机制就是为了将工作放到 以后执行。

定时器的使用很简单,你只需要执行一些初始化工作,设置一个超时时间,指定超时发生后的执行函数,然后激活定时器就可以了。指定的函数将在定时器到期时自动执行,注意定时器并周期运行linux 内核定时器,它在超时后自动撤销,不断地创建和撤销,而且它的执行次数不受限制,故被称为动态定时器。

使用注意:

Timer是Linux内核的一种软中断,被调用函数是异步执行的。

由于是软中断,所以函数被执行的时候是处于非进程的上下文中手机linux操作系统,所以有以下规则需要遵守:

不允许访问用户空间不能执行会引起休眠的函数和调度(如mutex)注意并发数据保护最高精度为(1000/HZ)ms,若HZ=1000,则最高精度为1ms内核添加printk后,由于打印函数耗时会导致执行时间延长redhat linux,一般为ms级。

调度函数总是在注册它的同一CPU中运行,即便是在SMP(对称多处理器)系统中。

定时器的数据结构:定义在文件中

struct timer_list {
struct list_head  entry;
unsigned long     expires;
void              (*function)(unsigned long);
unsigned long     data;
struct tvec_base  *base;
...
};

相关函数:

init_timer(struct timer_list*):定时器初始化函数;

add_timer(struct timer_list*):往系统添加定时器;

mod_timer(struct timer_list *, unsigned long jiffier_timerout):修改定时器的超时时间为jiffies_timerout;

d. timer_pending(struct timer_list *):定时器状态查询,如果在系统的定时器列表中则返回1linux 内核定时器,否则返回0;

linux网络体系结构linux内核中网络协议的设计与实现_android内核回归linux_linux 内核定时器

del_timer(struct timer_list*):删除定时器。

使用步骤:

init_timer->[timer.expires=? & timer.function=?]->add_timer->[mod_timer]->del_timer.

具体例子:

//timer.c  每1ms打印一次hello world
#include 
#include 
#include 
struct timer_list mytimer;
static void myfunc(unsigned long data)
{
	printk("------%s------n", (char *)data);
	mod_timer(&mytimer,jiffies + HZ/1000);
}
static int __init mytimer_init(void)
{
	//setup_timer(&mytimer, myfunc, (unsigned long)"Hello,world!");
	init_timer(&mytimer);                     //初始化内核定时器
	mytimer.function = myfunc;            //指定定时时间到后的回调函数
    mytimer.data = (unsigned long)"hello world";  //回调函数的参数
    mytimer.expires = jiffies+HZ/1000;        //定时时间 1ms 

android内核回归linux_linux 内核定时器_linux网络体系结构linux内核中网络协议的设计与实现

add_timer(&mytimer); return 0; } static void __exit mytimer_exit(void) { del_timer(&mytimer); } module_init(mytimer_init); module_exit(mytimer_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("KUNAlY"); MODULE_DESCRIPTION("Demo for timer");

Makefile文件:

obj-m:=timer.o
PWD:=$( pwd)
KERNELPATH:=/lib/modules/$(shell uname -r)/build
all:
	make -C $(KERNELPATH) M=$(PWD) modules
clean:

linux 内核定时器_linux网络体系结构linux内核中网络协议的设计与实现_android内核回归linux

make -C $(KERNELPATH) M=$(PWD) clean

执行步骤:

即可看到执行效果,在内核每1ms打印一次hello world,timer_list的最大精度为1ms,下面进行检测误差。

检测误差:

#include 
#include 
#include 
#include 
#include 
static struct timer_list tm;  //定义一个定时器
struct timeval oldtv;         //获取系统时间,用来计时
void myfunction(unsigned long arg)
{
    struct timeval tv;
    char *data = (char*)arg;
    
    printk("%s: %lu, %sn", __func__, jiffies, data); 

linux 内核定时器_android内核回归linux_linux网络体系结构linux内核中网络协议的设计与实现

do_gettimeofday(&tv); //获取新的当前时间 printk("%s:%ldmsn", __func__, tv.tv_usec/1000- oldtv.tv_usec/1000); //与上次中断间隔 ms=us/1000 //do_gettimeofday(&oldtv); //获取当前时间 oldtv = tv; tm.expires = jiffies+HZ/1000; //定时时间1ms add_timer(&tm); //重新开始计时 } static int __init demo_init(void) { printk(KERN_INFO "%s : start!...n",__func__); init_timer(&tm); //初始化内核定时器 do_gettimeofday(&oldtv); //获取当前时间 tm.function = myfunction; //指定定时时间到后的回调函数 tm.data = (unsigned long)"hello world"; //回调函数的参数 tm.expires = jiffies+HZ/1000; //定时时间 1ms add_timer(&tm); //将定时器加入内核

android内核回归linux_linux 内核定时器_linux网络体系结构linux内核中网络协议的设计与实现

return 0; } static void __exit demo_exit(void) { printk(KERN_INFO "%s: exit!...n",__func__); del_timer(&tm); //注销定时器 } module_init(demo_init); module_exit(demo_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Kunaly"); MODULE_DESCRIPTION("Demo for timer_test");

执行步骤:

执行结果(每隔几次就会有误差,不能每次精确到1ms):

注意:

本运行环境为:centos7,内核版本为linux-kernel-3.10.0-957.el7.x86_64

新版本的内核4.x, 5.x ,不断更新中,运行会出现一定的偏差,个别函数找不到了,而网上大多都是基于2.6版本的API,导致我再用Ubuntu时使用的5.2版本的内核总是出现一些错误,相关函数需要重新替换。

因需求是精度到1ms的定时器,所以还得再看看内核中hrtimer的使用。

本文原创地址://gulass.cn/lnhdsqdsqysy.html编辑:刘遄,审核员:暂无