c - 如果过期,hrtimer 不会返回负值

标签 c timer kernel linux-device-driver kernel-module

timeval v = ktime_to_timeval(hrtimer_get_remaining(timer));

我没有在计时器到期时得到一个负值(我预计 ~ 负 100 毫秒),我得到的是加 800 毫秒,这太离谱了,我无法在预期结果和实际结果之间建立任何联系。
我的第一个教导是 hrtimer_get_remaining 或 ktime_to_timeval 做错了什么,所以我使用了 ktime_to_timespec 和 hrtimer_expires_remaining,但结果是一样的。

还有其他建议吗?

最佳答案

简短回答

可能您得到了正确的结果,但您的解释是错误的。您的代码仅检查 tv_nsec,而忽略 tv_sec,它可能包含 -1。如果您添加 -1 秒并且比 800ms 多一点,您将获得您的 ~-100ms 值。

更长的解释

即使 ns_to_timespec 没有像之前那样调用 set_normalized_timespec,它仍然以相同的方式规范化 timespec 值。这是此函数的当前版本:

struct timespec ns_to_timespec(const s64 nsec)
{
        struct timespec ts;
        s32 rem;

        if (!nsec)
                return (struct timespec) {0, 0};

        ts.tv_sec = div_s64_rem(nsec, NSEC_PER_SEC, &rem);
        if (unlikely(rem < 0)) {               // <-- here is normalization
                ts.tv_sec--;
                rem += NSEC_PER_SEC;
        }
        ts.tv_nsec = rem;

        return ts;
}

仅供引用,几年前这种规范化是这样完成的:

if (unlikely(nsec < 0))
    set_normalized_timespec(&ts, ts.tv_sec, ts.tv_nsec);

我提到这个是因为 set_normalized_timespec 函数上面有一条评论说:

Note: The tv_nsec part is always in the range of
0 <= tv_nsec < NSEC_PER_SEC
For negative values only the tv_sec field is negative !

此行为由 POSIX 标准定义。例如 what it says关于发出 nanosleep() 函数(rqtpstruct timespec * 类型)后可能出现的错误:

[EINVAL]
  The rqtp argument specified a nanosecond value less than zero or greater than or equal to 1000 millio

这是来自 nanosleep(2) 的类似定义Linux 手册页:

结构 timespec 用于以纳秒精度指定时间间隔。定义如下:

struct timespec {
    time_t tv_sec;        /* seconds */
    long   tv_nsec;       /* nanoseconds */
};

The value of the nanoseconds field must be in the range 0 to 999999999. 

请注意,在这两种情况下,都没有关于负 tv_sec 无效的信息。

简单证明

这是一个简单的内核模块,可以证明我的观点:

#include <linux/module.h>
#include <linux/kernel.h>

int init_module(void)
{
    struct timeval v = ktime_to_timeval((ktime_t){.tv64 = -200000000});
    printk(KERN_INFO "v= %ld, %ld\n", v.tv_sec, v.tv_usec);

    return -1;
}

插入后,这是内核日志的输出:

v= -1, 800000

关于c - 如果过期,hrtimer 不会返回负值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22880575/

相关文章:

c++ - 如何知道指针是否在物理内存中,否则会触发页面错误?

c++ - 循环提升仍然是 C 代码的有效手动优化吗?

c - 如何同步多个appsink

MATLAB 定时器在函数内部的行为与在命令窗口中的行为不同

Java:有时从 TargetDataLine 读取声音和写入 ByteArrayOutPutStream 的时间不同

linux - 如何设置 linux 内核不发送 RST_ACK,这样我就可以在原始套接字中提供 SYN_ACK

c - 如何在 OSX 中将 C 编译为原始二进制文件?

java - 每 X 秒运行一个方法

linux - 了解 linux 或 BSD 内核内部结构的最佳方式是什么?

memory-management - 当在页表中找不到时,内核如何转换虚拟地址?