Linux内核定时器使用

内核定时器是内核用来控制在未来某个时间点(基于jiffies)调度执行某个函数的一种机制,其实现位于内核源码 linux/timer.h 和 kernel/timer.c 文件中。

被调度的函数肯定是异步执行的,它类似于一种“软件中断”,而且是处于非进程的上下文中,所以调度函数必须遵守以下规则:

  1. 没有 current 指针、不允许访问用户空间。因为没有进程上下文,相关代码和被中断的进程没有任何联系。

  2. 不能执行休眠(或可能引起休眠的函数)和调度。

  3. 任何被访问的数据结构都应该针对并发访问进行保护,以防止竞争条件。

内核定时器的调度函数运行过一次后就不会再被运行了(相当于自动注销),但可以通过在被调度的函数中重新调度自己来周期运行。

定时器的作用

内核定时器由用户控制某个函数(定时器函数)在特定的未来某个时刻执行
内核定时器注册的处理函数只执行一次

内核定时器的结构体定义


struct timer_list {
	/*
	 * All fields that change during normal runtime grouped to the
	 * same cacheline
	 */
	struct hlist_node	entry;	//内核使用
	unsigned long		expires;	//超时时候jiffies的值
	void			(*function)(unsigned long);		//超时处理函数
	unsigned long		data;	//内核调用超时处理函数时传递给它的参数
	u32			flags;

#ifdef CONFIG_TIMER_STATS
	int			start_pid;
	void			*start_site;
	char			start_comm[16];
#endif
#ifdef CONFIG_LOCKDEP
	struct lockdep_map	lockdep_map;
#endif
};

内核定时器操作

静态初始化
#define TIMER_INITIALIZER(_function, _expires, _data)		\
	__TIMER_INITIALIZER((_function), (_expires), (_data), 0)

_function:定时器处理函数
_expires:定时器超时jiffes的值
_data:传递给定时器处理函数的参数

定义定时器
#define DEFINE_TIMER(_name, _function, _expires, _data)		\
	struct timer_list _name =				\
		TIMER_INITIALIZER(_function, _expires, _data)

_name:带定义的内核定时器变量名称
_function:定时器处理函数
_expires:定时器超时jiffes的值
_data:传递给定时器处理函数的参数

动态初始化
void init_timer(struct timer_list * timer);

timer:带初始化的内核的定时器

添加定时器
void  add_timer(struct timer_list * timer);

timer:带添加的内核的定时器

删除定时器

该函数是在定时器超时前将定时器删除。如果在定时超市后,系统会自动将定时器删除。

void  del_timer(struct timer_list * timer);

timer:带删除的内核的定时器

修改定时器
int mod_timer(struct timer_list *timer, unsigned long expires)

timer:修改的内核的定时器
expires:修改的内核的定时器新的超时值

返回值:返回0表示定时器处于不活动状态,返回1表示定时器处于活动状态。

测试源码

/* 实现每隔一秒向内核log中打印一条信息 */
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/time.h>
#include <linux/timer.h>

static struct timer_list tm;
struct timeval oldtv;

void time_callback(unsigned long arg)
{
    struct timeval tv;
    char *strp = (char*)arg;

    printk("%s: %lu, %s\n", __func__, jiffies, strp);

    do_gettimeofday(&tv);
    printk("%s: %ld, %ld\n", __func__,
           tv.tv_sec - oldtv.tv_sec,        //与上次中断间隔 s
           tv.tv_usec- oldtv.tv_usec);        //与上次中断间隔 us

    oldtv = tv;
    tm.expires = jiffies + 1*HZ;    
    add_timer(&tm);        //重新开始计时

}

static int __init demo_init(void)
{
    printk(KERN_INFO "%s : %s : %d\n", __FILE__, __func__, __LINE__);

    init_timer(&tm);    //初始化内核定时器

    do_gettimeofday(&oldtv);        //获取当前时间
    tm.function= time_callback;            //指定定时时间到后的回调函数
    tm.data    = (unsigned long)"hello world";        //回调函数的参数
    tm.expires = jiffies + 1*HZ;        //定时时间
    add_timer(&tm);        //注册定时器

    return 0;

}

static void __exit demo_exit(void)
{
    printk(KERN_INFO "%s : %s : %d\n", __FILE__, __func__, __LINE__);
    del_timer(&tm);        //注销定时器

}

module_init(demo_init);
module_exit(demo_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("zxy");


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值