<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 牛人業(yè)話 > linux世界里的時間

          linux世界里的時間

          作者: 時間:2016-12-08 來源:網(wǎng)絡(luò) 收藏

            通常,操作系統(tǒng)可以使用三種方法來表示系統(tǒng)的當(dāng)前時間與日期:

          本文引用地址:http://www.ex-cimer.com/article/201612/341309.htm

           ?、僮詈唵蔚囊环N方法就是直接用一個64位的計數(shù)器來對滴答進(jìn)行計數(shù)。

           ?、诘诙N方法就是用一個32位計數(shù)器來對秒進(jìn)行計數(shù),同時還用一個32位的輔助計數(shù)器對滴答計數(shù),之子累積到一秒為止。因為232超過136年,因此這種方法直至22世紀(jì)都可以讓系統(tǒng)工作得很好。

           ?、鄣谌N方法也是按滴答進(jìn)行計數(shù),但是是相對于系統(tǒng)啟動以來的滴答次數(shù),而不是相對于相對于某個確定的外部時刻;當(dāng)讀外部后備時鐘(如RTC)或用戶輸入實際時間時,根據(jù)當(dāng)前的滴答次數(shù)計算系統(tǒng)當(dāng)前時間。

            UNIX類操作系統(tǒng)通常都采用第三種方法來維護(hù)系統(tǒng)的時間與日期。

            1 基本概念

            首先,有必要明確一些Linux內(nèi)核時鐘驅(qū)動中的基本概念。

            (1)時鐘周期(clock cycle)的頻率:8253/8254 PIT的本質(zhì)就是對由晶體振蕩器產(chǎn)生的時鐘周期進(jìn)行計數(shù),晶體振蕩器在1秒時間內(nèi)產(chǎn)生的時鐘脈沖個數(shù)就是時鐘周期的頻率。

            Linux用宏CLOCK_TICK_RATE來表示8254 PIT的輸入時鐘脈沖的頻率(在PC機中這個值通常是1193180HZ),該宏定義在include/asm-i386/timex.h頭文件中:

            #define CLOCK_TICK_RATE 1193180 /* Underlying HZ */

            (2)時鐘滴答(clock tick):我們知道,當(dāng)PIT通道0的計數(shù)器減到0值時,它就在IRQ0上產(chǎn)生一次時鐘中斷,也即一次時鐘滴答。PIT通道0的計數(shù)器的初始值決定了要過多少時鐘周期才產(chǎn)生一次時鐘中斷,因此也就決定了一次時鐘滴答的時間間隔長度。

            (3)時鐘滴答的頻率(HZ):也即1秒時間內(nèi)PIT所產(chǎn)生的時鐘滴答次數(shù)。類似地,這個值也是由PIT通道0的計數(shù)器初值決定的(反過來說, 確定了時鐘滴答的頻率值后也就可以確定8254 PIT通道0的計數(shù)器初值)。Linux內(nèi)核用宏HZ來表示時鐘滴答的頻率,而且在不同的平臺上HZ有不同的定義值。對于ALPHA和IA62平臺HZ的 值是1024,對于SPARC、MIPS、ARM和i386等平臺HZ的值都是100。該宏在i386平臺上的定義如下(include/asm- i386/param.h):

            #ifndef HZ

            #define HZ 100

            #endif

            根據(jù)HZ的值,我們也可以知道一次時鐘滴答的具體時間間隔應(yīng)該是(1000ms/HZ)=10ms。

            (4)時鐘滴答的時間間隔:Linux用全局變量tick來表示時鐘滴答的時間間隔長度,該變量定義在kernel/timer.c文件中,如下:

            long tick = (1000000 + HZ/2) / HZ; /* timer interrupt period */

            tick變量的單位是微妙(μs),由于在不同平臺上宏HZ的值會有所不同,因此方程式tick=1000000÷HZ的結(jié)果可能會是個小數(shù), 因此將其進(jìn)行四舍五入成一個整數(shù),所以Linux將tick定義成(1000000+HZ/2)/HZ,其中被除數(shù)表達(dá)式中的HZ/2的作用就是用來將 tick值向上圓整成一個整型數(shù)。

            另外,Linux還用宏TICK_SIZE來作為tick變量的引用別名(alias),其定義如下(arch/i386/kernel/time.c):

            #define TICK_SIZE tick

            (5)宏LATCH:Linux用宏LATCH來定義要寫到PIT通道0的計數(shù)器中的值,它表示PIT將沒隔多少個時鐘周期產(chǎn)生一次時鐘中斷。顯然LATCH應(yīng)該由下列公式計算:

            LATCH=(1秒之內(nèi)的時鐘周期個數(shù))÷(1秒之內(nèi)的時鐘中斷次數(shù))=(CLOCK_TICK_RATE)÷(HZ)

            類似地,上述公式的結(jié)果可能會是個小數(shù),應(yīng)該對其進(jìn)行四舍五入。所以,Linux將LATCH定義為(include//timex.h):

            /* LATCH is used in the interval timer and ftape setup. */

            #define LATCH ((CLOCK_TICK_RATE + HZ/2) / HZ) /* For divider */

            類似地,被除數(shù)表達(dá)式中的HZ/2也是用來將LATCH向上圓整成一個整數(shù)。

            2 表示系統(tǒng)當(dāng)前時間的內(nèi)核數(shù)據(jù)結(jié)構(gòu)

            作為一種UNIX類操作系統(tǒng),Linux內(nèi)核顯然采用本節(jié)一開始所述的第三種方法來表示系統(tǒng)的當(dāng)前時間。Linux內(nèi)核在表示系統(tǒng)當(dāng)前時間時用到了三個重要的數(shù)據(jù)結(jié)構(gòu):

           ?、偃肿兞縥iffies:這是一個32位的無符號整數(shù),用來表示自內(nèi)核上一次啟動以來的時鐘滴答次數(shù)。每發(fā)生一次時鐘滴答,內(nèi)核的時鐘中斷處 理函數(shù)timer_interrupt()都要將該全局變量jiffies加1。該變量定義在kernel/timer.c源文件中,如下所示:

            unsigned long volatile jiffies;

            C語言限定符volatile表示jiffies是一個易該變的變量,因此編譯器將使對該變量的訪問從不通過CPU內(nèi)部cache來進(jìn)行。

           ?、谌肿兞縳time:它是一個timeval結(jié)構(gòu)類型的變量,用來表示當(dāng)前時間距UNIX時間基準(zhǔn)1970-01-01 00:00:00的相對秒數(shù)值。結(jié)構(gòu)timeval是Linux內(nèi)核表示時間的一種格式(Linux內(nèi)核對時間的表示有多種格式,每種格式都有不同的時間 精度),其時間精度是微秒。該結(jié)構(gòu)是內(nèi)核表示時間時最常用的一種格式,它定義在頭文件include//time.h中,如下所示:

            struct timeval {

            time_t tv_sec; /* seconds */

            suseconds_t tv_usec; /* microseconds */

            };

            其中,成員tv_sec表示當(dāng)前時間距UNIX時間基準(zhǔn)的秒數(shù)值,而成員tv_usec則表示一秒之內(nèi)的微秒值,且1000000>tv_usec>=0。

            Linux內(nèi)核通過timeval結(jié)構(gòu)類型的全局變量xtime來維持當(dāng)前時間,該變量定義在kernel/timer.c文件中,如下所示:

            /* The current time */

            volatile struct timeval xtime __attribute__ ((aligned (16)));

            但是,全局變量xtime所維持的當(dāng)前時間通常是供用戶來檢索和設(shè)置的,而其他內(nèi)核模塊通常很少使用它(其他內(nèi)核模塊用得最多的是 jiffies),因此對xtime的更新并不是一項緊迫的任務(wù),所以這一工作通常被延遲到時鐘中斷的底半部分(bottom half)中來進(jìn)行。由于bottom half的執(zhí)行時間帶有不確定性,因此為了記住內(nèi)核上一次更新xtime是什么時候,Linux內(nèi)核定義了一個類似于jiffies的全局變量 wall_jiffies,來保存內(nèi)核上一次更新xtime時的jiffies值。時鐘中斷的底半部分每一次更新xtime的時侯都會將 wall_jiffies更新為當(dāng)時的jiffies值。全局變量wall_jiffies定義在kernel/timer.c文件中:

            /* jiffies at the most recent update of wall time */

            unsigned long wall_jiffies;

           ?、廴肿兞縮ys_tz:它是一個timezone結(jié)構(gòu)類型的全局變量,表示系統(tǒng)當(dāng)前的時區(qū)信息。結(jié)構(gòu)類型timezone定義在include//time.h頭文件中,如下所示:

            struct timezone {

            int tz_minuteswest; /* minutes west of Greenwich */

            int tz_dsttime; /* type of dst correction */

            };

            基于上述結(jié)構(gòu),Linux在kernel/time.c文件中定義了全局變量sys_tz表示系統(tǒng)當(dāng)前所處的時區(qū)信息,如下所示:

            struct timezone sys_tz;



          關(guān)鍵詞: linux 時鐘

          評論


          相關(guān)推薦

          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();