linux如何在jiffies中处理溢出?

SHH*_*SHH 5 c linux overflow linux-kernel

假设我们有以下代码:

if (timeout > jiffies)
{
    /* we did not time out, good ... */
}
else
{
    /* we timed out, error ...*
}
Run Code Online (Sandbox Code Playgroud)

当jiffies值不溢出时,此代码工作正常.但是,当jiffies溢出并回绕到零时,此代码无法正常工作.

Linux显然提供了用于处理此溢出问题的宏

#define time_before(unknown, known) ((long)(unkown) - (long)(known) < 0)
Run Code Online (Sandbox Code Playgroud)

当用这个宏替换时,上面的代码应该是安全的溢出:

// SAFE AGAINST OVERFLOW
if (time_before(jiffies, timeout)
{
    /* we did not time out, good ... */
}
else
{
    /* we timed out, error ...*
}    
Run Code Online (Sandbox Code Playgroud)

但是,time_before(和其他时间_宏)背后的理由是什么?

time_before(jiffies,timeout)将扩展为

((long)(jiffies) - (long)(timeout) < 0)
Run Code Online (Sandbox Code Playgroud)

这段代码如何防止溢出问题?

Rob*_*tin 6

我们实际上试一试:

#define time_before(unknown, known) ((long)(unkown) - (long)(known) < 0)
Run Code Online (Sandbox Code Playgroud)

我会通过说a long只有两个字节来简化很多事情,所以在十六进制中它可以有一个范围内的值[0, 0xFFFF].

现在,它已经签名,因此范围[0,0xFFFF]可以分为两个独立的范围[0,0x7FFF],[0x8000,0xFFFF].那些对应于值[0,32767],[ - 32768,-1].这是一个图表:

[0x0      -              -                  -               0xFFFF]
[0x0                       0x7FFF][0x8000                   0xFFFF]
[0                         32,767][-32,768                      -1]
Run Code Online (Sandbox Code Playgroud)

timeout是32,000.我们想检查一下我们是否在我们的超时时间内,但实际上我们已经溢出,所以jiffies是-31,000.所以如果我们天真地试图评估jiffies < timeout我们会得到的True.但是,插入值:

   time_before(jiffies, offset)
== ((long)(jiffies) - (long)(offset) < 0)
== (-31000 - 32000 < 0)             // WTF is this. Clearly NOT -63000
== (-31000 - 1768 - 1 - 30231 < 0)  // simply expanded 32000
== (-32768 - 1 - 30232 < 0)         // this -1 causes an underflow
== (32767 - 30232 < 0)
== (2535 < 0)
== False
Run Code Online (Sandbox Code Playgroud)

jiffies是4个字节,而不是2个字节,但同样的原则适用.这些帮助有用?


osg*_*sgx 4

例如,请参见此处:http://fixunix.com/kernel/266713-%5Bpatch-1-4%5D-fs-autofs-use-time_before-time_before_eq-etc.html

针对某些固定小常量检查溢出的代码已转换为使用 time_before。为什么?

我只是总结与 time_after 等函数的定义相关的评论:

包括/linux/jiffies.h:93

 93 /*
 94  *      These inlines deal with timer wrapping correctly. You are 
 95  *      strongly encouraged to use them
 96  *      1. Because people otherwise forget
 97  *      2. Because if the timer wrap changes in future you won't have to
 98  *         alter your driver code.
 99  *
100  * time_after(a,b) returns true if the time a is after time b.
101  *
Run Code Online (Sandbox Code Playgroud)

所以,time_beforetime_after是处理溢出的更好的努力。

您的测试用例更有可能是timeout < jiffles(无溢出)而不是timeout > jiffles(有溢出):

unsigned long jiffies = 2147483658;
unsigned long timeout = 10;
Run Code Online (Sandbox Code Playgroud)

如果您将超时更改为

unsigned long timeout = -2146483000;
Run Code Online (Sandbox Code Playgroud)

答案是什么?

或者您可以更改支票

printf("%d",time_before(jiffies,timeout));
Run Code Online (Sandbox Code Playgroud)

printf("%d",time_before(jiffies,old_jiffles+timeout));
Run Code Online (Sandbox Code Playgroud)

其中 old_jiffles 是定时器启动时保存的 jiffles 值。

所以,我认为 time_before 的用法可以是这样的:

old_jiffles=jiffles;
timeout=10;  // or even 10*HZ for ten-seconds

do_a_long_work_or_wait();

//check is the timeout reached or not
if(time_before(jiffies,old_jiffles+timeout) ) {
  do_another_long_work_or_wait();
} else {
  printk("ERRROR: the timeout is reached; here is a problem");
  panic();
}
Run Code Online (Sandbox Code Playgroud)