久久婷婷香蕉热狠狠综合,精品无码国产自产拍在线观看蜜,寡妇房东在做爰3,中文字幕日本人妻久久久免费,国产成人精品三上悠亚久久

當前位置:首頁 > 嵌入式培訓 > 嵌入式學習 > 講師博文 > linux內核時間(jian)管理(li)

linux內核時間管理 時間:2017-11-23      來源(yuan):未(wei)知

前言:

Linux中如何對時間進(jin)行管理?時鐘節拍(pai)的概(gai)念及(ji)延時函(han)數的用法(fa)很多同學都用不好,下面我(wo)給大家總結一下。

 

一,linux時(shi)鐘運作機(ji)制(zhi)

1,linux時鐘運作機制

• 大部分(fen)PC機(ji)中有兩個時(shi)鐘(zhong)(zhong)源,分(fen)別(bie)是實時(shi)時(shi)鐘(zhong)(zhong)(RTC)和 操作系統(OS)時(shi)鐘(zhong)(zhong)

• 實時時鐘也叫(jiao)CMOS時鐘,它靠電(dian)池供電(dian),即(ji)使系統(tong)斷(duan)電(dian),也可以(yi)維持日期和時間。

• RTC和OS時鐘(zhong)之間的關系通(tong)常也被稱(cheng)作操作系統的時鐘(zhong)運作機(ji)制

• 不同(tong)的操作系統,其時(shi)鐘運作機制也不同(tong)

linux中的(de)時鐘機制大致如下圖所(suo)示

linux中時鐘(zhong)機制

由上圖可知:

RTC是硬件時(shi)(shi)鐘,它為整個計(ji)算機提(ti)供(gong)一個計(ji)時(shi)(shi)標(biao)準(zhun),是原始底層的時(shi)(shi)鐘數據(ju),由紐扣電(dian)池供(gong)電(dian),系統斷電(dian)后(hou)仍然在工作(zuo)

OS時鐘產生于PC主板上的(de)定時/計(ji)數(shu)(shu)芯片(pian),由操(cao)(cao)作(zuo)(zuo)系統控(kong)制這(zhe)個芯片(pian)的(de)工(gong)作(zuo)(zuo),OS時鐘的(de)基本單位(wei)就是該芯片(pian)的(de)計(ji)數(shu)(shu)周期,開(kai)機(ji)時操(cao)(cao)作(zuo)(zuo)系統取得RTC中的(de)時間(jian)數(shu)(shu)據來初(chu)始化OS時鐘,所以它只是在開(kai)機(ji)有效(xiao),由操(cao)(cao)作(zuo)(zuo)系統控(kong)制,已被稱為軟時鐘或系統時鐘。操(cao)(cao)作(zuo)(zuo)系統通過OS時鐘提供(gong)給應用(yong)程序和時間(jian)有關的(de)服務。

擴展:OS時(shi)(shi)鐘其本質是一個(ge)(ge)計(ji)(ji)數(shu)(shu)器(qi)(qi),計(ji)(ji)數(shu)(shu)器(qi)(qi)從計(ji)(ji)數(shu)(shu)初(chu)值開(kai)始,每收到一次脈(mo)沖信(xin)號,計(ji)(ji)數(shu)(shu)器(qi)(qi)減1,當減至0時(shi)(shi),就會輸(shu)出高電平或低電平,然后獲取(qu)重(zhong)載值重(zhong)新從初(chu)值開(kai)始計(ji)(ji)數(shu)(shu),不斷(duan)循環,這樣就得(de)到一個(ge)(ge)輸(shu)出脈(mo)沖,這個(ge)(ge)脈(mo)沖作用中(zhong)斷(duan)控(kong)制器(qi)(qi)上,產(chan)生中(zhong)斷(duan)信(xin)號,觸發時(shi)(shi)鐘中(zhong)斷(duan)。

 

2,OS時(shi)鐘(zhong)中斷

 

• OS時鐘是由可編程定時/計(ji)數(shu)(shu)器產(chan)生的(de)輸出脈沖(chong)觸(chu)發(fa)中(zhong)斷(duan)而產(chan)生的(de),而輸出脈沖(chong)的(de)周期叫(jiao)做一個“時鐘節拍”(Tick,又稱滴(di)答),(中(zhong)斷(duan)觸(chu)發(fa)時會進入中(zhong)斷(duan)處理函數(shu)(shu),使jiffies+1)

• 操作系統(tong)的“時間基準” 由設(she)計(ji)者(zhe)決定,Linux的時間基準是(shi)1970年(nian)1月1日凌晨0點

• OS時(shi)鐘(zhong)記錄的時(shi)間(jian)就是系統時(shi)間(jian)。系統時(shi)間(jian)以(yi)“時(shi)鐘(zhong)節拍”為單(dan)位(wei)

•時(shi)鐘(zhong)中(zhong)斷觸發的頻(pin)率,由內核HZ來確(que)定(ding),系統啟動時(shi)會按照定(ding)義的HZ值對硬件進(jin)行設置

比如(ru)對(dui)HZ的定義如(ru)下:

#define  Hz 100      

內(nei)核(he)時(shi)間(jian)頻率:表示(shi)每秒鐘(zhong)觸發100次時(shi)鐘(zhong)中斷,即(ji)每10ms觸發一(yi)次,

   每次(ci)中斷jiffies+1,,則每秒jiffies增加了100,

 

 • Linux中用全局變量 jiffies表示系統自啟(qi)動以來的時鐘節拍數目(時鐘中斷觸發(fa)的次數)

   因此系(xi)統運行的時(shi)間以(yi)s為單位(wei)計數,  就等于 jiffies/HZ

   內核啟動時將該(gai)變(bian)量初始化為0,此后,每(mei)次(ci)時鐘中斷(duan)處(chu)理(li)程序都會增加該(gai)變(bian)量的(de)值,每(mei)秒鐘觸發(fa)中斷(duan)的(de)次(ci)數為Hz, 

 

3、實際時間

 

實(shi)際時(shi)間就是現實(shi)中鐘(zhong)表上顯示的時(shi)間,其實(shi)內核中并不常用這個(ge)時(shi)間,主(zhu)要(yao)是用戶空間的程(cheng)序有(you)時(shi)需要(yao)獲(huo)取當前時(shi)間,所以內核中也管理著這個(ge)時(shi)間。

實際(ji)時(shi)間的(de)獲取是在開機后(hou),內(nei)核初始化時(shi)從RTC讀取的(de)。

內核讀取這(zhe)個(ge)時間后(hou)就將其放(fang)入內核中的(de) xtime 變量中,并且在系統的(de)運行中不斷(duan)更新(xin)這(zhe)個(ge)值。

 

當(dang)前實際時間(jian)(墻(qiang)(qiang)上時間(jian)):  xtime.tv_sec以秒(miao)為(wei)單位,存放著(zhu)自1970年(nian)7月1日(UTC)以來(lai)經過(guo)的(de)時間(jian),1970年(nian)1月1日被稱為(wei)紀元。多數(shu)Unix系統的(de)墻(qiang)(qiang)上時間(jian)都是基于該紀元而言(yan)的(de)。xtime.tv_nsec記錄(lu)自上一秒(miao)開始(shi)經過(guo)的(de)納(na)秒(miao)數(shu)。

在<Time.h(incluce/linux)>中 

extern struct timespec xtime; 

#ifndef _STRUCT_TIMESPEC 

#define _STRUCT_TIMESPEC 

struct timespec {      /*高精度(du)*/

      time_t  tv_sec;     /* seconds */ 

    long    tv_nsec;    /* nanoseconds 納秒*/ 

}; 

     #endif

 從用戶(hu)空間取(qu)得墻上時間的主要接口是gettimeofday(),在內核中對(dui)應的系統調用為sys_gettimeofday():

雖然內核也(ye)實(shi)現(xian)了(le)time()系統(tong)調用,但是gettimeofday()幾乎(hu)完全(quan)取(qu)代了(le)它。C庫(ku)函數也(ye)提供了(le)墻上時(shi)間相關的庫(ku)調用,比(bi)如ftime(),ctime()。

  除了更新(xin)xtime時(shi)間外,內核不(bu)會想用戶空間程序那樣頻繁(fan)的使(shi)用xtime。但是,在(zai)文件系統(tong)的實現代碼中(zhong)存放(fang)訪問時(shi)間戳(創建,存取,修改等)需(xu)要使(shi)用xtime。

 

4,時鐘中斷(duan)處(chu)理程序----操(cao)作系統的脈搏

 

每一次時鐘中(zhong)斷的(de)產生都觸發下列幾個主要的(de)操作:

– 給(gei)jiffies變量加 1

– 更新時間和日期,既更新xtime墻上時間

&ndash; 確(que)定當前進(jin)程(cheng)在CPU 上已運行(xing)了(le)多長時(shi)間,如果已經(jing)超(chao)過了(le)分配給它的(de)時(shi)間,則搶占(zhan)它

– 更(geng)新資(zi)源使用統計(ji)數

– 檢查(cha)定(ding)時器時間間隔是否已到(dao),如果是,則執行它注(zhu)冊的函數(運行于底半部(bu)軟中斷中)

 

 以上工作(zuo)每秒要發生 Hz次,也就(jiu)是說PC上的時鐘中斷處理(li)程序執行的頻率為Hz

 

5、時間(jian)系統(tong)總結

1、節拍----->jiffies

    &nbsp;又稱(cheng)時(shi)鐘(zhong)滴答,是一個全局變量,它的值在系統引導的時(shi)候初(chu)始(shi)化為(wei)0,在時(shi)鐘(zhong)中斷初(chu)始(shi)化完成后,每次時(shi)鐘(zhong)中斷發生,在時(shi)鐘(zhong)中斷處理例程中都會將jiffies的值 +1。

     jiffies_64:為了解(jie)決jiffies溢出問(wen)題,更(geng)重要的是(shi)通過jiffies_64可以知道自開機以來的時間(jian)間(jian)隔。

2、節(jie)拍率---->HZ

     HZ表示時(shi)鐘中(zhong)斷發生的(de)頻率。可(ke)以在.config的(de)配置文件中(zhong)改(gai)寫(xie)。1/HZ是每個jiffies+1的(de)時(shi)間(jian)(jian)間(jian)(jian)隔。

3、通過jiffies可以(yi)進行(xing)時(shi)間的比較(jiao)和(he)時(shi)間轉換

4、時間比較

&nbsp;    32位                                                    64位

     time_after(a,b)                                    time_after64(a,b)

     time_before(a,b)                                 time_before64(a,b)

     time_after_eq(a,b)      ;                        time_after_eq64(a,b)

  &nbsp;  time_before_eq(a,b)           &nbsp;               time_before_eq64

     time_in_range(a,b,c)           &nbsp;               time_in_range(a,b,c)

5、時間轉換

     a、jiffies和msecs以及(ji)usecs的轉換:

     unsigned int jiffies_to_msecs(const unsigned long);

     unsigned int jiffies_to_usecs(const unsigned long);

&nbsp;    unsigned long msecs_to_jiffies(const unsigned int m);

&nbsp;    unsigned long usecs_to_jiffies(const unsigned int u);

 

    b、jiffies和timespec以及timeval的轉換

 ;    在(zai)用戶空間,應(ying)用程序更(geng)多(duo)的使用秒以及毫秒等時(shi)間形式,而在(zai)內核中多(duo)使用jiffes。

     ;內核定義了(le)struct timeval 和 struct timespec 兩種數據結構

     struct timespec {

  &nbsp;            __kernel_time_t tv_sec;

               long              tv_nsec;

      }

     struct timeval {

  &nbsp;            __kernel_time_t &nbsp;        tv_sec;

             &nbsp; __kernel_suseconds_t  tv_usec;

    }

    相互(hu)轉換函數(shu):

     unsigned long timespec_to_jiffies(const struct timespec *value);

  &nbsp;  void jiffies_to_timespec(const unsigned long jiffies, struct timespec *value);

  &nbsp;  unsigned long timeval_to_jiffies(const struct timeval *value);

     void jiffies_to_tim;

 

6、要(yao)注意的是(shi)jiffies的精度(du)問題(ti)。如果HZ = 1000,則(ze)jiffies增加1代(dai)表1ms。

     如果要(yao)用到更高精(jing)度的(de)始終(zhong),要(yao)用其他的(de)硬件機制。

 

 

二、內核短延時

 

Linux內核中提供了下列3個函數以分別進行納秒(miao)、微(wei)秒(miao)和毫秒(miao)延遲(chi):

 

void ndelay(unsigned long nsecs);

void udelay(unsigned long usecs);

void mdelay(unsigned long msecs);

 

上述延(yan)遲(chi)的實現(xian)原理本質上是忙等待,它根據(ju)CPU頻(pin)率進行一(yi)定次數的循(xun)環(huan)。如果沒有特殊的理由(比如在(zai)中斷上下文中獲(huo)取自旋(xuan)鎖的情況),不(bu)推薦(jian)使用這(zhe)些函數延(yan)遲(chi)較(jiao)長(chang)的時間,浪費CPU。

注:ndelay 和 mdelay都是基于udelay,將udelay的(de)次(ci)數除1000就是ndelay,因(yin)此ndelay的(de)次(ci)數為(wei)1000的(de)整數倍才準確(que)。

 

 

有時候(hou),人們在軟件中(zhong)進行(xing)下面的延遲:

void delay(unsigned int time)

{

while(time--);

}

ndelay()、udelay()和mdelay()函數的(de)實(shi)現方(fang)式原理(li)與(yu)此(ci)類似。

內核在啟動時,會(hui)運行一個(ge)延(yan)遲(chi)循環校準(Delay Loop Calibration),計算(suan)出lpj(Loops Per Jiffy)即處理器在一個(ge)jiffy時間內運行一個(ge)內部的延(yan)遲(chi)循環的次數(shu),內核啟動時會(hui)打印如下類似(si)信息:

Calibrating delay loop... 530.84 BogoMIPS (lpj=1327104)

如果我(wo)們直接在bootloader傳遞給內核的(de)(de)bootargs中(zhong)設(she)置lpj=1327104,則可以省掉這個校準的(de)(de)過程節省約百(bai)毫秒級的(de)(de)開(kai)機時間。

 

睡著延時

毫秒(miao)(miao)時(shi)(shi)延(以及更大的秒(miao)(miao)時(shi)(shi)延)已經比(bi)較大了(le),在內核中,好不要直(zhi)接使用mdelay()函(han)(han)數,這將耗費CPU資源(yuan),對(dui)于毫秒(miao)(miao)級以上的時(shi)(shi)延,內核提供(gong)了(le)下述函(han)(han)數:

 

void msleep(unsigned int millisecs);

unsigned long   msleep_interruptible(unsigned int millisecs);

void ssleep(unsigned int seconds);

 

上(shang)述函數將使得調用(yong)它(ta)的進程睡眠參數指定的時間為millisecs,msleep()、ssleep()不(bu)能被(bei)打(da)斷,而msleep_interruptible()則可以被(bei)打(da)斷。

受系統Hz以(yi)及進(jin)程調度的影(ying)響,msleep()類似函數的精度是(shi)有限的。

 

三、內核長延時

在內核(he)中(zhong),一個(ge)直觀的(de)(de)延(yan)時(shi)(shi)的(de)(de)方法是(shi)將所要(yao)延(yan)遲的(de)(de)時(shi)(shi)間設置(zhi)的(de)(de)當前的(de)(de)jiffies加上要(yao)延(yan)遲的(de)(de)時(shi)(shi)間,這樣就可以簡單的(de)(de)通過比較當前的(de)(de)jiffies和設置(zhi)的(de)(de)時(shi)(shi)間來判(pan)斷(duan)延(yan)時(shi)(shi)的(de)(de)時(shi)(shi)間時(shi)(shi)候到來。針對此方法,內核(he)中(zhong)提供了簡單的(de)(de)宏用于判(pan)斷(duan)延(yan)時(shi)(shi)是(shi)否完成(cheng)。

 

time_after(a,b);         /*如果(guo)時間a在b之后 (a>b),則(ze)返回(hui)真,否則(ze)返回(hui)0*/

time_before(a,b);      /*如(ru)果時間(jian)a在b之(zhi)前 (a<b),則(ze)(ze)返回真,否則(ze)(ze)返回0*/

 

長延(yan)時實(shi)現舉例:

/* 延遲 100 個(ge) jiffies */

unsigned long delay = jiffies + 100;

while(time_before(jiffies, delay));

 

/* 再延(yan)遲 2s */

unsigned long delay = jiffies + 2*Hz;

while(time_before(jiffies, delay));

 

與time_before()對應的(de)還(huan)有一個time_after(),它們在內核(he)中定義(yi)為(實際上(shang)只(zhi)是(shi)將傳入(ru)的(de)未來時間(jian)jiffies和被調用時的(de)jiffies進行一個簡單的(de)比較):

#define time_after(a,b) \

(typecheck(unsigned long, a) && \

typecheck(unsigned long, b) && \

((long)(b) - (long)(a) < 0))

 

#define time_before(a,b) time_after(b,a)

 

 

為了防止(zhi)在time_before()和time_after()的比較過(guo)程中編譯器(qi)對jiffies的優化(hua),內(nei)核將其定義為

volatile變(bian)量(liang),這將保證每次都(dou)會重新讀取這個變(bian)量(liang)。因此volatile更(geng)多(duo)的作(zuo)用(yong)還是(shi)避免這種讀合并。

 

 

四、讓進程(cheng)睡固定的時間(jian)

 

下面兩個函數可以將當(dang)前(qian)進程(cheng)添加到等(deng)(deng)待隊(dui)列中,從而在等(deng)(deng)待隊(dui)列上睡眠,當(dang)超時(shi)(shi)發生時(shi)(shi),進程(cheng)將被喚醒:

 

sleep_on_timeout(wait_queue_head_t *q, unsigned long timeout);

interrupt_sleep_on_timeout(wait_queue_head_t *q, unsigned long timeout);

上一篇:Linux設備驅動申請設備號過程分析

下一篇:Linux設備驅動模型之kobject linux2.6.0

熱點(dian)文章推(tui)薦(jian)
華清學員就業(ye)榜單
高薪學員經(jing)驗(yan)分享
熱點新聞推薦
前臺專線(xian):010-82525158 企業(ye)培訓洽談專線:010-82525379 院校合(he)作洽談專線(xian):010-82525379 Copyright © 2004-2022 北京華清遠見科技集團有限公司 版權所有 ,,京公海網安備11010802025203號

回到頂部