Linux驱动中的延时功能不准确?

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

我想在我的驱动程序代码中实现 8 毫秒的延迟。我使用了

msleep
函数,但是我发现我只循环了两次。
dmesg
中两次打印的时间差其实是10ms,不应该是2ms吗?有什么问题吗?

dmesg
的一部分:

[  386.199343] this is ioctl
[  386.199359] ioctl value = 0
[  386.210085] ioctl value = 1
驱动程序代码中的

ioctl
功能:

static long spiio_drv_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
        int i = 0;
        int value = 0;
        int *param = (int *)arg;
        printk("this is ioctl\n");

        switch (cmd)
        {
                case 0: /*no sleep*/
                        *param = 0;
                case 1: /*SPIIO_IOCTL_CMD*/
                        do {
                                value = gpio_get_value(spiio_gpio);
                                printk("ioctl value = %d\n", value);
                                if (value == 1) {
                                        return 1;
                                } else {
                                        if (*param) {
                                                msleep(1);
                                        }
                                        i ++;
                                }

                        } while(i < *param);
                        break;
                default:
                        printk("spiio ioctrl cmd %d is error", cmd);
                        return -1;

        }
        return 0;
}
c linux linux-kernel
1个回答
0
投票

有什么问题吗?

有2个问题。

第一个问题是,当无法保证任何延迟或睡眠不会比请求的时间长得多时,您期望它是精确的(例如,在请求的时间到期之后但在函数之前可能会发生中断或任务切换)将控制权返回给您的代码)。在循环中,最好的替代方案是某种带有

sleep_until(when)
when += period;
,这样如果前一个睡眠需要更长的时间,那么下一个睡眠会自动补偿(通过更短),并且额外不需要的时间不能/不会累积并且随着循环的每次迭代而变得更糟。此外,
msleep()
可能不是最好使用的函数(例如与
usleep_range()
相比)。

另一个问题是

msleep()
在Linux中的实现很糟糕。具体来说,Linux 有两种不同的计时系统。对于第一个/最旧的系统,一个计时器被配置为以固定频率(例如 100 Hz 或每 10 毫秒)生成一个中断,然后所有内容(所有时间延迟、所有调度等)都建立在其之上。当没有多核 CPU 和电源管理的时候,这被认为是“可以接受的”。第二个/较新的系统称为“无滴答”,并涉及设置底层(硬件)计时器以在“尽可能精确”的最快到期时间创建中断。因为你的时间延迟正好是 10 毫秒,所以 Linux 很可能正在使用旧的/坏的“10 毫秒滴答”系统,并且尚未更新为使用更新的/更好的“无滴答”系统。

当然,您希望的“理论上最好的”是一种分割方法,其中内核确定它可以安全睡眠的最长时间(运行其他任务或节省电量),然后执行一个小的最终“忙等待”循环以获得最大限度。精确。 AFAIK Linux 从来没有为任何类型的延迟或睡眠的“ticks”或“tickless”这样做过;但您也许可以自己实现它(例如,使用

 schedule_timeout_uninterruptible()
ktime_get()
的组合,实现某种
wait_until(when)
)。

注意:您还可以通过重新配置内核(启用“CONFIG_HZ=1000”或无滴答)来使 Linux 不那么糟糕;但如果您需要确保您的代码对其他人有效,您可能会想做相反的事情。

© www.soinside.com 2019 - 2024. All rights reserved.