課程設(shè)計(jì)報(bào)告_第1頁(yè)
課程設(shè)計(jì)報(bào)告_第2頁(yè)
課程設(shè)計(jì)報(bào)告_第3頁(yè)
課程設(shè)計(jì)報(bào)告_第4頁(yè)
課程設(shè)計(jì)報(bào)告_第5頁(yè)
已閱讀5頁(yè),還剩32頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、系統(tǒng)軟件課程設(shè)計(jì)時(shí)鐘中斷與進(jìn)程調(diào)度學(xué)號(hào)姓名許明秀指導(dǎo)教師金雪云2013年12月一、 報(bào)告摘要進(jìn)程調(diào)度是操作系統(tǒng)十分重要的一個(gè)部分。在操作系統(tǒng)的設(shè)計(jì)過程中,進(jìn)程調(diào)度和時(shí)鐘中斷形成了密不可分的關(guān)系。系統(tǒng)時(shí)鐘、定時(shí)器的實(shí)現(xiàn)和進(jìn)程調(diào)度,共同合作,實(shí)現(xiàn)了操作系統(tǒng)的有關(guān)功能。二、 關(guān)鍵詞操作系統(tǒng)、系統(tǒng)時(shí)鐘、時(shí)鐘中斷、定時(shí)器、任務(wù)隊(duì)列、進(jìn)程調(diào)度三、 引言進(jìn)程調(diào)度是CPU處理多進(jìn)程并發(fā)執(zhí)行所必須的步驟,而和進(jìn)程調(diào)度緊密相關(guān)的是時(shí)間中斷,其中涉及到系統(tǒng)時(shí)鐘的初始化和定時(shí)器的相關(guān)知識(shí)。課設(shè)進(jìn)行過程中,采用分工方式,每人負(fù)責(zé)一部分內(nèi)容,在每人閱讀代碼的過程中,若存在相互調(diào)用的關(guān)系,則合在一起共同完成代碼閱讀。分工如

2、下:系統(tǒng)時(shí)鐘(time.c) 許明秀 定時(shí)器(timer.c) 胡建 進(jìn)程調(diào)度(sched.c) 彭春華四、 任務(wù)分配與代碼分析4.1系統(tǒng)時(shí)鐘的實(shí)現(xiàn)4.2.1內(nèi)核機(jī)制原理分析時(shí)間在一個(gè)操作系統(tǒng)內(nèi)核中占據(jù)著重要的地位,它是驅(qū)動(dòng)一個(gè)OS內(nèi)核運(yùn)行的“起博器”。一般說來,內(nèi)核主要需要兩種類型的時(shí)間:1. 在內(nèi)核運(yùn)行期間持續(xù)記錄當(dāng)前的時(shí)間與日期,以便內(nèi)核對(duì)某些對(duì)象和事件作時(shí)間標(biāo)記(timestamp,也稱為“時(shí)間戳”),或供用戶通過時(shí)間syscall進(jìn)行檢索。2. 維持一個(gè)固定周期的定時(shí)器,以提醒內(nèi)核或用戶一段時(shí)間已經(jīng)過去了。PC機(jī)中的時(shí)間是有三種時(shí)鐘硬件提供的,而這些時(shí)鐘硬件又都基于固定頻率的晶體振蕩

3、器來提供時(shí)鐘方波信號(hào)輸入。這三種時(shí)鐘硬件是:(1)實(shí)時(shí)時(shí)鐘 (Real Time Clock,RTC);(2)可編程間隔定時(shí)器(Programmable Interval Timer,PIT);(3)時(shí)間戳計(jì)數(shù)器(Time Stamp Counter,TSC)。1 時(shí)鐘硬件11 實(shí)時(shí)時(shí)鐘RTC自從IBM PC AT起,所有的PC機(jī)就都包含了一個(gè)叫做實(shí)時(shí)時(shí)鐘(RTC)的時(shí)鐘芯片,以便在PC機(jī)斷電后仍然能夠繼續(xù)保持時(shí)間。顯然,RTC是通過主板上的電池來供電 的,而不是通過PC機(jī)電源來供電的,因此當(dāng)PC機(jī)關(guān)掉電源后,RTC仍然會(huì)繼續(xù)工作。通常,CMOS RAM和RTC被集成到一塊芯片上,因此RTC也

4、稱作“CMOS Timer”。最常見的RTC芯片是MC(Motorola)和DS12887(maxim),DS12887完全兼容于MC, 并有一定的擴(kuò)展。本節(jié)內(nèi)容主要基于MC這一標(biāo)準(zhǔn)的RTC芯片。具體內(nèi)容可以參考MC的Datasheet。12 可編程間隔定時(shí)器PIT每個(gè)PC機(jī)中都有一個(gè)PIT,以通過IRQ0產(chǎn)生周期性的時(shí)鐘中斷信號(hào)。當(dāng)前使用最普遍的是Intel 8254 PIT芯片,它的I/O端口地址是0x400x43。Intel 8254 PIT有3個(gè)計(jì)時(shí)通道,每個(gè)通道都有其不同的用途:(1) 通道0用來負(fù)責(zé)更新系統(tǒng)時(shí)鐘。每當(dāng)一個(gè)時(shí)鐘滴答過去時(shí),它就會(huì)通過IRQ0向系統(tǒng)產(chǎn)生一次時(shí)鐘中斷。(2

5、) 通道1通常用于控制DMAC對(duì)RAM的刷新。(3) 通道2被連接到PC機(jī)的揚(yáng)聲器,以產(chǎn)生方波信號(hào)。每個(gè)通道都有一個(gè)向下減小的計(jì)數(shù)器,8254 PIT的輸入時(shí)鐘信號(hào)的頻率是HZ,也即一秒鐘輸入個(gè)clock-cycle。每輸入一個(gè)clock-cycle其時(shí)間通道 的計(jì)數(shù)器就向下減1,一直減到0值。因此對(duì)于通道0而言,當(dāng)他的計(jì)數(shù)器減到0時(shí),PIT就向系統(tǒng)產(chǎn)生一次時(shí)鐘中斷,表示一個(gè)時(shí)鐘滴答已經(jīng)過去了。當(dāng)各通道 的計(jì)數(shù)器減到0時(shí),我們就說該通道處于“Terminal count”狀態(tài)。通道計(jì)數(shù)器的最大值是10000h,所對(duì)應(yīng)的時(shí)鐘中斷頻率是(65536)18.2HZ,也就是說,此時(shí)一秒鐘之內(nèi)將產(chǎn)生18

6、.2次時(shí)鐘中斷。13 時(shí)間戳記數(shù)器TSC從Pentium開始,所有的Intel 80x86 CPU就都又包含一個(gè)64位的時(shí)間戳記數(shù)器(TSC)的寄存器。該寄存器實(shí)際上是一個(gè)不斷增加的計(jì)數(shù)器,它在CPU的每個(gè)時(shí)鐘信號(hào)到來時(shí)加1(也即每一個(gè)clock-cycle輸入CPU時(shí),該計(jì)數(shù)器的值就加1)。匯編指令rdtsc可以用于讀取TSC的值。利用CPU的TSC,操作系統(tǒng)通??梢缘玫礁鼮榫珳?zhǔn)的時(shí)間度量。假如clock-cycle的頻率是400MHZ,那么TSC就將每2.5納秒增加一次。不同的操作系統(tǒng),RTC和OS時(shí)鐘的關(guān)系是不同的。RTC和OS時(shí)鐘之間的關(guān)系通常也被稱作操作系統(tǒng)的時(shí)鐘運(yùn)作機(jī)制。一般來說,

7、RTC是OS時(shí)鐘的時(shí)間基準(zhǔn),操作系統(tǒng)通過讀取RTC來初始化OS時(shí)鐘,此后二者保持同步運(yùn)行,共同維持著系統(tǒng)時(shí)間。linux時(shí)鐘機(jī)制Linux中的時(shí)鐘運(yùn)作機(jī)制如圖所示。OS時(shí)鐘和RTC之間要通過BIOS的連接,是因?yàn)閭鹘y(tǒng)PC機(jī)的BIOS中固化有對(duì)RTC進(jìn)行有關(guān)操作的函數(shù),例如INT 1AH等中斷服務(wù)程序,通常操作系統(tǒng)也直接利用這些函數(shù)對(duì)RTC進(jìn)行操作,例如從RTC中讀出有關(guān)數(shù)據(jù)對(duì)OS時(shí)鐘初始化、對(duì)RTC進(jìn)行更新等等。實(shí)際上,不通過BIOS而直接對(duì)RTC的有關(guān)端口進(jìn)行操作也是可以的。Linux中在內(nèi)核初始化完成后就完全拋棄了BIOS中的程序。我們可以看到,RTC處于最底層,提供最原始的時(shí)鐘數(shù)據(jù)。OS

8、時(shí)鐘建立在RTC之上,初始化完成后將完全由操作系統(tǒng)控制,和RTC脫離關(guān)系。操作系統(tǒng)通過OS時(shí)鐘提供給應(yīng)用程序所有和時(shí)間有關(guān)的服務(wù)。因?yàn)镺S時(shí)鐘完全是一個(gè)軟件問題,其所能表達(dá)的時(shí)間由操作系統(tǒng)的設(shè)計(jì)者決定,將OS時(shí)鐘定義為整型還是長(zhǎng)整型或者大的超乎想象都是設(shè)計(jì)者的事。Linux時(shí)間基準(zhǔn)以上我們了解了RTC(實(shí)時(shí)時(shí)鐘、硬件時(shí)鐘)和OS時(shí)鐘(系統(tǒng)時(shí)鐘、軟時(shí)鐘)。下面我們具體描述OS時(shí)鐘。我們知道,OS時(shí)鐘是由可編程定時(shí)/計(jì)數(shù)器產(chǎn)生的輸出脈沖觸發(fā)中斷而產(chǎn)生的。輸出脈沖的周期叫做一個(gè)“時(shí)鐘滴答”,有些書上也把它叫做“時(shí)標(biāo)”。計(jì)算機(jī)中的時(shí)間是以時(shí)鐘滴答為單位的,每一次時(shí)鐘滴答,系統(tǒng)時(shí)間就會(huì)加1。操作系統(tǒng)根據(jù)

9、當(dāng)前時(shí)鐘滴答的數(shù)目就可以得到以秒或毫秒等為單位的其他時(shí)間格式。不同的操作系統(tǒng)采用不同的“時(shí)間基準(zhǔn)”。定義“時(shí)間基準(zhǔn)”的目的是為了簡(jiǎn)化計(jì)算,這樣計(jì)算機(jī)中的時(shí)間只要表示為從這個(gè)時(shí)間基準(zhǔn)開始的時(shí)鐘滴答數(shù)就可以了。“時(shí)間基準(zhǔn)是由操作系統(tǒng)的設(shè)計(jì)者規(guī)定的。例如DOS的時(shí)間基準(zhǔn)是1980年1月1日,Unix和Minux的時(shí)間基準(zhǔn)是1970年1月1日上午12點(diǎn),Linux的時(shí)間基準(zhǔn)是1970年1月1日凌晨0點(diǎn)。Linux的時(shí)間系統(tǒng)通過上面的時(shí)鐘運(yùn)作機(jī)制,我們知道了OS時(shí)鐘在Linux中的重要地位。OS時(shí)鐘記錄的時(shí)間也就是通常所說的系統(tǒng)時(shí)間。系統(tǒng)時(shí)間是以“時(shí)鐘滴答”為單位的,而時(shí)鐘中斷的頻率決定了一個(gè)時(shí)鐘滴答的

10、長(zhǎng)短,例如每秒有100次時(shí)鐘中斷,那么一個(gè)時(shí)鐘滴答的就是10毫秒(記為10ms),相應(yīng)地,系統(tǒng)時(shí)間就會(huì)每10ms增1。不同的操作系統(tǒng)對(duì)時(shí)鐘滴答的定義是不同的,例如DOS的時(shí)鐘滴答滴答為1/18.2s,Minix的時(shí)鐘滴答為1/60s等等。時(shí)鐘中斷的產(chǎn)生前面我們看到,Linux的OS時(shí)鐘的物理產(chǎn)生原因是可編程定時(shí)/計(jì)數(shù)器產(chǎn)生的輸出脈沖,這個(gè)脈沖送入CPU,就可以引發(fā)一個(gè)中斷請(qǐng)求信號(hào),我們就把它叫做時(shí)鐘中斷?!皶r(shí)鐘中斷”是特別重要的一個(gè)中斷,因?yàn)檎麄€(gè)操作系統(tǒng)的活動(dòng)都受到它的激勵(lì)。系統(tǒng)利用時(shí)鐘中斷維持系統(tǒng)時(shí)間、促使環(huán)境的切換,以保證所有進(jìn)程共享CPU;利用時(shí)鐘中斷進(jìn)行記帳、監(jiān)督系統(tǒng)工作以及確定未來的

11、調(diào)度優(yōu)先級(jí)等工作??梢哉f,“時(shí)鐘中斷”是整個(gè)操作系統(tǒng)的脈搏。時(shí)鐘中斷的物理產(chǎn)生如圖所示:操作系統(tǒng)對(duì)可編程定時(shí)/計(jì)數(shù)器進(jìn)行有關(guān)初始化,然后定時(shí)/計(jì)數(shù)器就對(duì)輸入脈沖進(jìn)行計(jì)數(shù)(分頻),產(chǎn)生的三個(gè)輸出脈沖Out0、Out1、Out2各有用途,很多接口書都介紹了這個(gè)問題,我們只看Out0上的輸出脈沖,這個(gè)脈沖信號(hào)接到中斷控制器8259A_1的0號(hào)管腳,觸發(fā)一個(gè)周期性的中斷,我們就把這個(gè)中斷叫做時(shí)鐘中斷,時(shí)鐘中斷的周期,也就是脈沖信號(hào)的周期,我們叫做“滴答”或“時(shí)標(biāo)”(tick)。從本質(zhì)上說,時(shí)鐘中斷只是一個(gè)周期性的信號(hào),完全是硬件行為,該信號(hào)觸發(fā)CPU去執(zhí)行一個(gè)中斷服務(wù)程序4.2.2數(shù)據(jù)結(jié)構(gòu)與變量說明1

12、、 結(jié)構(gòu)體n Xtime在頭文件include/linux/time.h中struct timeval time_t tv_sec; /* seconds */suseconds_t tv_usec; /* microseconds */;其中,成員tv_sec表示當(dāng)前時(shí)間距UNIX時(shí)間基準(zhǔn)的秒數(shù)值,而成員tv_usec則表示一秒之內(nèi)的微秒值,且tv_usec0。Linux內(nèi)核通過timeval結(jié)構(gòu)類型的全局變量xtime來維持當(dāng)前時(shí)間,該變量定義在kernel/timer.c文件中,如下所示:/* The current time */volatile struct timeval xtim

13、e _attribute_ (aligned (16);n struct irqaction irq0時(shí)鐘中斷結(jié)構(gòu)體2、宏定義:n HZ 節(jié)拍率時(shí)鐘滴答的頻率(HZ):也即1秒時(shí)間內(nèi)PIT所產(chǎn)生的時(shí)鐘滴答次數(shù)。在#include 中設(shè)置2.5版本前,時(shí)鐘中斷頻率為100Hz一次時(shí)鐘滴答的具體時(shí)間間隔應(yīng)該是(1000msHZ)10ms。n #define TICK_SIZE tick宏TICK_SIZE來作為tick變量的引用別名Linux用全局變量tick來表示時(shí)鐘滴答的時(shí)間間隔長(zhǎng)度tick=(HZ2)HZ其中被除數(shù)表達(dá)式中的HZ2的作用就是用來將 tick值向上圓整成一個(gè)整型數(shù)。n #ifn

14、def CONFIG_X86_TSC 表示是否存在TSC寄存器。n CLOCK_TICK_RATE 1s內(nèi)時(shí)鐘周期個(gè)數(shù)n LATCH定義要寫到PIT通道0的計(jì)數(shù)器中的值,它表示PIT將沒隔多少個(gè)時(shí)鐘周期產(chǎn)生一次時(shí)鐘中斷鎖:n xtime_lock 相對(duì)時(shí)間鎖,保證進(jìn)程對(duì)xtime修改的互斥性n rtc_lock rtc鎖,保證進(jìn)程對(duì)rtc操作的互斥,初始未鎖n i8253_lock 計(jì)數(shù)器8253鎖,初始未鎖n i8259A_lock 中斷8259A鎖n rtc_lock 實(shí)時(shí)時(shí)鐘RTC鎖,用于保證操作RTC互斥3、主要變量cpu_khz系統(tǒng)時(shí)鐘頻率delay_at_last_interrup

15、t中斷服務(wù)執(zhí)行延遲delay_at_last_interrupt:由于從產(chǎn)生時(shí)鐘中斷的那個(gè)時(shí)刻到內(nèi)核時(shí)鐘中斷服務(wù)函數(shù) timer_interrupt真正在CPU上執(zhí)行的那個(gè)時(shí)刻之間是有一段延遲間隔的,因此,Linux內(nèi)核用變量 delay_at_last_interrupt來表示這一段時(shí)間延遲間隔.last_tsc_low表示中斷服務(wù)timer_interrupt真正在CPU上執(zhí)行時(shí)刻的TSC寄存器值的低32位(LSB)。fast_gettimeoffset_quotient1個(gè)TSC計(jì)數(shù)值代表多長(zhǎng)的時(shí)間間隔jiffies表示自內(nèi)核上一次啟動(dòng)以來的時(shí)鐘滴答次數(shù)。每發(fā)生一次時(shí)鐘滴答,內(nèi)核的時(shí)鐘中

16、斷處理函數(shù)timer_interrupt()都要將該全局變量jiffies加1。wall_jiffies保存內(nèi)核上一次更新xtime時(shí)的jiffies值xtime表示當(dāng)前時(shí)間距UNIX時(shí)間基準(zhǔn)19700101 00:00:00的相對(duì)秒數(shù)值last_rtc_update表示內(nèi)核最近一次成功地對(duì)RTC進(jìn)行 更新的時(shí)間(單位是秒數(shù))。timer_ack時(shí)間中斷申請(qǐng)use_tsc表示內(nèi)核是否使用CPU的TSC寄存器4.2.3函數(shù)組織流程及功能do_fast_gettimeoffset通過TSC寄存器來計(jì)算do_fast_gettimeoffset()函數(shù)被執(zhí)行的時(shí)刻到上一次時(shí)鐘中斷發(fā)生時(shí)的時(shí)間間隔值d

17、o_slow_gettimeoffset在無TSC的情況下計(jì)算函數(shù)被執(zhí)行的時(shí)刻到上一次時(shí)鐘中斷發(fā)生時(shí)的時(shí)間間隔值do_gettimeofday完成實(shí)際的當(dāng)前時(shí)間檢索工作,精確地修正xtime的值do_settimeofday把 tv 的時(shí)間設(shè)定為系統(tǒng)時(shí)間set_rtc_mmss向RTC中回寫當(dāng)前時(shí)間與日期,該函數(shù)用來更新RTC中的時(shí)間do_timer_interrupt中斷服務(wù)程序通用例程,執(zhí)行真正的中斷時(shí)鐘服務(wù)timer_interrupt時(shí)鐘中斷程序get_cmos_time內(nèi)核在啟動(dòng)時(shí)從RTC中讀取啟動(dòng)時(shí)的時(shí)間與日期僅僅在內(nèi)核啟動(dòng)時(shí)被調(diào)用一次calibrate_tsc校準(zhǔn)TSC,獲取更新

18、的fast_gettimeoffset_quotient的值time_init系統(tǒng)時(shí)鐘初始化4.2.3程序段功能描述與代碼注釋/* * linux/arch/i386/kernel/time.c * * Copyright (C) 1991, 1992, 1995 Linus Torvalds * * This file contains the PC-specific time handling details: * reading the RTC at bootup, etc. * 1994-07-02 Alan Modra *fixed set_rtc_mmss, fixed time.

19、year for = 2000, new mktime * 1995-03-26 Markus Kuhn * fixed 500 ms bug at call to set_rtc_mmss, fixed DS12887 * precision CMOS clock update * 1996-05-03 Ingo Molnar * fixed time warps in do_slow|fast_gettimeoffset() * 1997-09-10Updated NTP code according to technical memorandum Jan 96 *A Kernel Mod

20、el for Precision Timekeeping by Dave Mills * 1998-09-05 (Various) *More robust do_fast_gettimeoffset() algorithm implemented *(works with APM, Cyrix 6x86MX and Centaur C6), *monotonic gettimeofday() with fast_get_timeoffset(), *drift-proof precision TSC calibration on boot *(C. Scott Ananian , Andre

21、w D. *Balsa , Philip Gladstone ; *ported from 2.0.35 Jumbo-9 by Michael Krause ). * 1998-12-16 Andrea Arcangeli *Fixed Jumbo-9 code in 2.1.131: do_gettimeofday was missing 1 jiffy *because was not accounting lost_ticks. * 1998-12-24 Copyright (C) 1998 Andrea Arcangeli *Fixed a xtime SMP race (we nee

22、d the xtime_lock rw spinlock to *serialize accesses to xtime/lost_ticks). */#include #include #include #include 節(jié)拍率值在這里設(shè)置,2.5版本前,時(shí)鐘中斷頻率為100Hz時(shí)鐘滴答的頻率(HZ):也即1秒時(shí)間內(nèi)PIT所產(chǎn)生的時(shí)鐘滴答次數(shù)。類似地,這個(gè)值也是由PIT通道0的計(jì)數(shù)器初值決定的(反過來說,確 定了時(shí)鐘滴答的頻率值后也就可以確定8254 PIT通道0的計(jì)數(shù)器初值)。Linux內(nèi)核用宏HZ來表示時(shí)鐘滴答的頻率,而且在不同的平臺(tái)上HZ有不同的定義值。根據(jù)HZ的值,我們也可以知道一次

23、時(shí)鐘滴答的具體時(shí)間間隔應(yīng)該是(1000msHZ)10ms。#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * for x86_do_profile() */#include /*在linux系統(tǒng)中,起作用的是軟件時(shí)鐘,即系統(tǒng)時(shí)鐘。*/unsigned long cpu_khz;/*

24、 Detected as we calibrate the TSC */* Number of usecs that the last interrupt was delayed */static int delay_at_last_interrupt;中斷服務(wù)執(zhí)行延遲delay_at_last_interrupt:由于從產(chǎn)生時(shí)鐘中斷的那個(gè)時(shí)刻到內(nèi)核時(shí)鐘中斷服務(wù)函數(shù) timer_interrupt真正在CPU上執(zhí)行的那個(gè)時(shí)刻之間有一段延遲間隔, Linux內(nèi)核用變量 delay_at_last_interrupt來表示這一段時(shí)間延遲間隔.static unsigned long last_ts

25、c_low; /* lsb 32 bits of Time Stamp Counter */它表示中斷服務(wù)timer_interrupt真正在CPU上執(zhí)行時(shí)刻的TSC寄存器值的低32位(LSB)。顯然,通過delay_at_last_interrupt、last_tsc_low和時(shí)刻x處的TSC寄存器值,我們就可以完全確定時(shí)刻x距 上一次時(shí)鐘中斷產(chǎn)生時(shí)刻的時(shí)間間隔偏移offset_usec的值。/* Cached *multiplier* to convert TSC counts to microseconds. * (see the equation below). * Equal to

26、232 * (1 / (clocks per usec) ). * Initialized in time_init. */unsigned long fast_gettimeoffset_quotient;與可編程定時(shí)器PIT相比,用TSC寄存器可以獲得更精確的時(shí)間度量。但是在可以使用TSC之前,它必須精確地確定1個(gè)TSC計(jì)數(shù)值到底代表多長(zhǎng) 的時(shí)間間隔,也即到底要過多長(zhǎng)時(shí)間間隔TSC寄存器才會(huì)加1。Linux內(nèi)核用全局變量fast_gettimeoffset_quotient來表示這 個(gè)值這個(gè)變量的值是通過下述公式來計(jì)算的: fast_gettimeoffset_quotient (232)

27、 / (每微秒內(nèi)的時(shí)鐘周期個(gè)數(shù)) 定義在arch/i386/kernel/time.c文件中的函數(shù)calibrate_tsc()就是根據(jù)上述公式來計(jì)算 fast_gettimeoffset_quotient的值的。顯然這個(gè)計(jì)算過程必須在內(nèi)核啟動(dòng)時(shí)完成,因此,函數(shù)calibrate_tsc()只被 初始化函數(shù)time_init()所調(diào)用。 extern rwlock_t xtime_lock; /相對(duì)時(shí)間鎖,保證進(jìn)程對(duì)xtime修改的互斥性extern unsigned long wall_jiffies;jiffies表示系統(tǒng)自啟動(dòng)以來的時(shí)鐘滴答數(shù)目。由于Bottom Half機(jī)制在執(zhí)行時(shí)間具

28、有某些不確定性,因此在timer_bh()函數(shù)(更新xtime,執(zhí)行定時(shí)器)得到真正執(zhí)行之前,期間可能又會(huì)有幾次時(shí)鐘中斷發(fā)生。這樣就會(huì)造成時(shí)鐘滴答的丟失現(xiàn)象。為了處理這種情況,Linux內(nèi)核使用了一個(gè)輔助全局變量wall_jiffies,來表示上一次更新xtime時(shí)的jiffies值。而timer_bh()函數(shù)真正執(zhí)行時(shí)的jiffies值與wall_jiffies的差就是在timer_bh()真正執(zhí)行之前所發(fā)生的時(shí)鐘中斷次數(shù)。spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED; /rtc鎖,保證進(jìn)程對(duì)rtc操作的互斥,初始未鎖= do_fast_gettimeof

29、fset =計(jì)算該函數(shù)執(zhí)行的時(shí)刻到上一次時(shí)鐘中斷發(fā)生時(shí)的時(shí)間間隔值static inline unsigned long do_fast_gettimeoffset(void)register unsigned long eax, edx; /* Read the Time Stamp Counter */rdtsc(eax,edx);先調(diào)用rdtsc()函數(shù)讀取當(dāng)前時(shí)刻TSC寄存器的值,并將其高32位保存在edx局部變量中,低32位保存在局部變量eax中/* . relative to previous jiffy (32 bits is enough) */eax -= last_tsc_

30、low;/* tsc_low delta */讓局部變量eaxtsc_loweaxlast_tsc_low;也即計(jì)算當(dāng)前時(shí)刻的TSC值與上一次時(shí)鐘中斷服務(wù)函數(shù)timer_interrupt()執(zhí)行時(shí)的TSC值之間的差值。/* * Time offset = (tsc_low delta) * fast_gettimeoffset_quotient * = (tsc_low delta) * (usecs_per_clock) * = (tsc_low delta) * (usecs_per_jiffy / clocks_per_jiffy) * * Using a mull instead o

31、f a divl saves up to 31 clock cycles * in the critical path. */顯然,從上一次timer_interrupt()到當(dāng)前時(shí)刻的時(shí)間間隔就是(tsc_lowfast_gettimeoffset_quotient)。因此用一條mul指令來計(jì)算這個(gè)乘法表達(dá)式的值。_asm_(mull %2:=a (eax), =d (edx):rm (fast_gettimeoffset_quotient), 0 (eax);/* our adjusted time offset in microseconds */return delay_at_last

32、_interrupt + edx;返回值delay_at_last_interrupt(tsc_lowfast_gettimeoffset_quotient)就是從上一次時(shí)鐘中斷發(fā)生時(shí)到當(dāng)前時(shí)刻之間的時(shí)間偏移間隔值。=end= do_fast_gettimeoffset =#define TICK_SIZE tick宏TICK_SIZE來作為tick變量的引用別名Linux用全局變量tick來表示時(shí)鐘滴答的時(shí)間間隔長(zhǎng)度tick變量的單位是微妙(s),由于在不同平臺(tái)上宏HZ的值會(huì)有所不同,因此方程式tickHZ的結(jié)果可能會(huì)是個(gè)小數(shù),因 此將其進(jìn)行四舍五入成一個(gè)整數(shù),所以Linux將tick定義成

33、(HZ2)HZ,其中被除數(shù)表達(dá)式中的HZ2的作用就是用來將 tick值向上圓整成一個(gè)整型數(shù)。spinlock_t i8253_lock = SPIN_LOCK_UNLOCKED; 計(jì)數(shù)器8253鎖,初始未鎖(1) 通道0用來負(fù)責(zé)更新系統(tǒng)時(shí)鐘。每當(dāng)一個(gè)時(shí)鐘滴答過去時(shí),它就會(huì)通過IRQ0向系統(tǒng)產(chǎn)生一次時(shí)鐘中斷。 (2) 通道1通常用于控制DMAC對(duì)RAM的刷新。 (3) 通道2被連接到PC機(jī)的揚(yáng)聲器,以產(chǎn)生方波信號(hào)。extern spinlock_t i8259A_lock; 中斷8259A鎖#ifndef CONFIG_X86_TSC 宏CONFIG_X86_TSC也表示是否存在TSC寄存器。/

34、* This function must be called with interrupts disabled * It was inspired by Steve McCannes microtime-i386 for BSD. - jrs * * However, the pc-audio speaker driver changes the divisor so that * it gets interrupted rather more often - it loads 64 into the * counter rather than 11932! This has an adver

35、se impact on * do_gettimeoffset() - it stops working! What is also not * good is that the interval that our timer function gets called * is no longer 10.0002 ms, but 9.9767 ms. To get around this * would require using a different timing source. Maybe someone * could use the RTC - I know that this ca

36、n interrupt at frequencies * ranging from 8192Hz to 2Hz. If I had the energy, Id somehow fix * it so that at startup, the timer code in sched.c would select * using either the RTC or the 8253 timer. The decision would be * based on whether there was any other device around that needed * to trample o

37、n the 8253. Id set up the RTC to interrupt at 1024 Hz, * and then do some jiggery to have a version of do_timer that * advanced the clock by 1/1024 s. Every time that reached over 1/100 * of a second, then do all the old code. If the time was kept correct * then do_gettimeoffset could just return 0

38、- there is no low order * divider that can be accessed. * * Ideally, you would be able to use the RTC for the speaker driver, * but it appears that the speaker driver really needs interrupt more * often than every 120 us or so. * * Anyway, this needs more thought.pjsg (1993-08-28) * * If you are rea

39、lly that interested, you should be reading * tocols.time.ntp! */= do_slow_gettimeoffset =static unsigned long do_slow_gettimeoffset(void)int count;static int count_p = LATCH; /* for the first call after boot */ LATCH為計(jì)數(shù)初值static unsigned long jiffies_p = 0;/* * cache volatile jiffies temporar

40、ily; we have IRQs turned off. */unsigned long jiffies_t;/* gets recalled with irq locally disabled */spin_lock(&i8253_lock);/* timer count may underflow right here */outb_p(0x00, 0x43);/* latch the count ASAP */把控制字寫到8253控制端口,用于鎖存count = inb_p(0x40);/* read the latched count */將計(jì)數(shù)器0的值寫入count/* * We

41、do this guaranteed double memory access instead of a _p * postfix in the previous port access. Wheee, hackady hack */ jiffies_t = jiffies;count |= inb_p(0x40) max + 1 */ if (count LATCH) outb_p(0x34, 0x43);將控制字寫入控制端口 outb_p(LATCH & 0xff, 0x40); outb(LATCH 8, 0x40); count = LATCH - 1; spin_unlock(&i8

42、253_lock);/* * avoiding timer inconsistencies (they are rare, but they happen). * there are two kinds of problems that must be avoided here: * 1. the timer counter underflows * 2. hardware problem with the timer, not giving us continuous time, * the counter does small jumps upwards on some Pentium s

43、ystems, * (see ct 95/10 page 335 for Neptun bug.) */* you can safely undefine this if you dont have the Neptune chipset */#define BUGGY_NEPTUN_TIMERif( jiffies_t = jiffies_p ) if( count count_p ) /* the nutcase */int i;spin_lock(&i8259A_lock);/* * This is tricky when I/O APICs are used; * see do_tim

44、er_interrupt(). */i = inb(0x20);spin_unlock(&i8259A_lock);/* assumption about timer being IRQ0 */if (i & 0x01) /* * We cannot detect lost timer interrupts . * well, thats why we call them lost, dont we? :) * hmm, on the Pentium and Alpha we can . sort of */count -= LATCH; else #ifdef BUGGY_NEPTUN_TI

45、MER/* * for the Neptun bug we know that the latch * command doesnt latch the high and low value * of the counter atomically. Thus we have to * substract 256 from the counter * . funny, isnt it? :) */count -= 256;#elseprintk(do_slow_gettimeoffset(): hardware timer problem?n);#endif elsejiffies_p = ji

46、ffies_t;count_p = count;count = (LATCH-1) - count) * TICK_SIZE;count = (count + LATCH/2) / LATCH;return count;=end= do_slow_gettimeoffset =static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset;#else#define do_gettimeoffset()do_fast_gettimeoffset()#endif=精確修正時(shí)間us= do_gettimeofday = =

47、完成實(shí)際的當(dāng)前時(shí)間檢索工作。由于gettimeofday()系統(tǒng)調(diào)用要求時(shí)間精度要達(dá)到微秒級(jí),因此do_gettimeofday ()函數(shù)不能簡(jiǎn)單地返回xtime中的值即可,而必須精確地確定自從時(shí)鐘驅(qū)動(dòng)的Bottom Half上一次更新xtime的那個(gè)時(shí)刻到do_gettimeofday()函數(shù)的當(dāng)前執(zhí)行時(shí)刻 之間的具體時(shí)間間隔長(zhǎng)度,以便精確地修正xtime的值/* * This version of gettimeofday has microsecond resolution * and better than microsecond precision on fast x86 machi

48、nes with TSC. */void do_gettimeofday(struct timeval *tv)unsigned long flags;unsigned long usec, sec;read_lock_irqsave(&xtime_lock, flags);usec = do_gettimeoffset();調(diào)用函數(shù)do_gettimeoffset()計(jì)算從上一次時(shí)鐘中斷發(fā)生到執(zhí)行do_gettimeofday()函數(shù)的當(dāng)前時(shí)刻之間的時(shí)間間隔offset_usec。unsigned long lost = jiffies - wall_jiffies;if (lost)use

49、c += lost * ( / HZ); /HZ -tick時(shí)鐘滴答時(shí)間間隔長(zhǎng)度通過wall_jiffies和jiffies計(jì)算丟失的時(shí)鐘間隔lost_usec的值。sec = xtime.tv_sec; usec += xtime.tv_usec;當(dāng)前實(shí)際時(shí)間(墻上時(shí)間)定義在文件kernel/timer.c中: struct timespec xtime;timespec數(shù)據(jù)結(jié)構(gòu)定義在文件中,形式如下:struct timespec time_t tv_sec; /* 秒 */以秒為單位,存放著自1970年1月1日以來經(jīng)過的時(shí)間long tv_nsec; /* 納秒 */ 記錄了自上一秒開

50、始經(jīng)過的納秒數(shù); read_unlock_irqrestore(&xtime_lock, flags);然后,令sec=xtime.tv_sec,usec=xtime.tv_usec+lost_usec+offset_usec。顯然,sec表示系統(tǒng)當(dāng)前時(shí)間在秒數(shù)量級(jí)上的值,而usec表示系統(tǒng)當(dāng)前時(shí)間在微秒量級(jí)上的值。while (usec = ) usec -= ;sec+;用一個(gè)while循環(huán)來判斷usec是否已經(jīng)溢出而超過us1秒。如果溢出,則將usec減去us并相應(yīng)地將sec增加1,直到usec不溢出為止。tv-tv_sec = sec;tv-tv_usec = usec;最后,用sec

51、和usec分別更新參數(shù)指針?biāo)赶虻膖imeval結(jié)構(gòu)變量。至此,整個(gè)查詢過程結(jié)束。=end= do_gettimeofday =設(shè)定系統(tǒng)時(shí)間= do_settimeofday = =把 tv 的時(shí)間設(shè)定為系統(tǒng)時(shí)間void do_settimeofday(struct timeval *tv)write_lock_irq(&xtime_lock);/* * This is revolting. We need to set xtime correctly. However, the * value in this location is the value at the most recent update of * wall time.

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論