Linux内核定标准定时器
linux-dash
A beautiful web dashboard for Linux
项目地址:https://gitcode.com/gh_mirrors/li/linux-dash
免费下载资源
·
Linux驱动定时器的使用
内核使用绝对时间来了解具体的时间,也就是一天的日期和时间,而相对时间则被内核调度程序使用。对于绝对时间,有一个称为实时时钟的硬件芯片(RTC)。
内核定时器有两种
- 标准定时器或系统定时器
- 高精度定时器
标准定时器
标准定时器是内核定时器,它以jiffy为粒度运行。
常量HZ是jiffies在1s内递增的次数,每个增量被称为一个Tick。
定时器API
定时器在内核中表示为timer_list的一个实例
struct timer_list {
/*
* All fields that change during normal runtime grouped to the
* same cacheline
*/
struct hlist_node entry;
unsigned long expires;
void (*function)(struct timer_list *);
u32 flags;
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
#endif
};
expires
以jiffies为单位,function为回调函数。
初始化定时器
- 设置定时器。设置定时器,提供用户自定义的回调函数
/**
* timer_setup - prepare a timer for first use
* @timer: the timer in question
* @callback: the function to call when timer expires
* @flags: any TIMER_* flags
*
* Regular timer initialization should use either DEFINE_TIMER() above,
* or timer_setup(). For timers on the stack, timer_setup_on_stack() must
* be used and must be balanced with a call to destroy_timer_on_stack().
*/
#define timer_setup(timer, callback, flags) \
__init_timer((timer), (callback), (flags))
#define timer_setup_on_stack(timer, callback, flags) \
__init_timer_on_stack((timer), (callback), (flags))
- 设置过期时间。当定时器初始化时,需要在启动回调之前设置定时时间。
/**
* mod_timer - modify a timer's timeout
* @timer: the timer to be modified
* @expires: new timeout in jiffies
*
* mod_timer() is a more efficient way to update the expire field of an
* active timer (if the timer is inactive it will be activated)
*
* mod_timer(timer, expires) is equivalent to:
*
* del_timer(timer); timer->expires = expires; add_timer(timer);
*
* Note that if there are multiple unserialized concurrent users of the
* same timer, then mod_timer() is the only safe way to modify the timeout,
* since add_timer() cannot modify an already running timer.
*
* The function returns whether it has modified a pending timer or not.
* (ie. mod_timer() of an inactive timer returns 0, mod_timer() of an
* active timer returns 1.)
*/
int mod_timer(struct timer_list *timer, unsigned long expires)
{
return __mod_timer(timer, expires, 0);
}
EXPORT_SYMBOL(mod_timer);
- 释放定时器。定时器使用完毕之后需要释放。
/**
* del_timer - deactivate a timer.
* @timer: the timer to be deactivated
*
* del_timer() deactivates a timer - this works on both active and inactive
* timers.
*
* The function returns whether it has deactivated a pending timer or not.
* (ie. del_timer() of an inactive timer returns 0, del_timer() of an
* active timer returns 1.)
*/
int del_timer(struct timer_list *timer)
{
struct timer_base *base;
unsigned long flags;
int ret = 0;
debug_assert_init(timer);
if (timer_pending(timer)) {
base = lock_timer_base(timer, &flags);
ret = detach_if_pending(timer, base, true);
raw_spin_unlock_irqrestore(&base->lock, flags);
}
return ret;
}
EXPORT_SYMBOL(del_timer);
对于不活动的定时器,返回0,对于活动的定时器,返回1。
/**
* del_timer_sync - deactivate a timer and wait for the handler to finish.
* @timer: the timer to be deactivated
*
* This function only differs from del_timer() on SMP: besides deactivating
* the timer it also makes sure the handler has finished executing on other
* CPUs.
*
* Synchronization rules: Callers must prevent restarting of the timer,
* otherwise this function is meaningless. It must not be called from
* interrupt contexts unless the timer is an irqsafe one. The caller must
* not hold locks which would prevent completion of the timer's
* handler. The timer's handler must not call add_timer_on(). Upon exit the
* timer is not queued and the handler is not running on any CPU.
*
* Note: For !irqsafe timers, you must not hold locks that are held in
* interrupt context while calling this function. Even if the lock has
* nothing to do with the timer in question. Here's why::
*
* CPU0 CPU1
* ---- ----
* <SOFTIRQ>
* call_timer_fn();
* base->running_timer = mytimer;
* spin_lock_irq(somelock);
* <IRQ>
* spin_lock(somelock);
* del_timer_sync(mytimer);
* while (base->running_timer == mytimer);
*
* Now del_timer_sync() will never return and never release somelock.
* The interrupt on the other CPU is waiting to grab somelock but
* it has interrupted the softirq that CPU0 is waiting to finish.
*
* The function returns whether it has deactivated a pending timer or not.
*/
int del_timer_sync(struct timer_list *timer);
等待处理程序(即使在另一个cpu上执行)执行完成,不应该持有阻止处理程序完成的锁,这样会导致死锁,应该在模块清理流程中释放定时器,可以独立检查定时器是否在运行。
/**
* timer_pending - is a timer pending?
* @timer: the timer in question
*
* timer_pending will tell whether a given timer is currently pending,
* or not. Callers must ensure serialization wrt. other operations done
* to this timer, eg. interrupt contexts, or other CPUs on SMP.
*
* return value: 1 if the timer is pending, 0 if not.
*/
static inline int timer_pending(const struct timer_list * timer)
{
return !hlist_unhashed_lockless(&timer->entry);
}
三、测试代码
注册定时器之后,在timer_callback()修改定时器的延时时间,这个是第一种方式实现,大家可以尝试使用add_timer()方式实现。
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/kernel.h>
//毫秒
#define TIMEOUT 5000
//定义定时器
struct timer_list mytimer;
unsigned int count = 0;
//定时器处理函数 mod_timer(&mytimer, jiffies + TIMEOUT);
static void timer_callback(struct timer_list *data) {
printk("Timer Callback function Called [%d]\n", count++);
mod_timer(&mytimer, jiffies + msecs_to_jiffies(TIMEOUT));
}
//定时器初始化过程
static int __init timer_init(void) {
/* 初始化一个定时器 */
timer_setup(&mytimer, timer_callback, 0);
/* 修改定时器的延时时间 */
mod_timer(&mytimer, jiffies + msecs_to_jiffies(TIMEOUT));
return 0;
}
static void __exit timer_exit(void) {
/* 卸载驱动移除注册的定时器 */
del_timer(&mytimer);
}
module_init(timer_init);
module_exit(timer_exit);
MODULE_AUTHOR("curtis");
MODULE_LICENSE("GPL");
四、注意事项
-
没有 current 指针、不允许访问用户空间。因为没有进程上下文,相关代码和被中断的进程没有任何联系。
-
不能执行休眠(或可能引起休眠的函数)和调度。
-
任何被访问的数据结构都应该针对并发访问进行保护,以防止竞争条件。
GitHub 加速计划 / li / linux-dash
10.39 K
1.2 K
下载
A beautiful web dashboard for Linux
最近提交(Master分支:2 个月前 )
186a802e
added ecosystem file for PM2 4 年前
5def40a3
Add host customization support for the NodeJS version 4 年前
更多推荐
已为社区贡献7条内容
所有评论(0)