linux内核编程之内核定时器

时间:2022-07-17 22:39:20

【版权声明:转载请保留出处:blog.csdn.net/gentleliu。邮箱:shallnew*163.com】

如果我们需要在将来某个时间点调度执行某个动作,同时在该时间点到达之前不会阻塞当前进程,可以使用内核定时器。内核定时器可用来在未来的某个特定时间点调度执行某个函数,从而可用于完成许多任务。
Linux 内核所提供的用于操作定时器的数据结构和函数(位于 <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; /* 期望定时器执行的jiffies值 */
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
};

使用定时器必须初始化,使用函数
void init_timer(struct timer_list * timer);
然后还需为定时器结构成员expires、function、data(需要的话)赋值。
使用如下函数注册定时器:
void add_timer(struct timer_list * timer);
这样定时器将在expires之后执行函数function,不过此时只能执行一次,如果想在之后每个expires时间都执行function函数的话,需要在function函数里面修改定时器expires的值。使用如下函数修改:
int mod_timer(struct timer_list *timer, unsigned long expires);
在定时器处理函数中,在做完相应的工作后,往往会延后 expires 并将定时器再次添加到内核定时器链表,以便定时器能再次被触发。

一个示例如下:
#include <linux/module.h>#include <linux/init.h>
#include <linux/version.h>

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

struct timer_list sln_timer;

void sln_timer_do(unsigned long l)
{
mod_timer(&sln_timer, jiffies + HZ);//HZ为1秒,在此时间之后继续执行

printk(KERN_ALERT"jiffies: %ld\n", jiffies);//简单打印jiffies的值
}

void sln_timer_set(void)
{
init_timer(&sln_timer);//初始化定时器

sln_timer.expires = jiffies + HZ; //1s后执行
sln_timer.function = sln_timer_do; //执行函数

add_timer(&sln_timer); //向内核注册定时器
}

static int __init sln_init(void)
{
printk(KERN_ALERT"===%s===\n", __func__);

sln_timer_set();
return 0;
}

static void __exit sln_exit(void)
{
printk(KERN_ALERT"===%s===\n", __func__);

del_timer(&sln_timer);//删除定时器
}

module_init(sln_init);
module_exit(sln_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("sln");

像定时器这种周期性的任务还可以使用延时工作队列来实现。
给一个示例:
#include <linux/module.h>#include <linux/init.h>
#include <linux/version.h>

#include <linux/workqueue.h>
#include <linux/delay.h>

static struct workqueue_struct *sln_wq = NULL;
static struct delayed_work sln_dwq;


static void sln_do(struct work_struct *ws)
{
queue_delayed_work(sln_wq, &sln_dwq, 1000);
printk(KERN_ALERT"jiffies: %ld\n", jiffies);
}

static int __init sln_init(void)
{
printk(KERN_ALERT"===%s===\n", __func__);

sln_wq = create_workqueue("sln_work_queue");
INIT_DELAYED_WORK(&sln_dwq, sln_do);
queue_delayed_work(sln_wq, &sln_dwq, 0);

return 0;
}

static void __exit sln_exit(void)
{
printk(KERN_ALERT"===%s===\n", __func__);

cancel_delayed_work(&sln_dwq);
flush_workqueue(sln_wq);
destroy_workqueue(sln_wq);
}

module_init(sln_init);
module_exit(sln_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("allen");