日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > linux >内容正文

linux

Linux 内核宏 time_after解析

發(fā)布時(shí)間:2023/12/20 linux 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux 内核宏 time_after解析 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

同學(xué)們留言回復(fù)答案看看


可能很多老鳥對(duì)這樣的Linux 內(nèi)核宏已經(jīng)見慣不怪了,但是作為新手的Linux內(nèi)核開發(fā)者,我覺(jué)得非常有必要了解其中的原理和作用。

jiffies 這個(gè)想必大家已經(jīng)非常熟悉,jiffies表示的是當(dāng)前的系統(tǒng)時(shí)鐘節(jié)拍總數(shù),它統(tǒng)計(jì)的是從開機(jī)到現(xiàn)在的系統(tǒng)時(shí)間節(jié)拍。

既然說(shuō)到時(shí)鐘節(jié)拍,那就不能不說(shuō)HZ,這個(gè)是系統(tǒng)的節(jié)拍,每個(gè)體系結(jié)構(gòu)系統(tǒng)的節(jié)拍都不一樣,內(nèi)核中通常的節(jié)拍數(shù)都不同,是 100,200,1000等,根據(jù)不同的體系結(jié)構(gòu)來(lái)設(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è)代碼來(lái)舉例,這個(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 表示沒(méi)有產(chǎn)生超時(shí)

如果

a = 101時(shí)

(long)b - (long)a = 100 - 101 = -1 < 0 表示時(shí)間超時(shí)

但是我們正常不會(huì)這樣使用,我們會(huì)利用HZ參數(shù)來(lái)一起使用

比如,我要設(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回繞的問(wèn)題

我們知道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)問(wè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)問(wèn)題 ,但是unsigned long/2 表示多長(zhǎng)的時(shí)間呢?我們計(jì)算一下

18446744073709551615 /HZ(200)/60/60/24 = 533759955836/2 = 266879977918(天)

沒(méi)有誰(shuí)把超時(shí)時(shí)間設(shè)置到這么久吧,所以說(shuō)這個(gè)宏是足夠你使用的了。

可能很多人不明白為什么timeout設(shè)置太長(zhǎng)會(huì)出現(xiàn)問(wè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)問(wèn)題了。

***************************

總結(jié)

以上是生活随笔為你收集整理的Linux 内核宏 time_after解析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。