Linux 内核宏 time_after解析
同學(xué)們留言回復(fù)答案看看
可能很多老鳥對(duì)這樣的Linux 內(nèi)核宏已經(jīng)見慣不怪了,但是作為新手的Linux內(nèi)核開發(fā)者,我覺得非常有必要了解其中的原理和作用。
jiffies 這個(gè)想必大家已經(jīng)非常熟悉,jiffies表示的是當(dāng)前的系統(tǒng)時(shí)鐘節(jié)拍總數(shù),它統(tǒng)計(jì)的是從開機(jī)到現(xiàn)在的系統(tǒng)時(shí)間節(jié)拍。
既然說到時(shí)鐘節(jié)拍,那就不能不說HZ,這個(gè)是系統(tǒng)的節(jié)拍,每個(gè)體系結(jié)構(gòu)系統(tǒng)的節(jié)拍都不一樣,內(nèi)核中通常的節(jié)拍數(shù)都不同,是 100,200,1000等,根據(jù)不同的體系結(jié)構(gòu)來設(shè)定,節(jié)拍數(shù)可以理解為心跳,jiffies 可以理解為從出生到現(xiàn)在你系統(tǒng)產(chǎn)生了多少次心跳。
/* * These inlines deal with timer wrapping correctly. You are * strongly encouraged to use them * 1. Because people otherwise forget * 2. Because if the timer wrap changes in future you won't have to * ? alter your driver code. * * ?time_after(a,b) returns true if the time a is after time b. * * Do this with "<0" and ">=0" to only test the sign of the result. A * good compiler would generate better code (and a really good compiler * wouldn't care). Gcc is currently neither. */ #define time_after(a,b) \ (typecheck(unsigned long, a) && \ typecheck(unsigned long, b) && \ ((long)(b) - (long)(a) < 0)) |
看注釋,就是如果 a 的時(shí)間在 b 的時(shí)間之后,就返回true,也可以理解為產(chǎn)生b的時(shí)間段超時(shí)后,就返回true。
然后我們看看在內(nèi)核代碼里面是如何使用這個(gè)宏的?
timeout =2; timeout += jiffies; do { if (time_after(jiffies, timeout)) { /* drive timed-out */ return 1; } /* give drive a breather */ msleep(50); } while ((hwif->INB(hd_status)) & BUSY_STAT); |
我隨便拿了一個(gè)代碼來舉例,這個(gè)是在驅(qū)動(dòng)里面的一個(gè)代碼,如果這個(gè)驅(qū)動(dòng)代碼產(chǎn)生了超時(shí),就返回true,函數(shù)就返回,可以理解為注冊(cè)驅(qū)動(dòng)產(chǎn)生了超時(shí)時(shí)間后,while里面的判斷還是真。
我們看這個(gè)宏實(shí)現(xiàn)的原理
如果
b = 100; (超時(shí)時(shí)間)
a = 55; ? ? (當(dāng)前時(shí)間)
正常的時(shí)候
(long)b - (long)a > 0 表示沒有產(chǎn)生超時(shí)
如果
a = 101時(shí)
(long)b - (long)a = 100 - 101 = -1 < 0 表示時(shí)間超時(shí)
但是我們正常不會(huì)這樣使用,我們會(huì)利用HZ參數(shù)來一起使用
比如,我要設(shè)置2秒后超時(shí),那么timeout可以這樣設(shè)置
timeout = 2*HZ; timeout += jiffies; if(time_after(jiffies,timeout)){ //do somethings } |
但是前面有一個(gè)typecheck(unsigned long) 后面比較的時(shí)候又強(qiáng)制轉(zhuǎn)變?yōu)閘ong,這個(gè)有什么玄機(jī)呢?
這個(gè)主要是解決jiffies回繞的問題
我們知道unsigned long 的最大值是 2^64 -1 = 18446744073709551615 (64位系統(tǒng))
? ? ? ? ? ? ? ? ? ? ? ?
假設(shè)time_after的宏定義如下
#define time_after(a,b) \ (typecheck(unsigned long, a) && \ typecheck(unsigned long, b) && \ ((unsigned long)(b) - (unsigned long)(a) < 0)) //jiffies = 18446744073709550615 timeout = 2*HZ; timeout += jiffies; //do something if(time_after(jiffies,timeout)){? //這時(shí)候,jiffies 已經(jīng)回繞為 0,timeout還是一個(gè)很大的值,這時(shí)候就會(huì)出現(xiàn)問題了,jiffies需要重新計(jì)數(shù)很久很久才可能再回到和timeout比較的一個(gè)量級(jí)。 ? ?//do something } |
但是如果上面的宏,被強(qiáng)制轉(zhuǎn)換成long 有符號(hào)數(shù)呢?
signed long 的范圍是 [-9223372036854775808, 9223372036854775807]
#define time_after(a,b) \ (typecheck(unsigned long, a) && \ typecheck(unsigned long, b) && \ ((long)(b) - (long)(a) < 0)) ? ? ? ?jiffies = 18446744073709550615; timeout =2*HZ; timeout += jiffies; ? ? ? //do something ? ? ? if(time_after(jiffies,timeout)){? //這時(shí)候,jiffies 已經(jīng)回繞為 0,timeout 還是一個(gè)很大 ? ? ? 的值,轉(zhuǎn)成有符號(hào)的long是 -801,這時(shí)候timeout - jiffies = -801 < 0是成立的。 ? ? ? ? ??//do something ? ? ? } |
我們看注釋里面也寫著,這個(gè)宏是非常強(qiáng)壯的,但是這個(gè)也有一個(gè)弊端的時(shí)候,就是timeout的時(shí)間超出了unsigned long /2 的范圍,就會(huì)出現(xiàn)問題 ,但是unsigned long/2 表示多長(zhǎng)的時(shí)間呢?我們計(jì)算一下
18446744073709551615 /HZ(200)/60/60/24 = 533759955836/2 = 266879977918(天)
沒有誰把超時(shí)時(shí)間設(shè)置到這么久吧,所以說這個(gè)宏是足夠你使用的了。
可能很多人不明白為什么timeout設(shè)置太長(zhǎng)會(huì)出現(xiàn)問題,我們可以列舉一下
#define time_after(a,b) \ (typecheck(unsigned long, a) && \ typecheck(unsigned long, b) && \ ((long)(b) - (long)(a) < 0)) jiffies = 18446744073709551615/2; printf("%lld\n",(long)(jiffies)); timeout = 18446744073709551615/2; timeout += jiffies; ? ? ? ?jiffies += 202; printf("jiffies=%ld,timeout=%ld, time_after(a,a+b)=%d\n",(long)jiffies, (long)timeout, time_after(jiffies,timeout)); ? ? ? //輸出結(jié)果如下 ? ? ??9223372036854775807 ? ? ? jiffies=-9223372036854775607,timeout=-2, time_after(a,a+b)=0 請(qǐng)讀者自行驗(yàn)證?jiffies =0?timeout =?18446744073709551615/2?的情況 |
看到最后返回的是? 0 ,不是 1?
原因很簡(jiǎn)單,因?yàn)閠imeout回繞變成了在 0附近的值(可以回去看那個(gè)圖片加深理解),然后jiffies是一個(gè)負(fù)數(shù)很大的值,相減就出現(xiàn)問題了。
***************************
總結(jié)
以上是生活随笔為你收集整理的Linux 内核宏 time_after解析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python定时任务框架APSchedu
- 下一篇: Activiti6.0 - 核心数据库表