我想用mod_timer来定时器10毫秒,但是结果总是20毫秒

问题描述 投票:0回答:1

我的驱动测试代码,我想用mod_timer来定时器10毫秒,但结果总是20毫秒。它出什么问题了? ..

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/timer.h>
#include <linux/jiffies.h>
#include <linux/unistd.h>
#include <linux/delay.h>

static struct timer_list my_timer;

void my_timer_callback(struct timer_list *timer)
{
    printk("my_timer_callback called (%lu).\n", jiffies);

    mod_timer(&my_timer, jiffies + msecs_to_jiffies(10));
}

static int __init my_init(void)
{
    printk("Timer module loaded\n");

    timer_setup(&my_timer, my_timer_callback, 0);

    mod_timer(&my_timer, jiffies + msecs_to_jiffies(10));

    return 0;
}

static void __exit my_exit(void)
{
    printk("Timer module unloaded\n");

    del_timer(&my_timer);
}

module_init(my_init);
module_exit(my_exit);

MODULE_AUTHOR("[email protected]");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver);

dmesg 结果:

[   70.391971] my_timer_callback called (4294944328).
[   70.411947] my_timer_callback called (4294944330).
[   70.431944] my_timer_callback called (4294944332).
[   70.451961] my_timer_callback called (4294944334).

内核版本:5.10

.配置: CONFIG_HZ=100

c linux linux-kernel
1个回答
0
投票

根据 OP 的经验,以及本电子邮件消息中所述,在调用计时器到期函数时,由于某些 CPU 正在读取旧的 jiffies 值,而另一个 CPU 正在更新它,因此可能会出现一 jiffy 延迟。

由于 OP 的计时器回调函数会在

jiffies
上添加一个相对量来设置下一个到期时间,因此回调之间的时间可能比所需的时间长一瞬间。可以通过将下一个到期时间设置为相对于前一个到期时间来缓解这种情况。如果一瞬间延迟一致,则所有回调函数将延迟一瞬间运行。但是,有些回调函数可能会按时运行,有些会延迟运行,这可能是不希望的。

如果用例需要更精确的计时,最好使用 hrtimer API,如下面 OP 代码的修改版本所示:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/hrtimer.h>
#include <linux/unistd.h>
#include <linux/delay.h>

static struct hrtimer my_timer;

static enum hrtimer_restart my_timer_callback(struct hrtimer *timer)
{
    s64 now = ktime_to_ns(hrtimer_cb_get_time(timer));
    s64 expires = ktime_to_ns(hrtimer_get_softexpires(timer));
    s64 diff = now - expires;

    printk("my_timer_callback called (now %lld, expired %lld, diff %lld).\n",
           now, expires, diff);

    hrtimer_add_expires_ns(timer, 10 * NSEC_PER_MSEC);
    return HRTIMER_RESTART;
}

static int __init my_init(void)
{
    printk("Timer module loaded\n");

    hrtimer_init(&my_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
    my_timer.function = my_timer_callback;

    hrtimer_start(&my_timer,
                  ktime_add_ms(hrtimer_cb_get_time(&my_timer), 10),
                  HRTIMER_MODE_ABS);

    return 0;
}

static void __exit my_exit(void)
{
    printk("Timer module unloaded\n");

    hrtimer_cancel(&my_timer);
}

module_init(my_init);
module_exit(my_exit);

MODULE_AUTHOR("[email protected]");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver);

模块的 dmesg 输出示例如下所示:

[ 7119.967286] my_timer_callback called (now 7119822903369, expired 7119822900229, diff 3140).
[ 7119.977294] my_timer_callback called (now 7119832911804, expired 7119832900229, diff 11575).
[ 7119.987347] my_timer_callback called (now 7119842964493, expired 7119842900229, diff 64264).
[ 7119.997286] my_timer_callback called (now 7119852903102, expired 7119852900229, diff 2873).
[ 7120.007348] my_timer_callback called (now 7119862964879, expired 7119862900229, diff 64650).
[ 7120.017348] my_timer_callback called (now 7119872964924, expired 7119872900229, diff 64695).
[ 7120.027347] my_timer_callback called (now 7119882964377, expired 7119882900229, diff 64148).
[ 7120.037333] my_timer_callback called (now 7119892950004, expired 7119892900229, diff 49775).
[ 7120.047348] my_timer_callback called (now 7119902964627, expired 7119902900229, diff 64398).
[ 7120.057348] my_timer_callback called (now 7119912964748, expired 7119912900229, diff 64519).
[ 7120.067337] my_timer_callback called (now 7119922952994, expired 7119922900229, diff 52765).
[ 7120.077350] my_timer_callback called (now 7119932966586, expired 7119932900229, diff 66357).
[ 7120.087348] my_timer_callback called (now 7119942964245, expired 7119942900229, diff 64016).
[ 7120.097334] my_timer_callback called (now 7119952950074, expired 7119952900229, diff 49845).
[ 7120.107351] my_timer_callback called (now 7119962966616, expired 7119962900229, diff 66387).
© www.soinside.com 2019 - 2024. All rights reserved.