gpt4 book ai didi

Linux 内核 : Why add_timer() is modifying my "expires" value?

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:55:06 24 4
gpt4 key购买 nike

我正在尝试设置一个周期性计时器,每秒钟触发一个函数,但每次调用之间都有一个小偏差。经过一些调查,我发现这是 add_timer() 调用,它向 expires 字段添加了 2 的偏移量(在我的例子中为 ~2ms)。

为什么要加这个漂移?有没有一种干净的方法来防止它?我并不想获得准确的毫秒精度,我对内核实时限制有一个模糊的理解,但至少可以避免每次调用时这种故意延迟。

这是测试模块的输出。每对数字是调用前后 expires 字段的值:

[100047.127123] Init timer 1000
[100048.127986] Expired timer 99790884 99790886
[100049.129578] Expired timer 99791886 99791888
[100050.131146] Expired timer 99792888 99792890
[100051.132728] Expired timer 99793890 99793892
[100052.134315] Expired timer 99794892 99794894
[100053.135882] Expired timer 99795894 99795896
[100054.137411] Expired timer 99796896 99796898
[...]
[100071.164276] Expired timer 99813930 99813932
[100071.529455] Exit timer

这是来源:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/jiffies.h>
#include <linux/time.h>

static struct timer_list t;

static void timer_func(unsigned long data)
{
unsigned long pre, post;
t.expires = jiffies + HZ;
pre = t.expires;
add_timer(&t);
post = t.expires;
printk("Expired timer %lu %lu\n", pre, post);
}

static int __init timer_init(void)
{
init_timer(&t);
t.function = timer_func;
t.expires = jiffies + HZ;
add_timer(&t);
printk("Init timer %d\n", HZ);
return 0;
}

static void __exit timer_exit(void)
{
del_timer(&t);
printk("Exit timer\n");
}

module_init(timer_init);
module_exit(timer_exit);

最佳答案

我找到了原因。让我们跟踪 add_timer 函数:

add_timer函数调用:

mod_timer(timer, timer->expires);

mod_timer函数调用:

expires = apply_slack(timer, expires);

然后继续实际修改计时器。

apply_slack功能说:

/*
* Decide where to put the timer while taking the slack into account
*
* Algorithm:
* 1) calculate the maximum (absolute) time
* 2) calculate the highest bit where the expires and new max are different
* 3) use this bit to make a mask
* 4) use the bitmask to round down the maximum time, so that all last
* bits are zeros
*/

在继续之前,让我们看看计时器的松弛度是多少。 init_timer宏最终调用 do_init_timer默认情况下将松弛设置为 -1

有了这些知识,让我们减少 apply_slack 并看看它还剩下什么:

static inline
unsigned long apply_slack(struct timer_list *timer, unsigned long expires)
{
unsigned long expires_limit, mask;
int bit;

if (timer->slack >= 0) {
expires_limit = expires + timer->slack;
} else {
long delta = expires - jiffies;

if (delta < 256)
return expires;

expires_limit = expires + delta / 256;
}
mask = expires ^ expires_limit;
if (mask == 0)
return expires;

bit = find_last_bit(&mask, BITS_PER_LONG);

mask = (1 << bit) - 1;

expires_limit = expires_limit & ~(mask);

return expires_limit;
}

第一个 if,检查 timer->slack >= 0 失败,所以应用 else 部分。在那部分中,expiresjiffies 之间的区别略小于 HZ(你只是做了 t.expires = jiffies + HZ。因此,函数(包含您的数据)中的 delta 很可能约为 4,而 delta/4 不为零。

这反过来意味着 mask(即 expires ^ expires_limit)不为零。其余部分实际上取决于 expires 的值,但可以肯定的是,它会发生变化。

好了,由于 slack 自动设置为 -1apply_slack 函数正在更改您的 expires 是时候对齐了,我猜,计时器滴答作响。

如果你不想要这个 slack,你可以在 timer_init 中初始化定时器时设置 t.slack = 0;

关于Linux 内核 : Why add_timer() is modifying my "expires" value?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20975047/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com