内核中的标准定时器
迪丽瓦拉
2024-02-02 18:43:11
0

内核使用绝对时间来了解具体的时间,也就是一天的日期和时间,而相对时间则被内核调度程序使用。对于绝对时间,有一个称为实时时钟的硬件芯片(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_LOCKDEPstruct 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*    ----                             ----*                                     *                                       call_timer_fn();*                                       base->running_timer = mytimer;*    spin_lock_irq(somelock);*                                     *                                        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);
}

使用示例(内核版本为5.15.0-52-generic

// timer.c
#include 
#include 
#include 
#include static struct timer_list my_timer;static void timer_callback(struct timer_list *timer)
{printk("%s is called (%ld)\n", __func__, jiffies);
}static int __init test_init(void)
{int ret;printk("Enter into timer module!\n");timer_setup(&my_timer, timer_callback, 0);printk("Setup timer to fire in 300ms (%ld)\n", jiffies);ret = mod_timer(&my_timer, jiffies + msecs_to_jiffies(300));if (ret)printk("Moder timer failed\n");return 0;
}void test_exit(void)
{int ret;printk("Timer example cleanup!\n");ret = del_timer(&my_timer);if (ret)printk("The timer is still in use...\n");
}module_init(test_init);
module_exit(test_exit);
MODULE_LICENSE("GPL");
[52444.589564] Enter into timer module!
[52444.589565] Setup timer to fire in 300ms (4308003645)
[52444.920592] timer_callback is called (4308003728)

相关内容