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

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

生活随笔

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

linux

Linux之时钟中断

發(fā)布時(shí)間:2025/4/16 linux 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux之时钟中断 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

from:深入分析Linux內(nèi)核源碼(http://oss.org.cn/kernel-book/)

?時(shí)鐘中斷的產(chǎn)生

? ? ?Linux的OS時(shí)鐘的物理產(chǎn)生原因是可編程定時(shí)/計(jì)數(shù)器產(chǎn)生的輸出脈沖,這個(gè)脈沖送入CPU,就可以引發(fā)一個(gè)中斷請(qǐng)求信號(hào),我們就把它叫做時(shí)鐘中斷。

“時(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)工作以及確定未來(lái)的調(diào)度優(yōu)先級(jí)等工作。可以說(shuō),“時(shí)鐘中斷”是整個(gè)操作系統(tǒng)的脈搏。

時(shí)鐘中斷的物理產(chǎn)生如圖所示:

???????????????????????
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 圖 8253和8259A的物理連接方式

操作系統(tǒng)對(duì)可編程定時(shí)/計(jì)數(shù)器進(jìn)行有關(guān)初始化,然后定時(shí)/計(jì)數(shù)器就對(duì)輸入脈沖進(jìn)行計(jì)數(shù)(分頻),產(chǎn)生的三個(gè)輸出脈沖Out0、Out1、Out2各有用途,很多接口書(shū)都介紹了這個(gè)問(wèn)題,我們只看Out0上的輸出脈沖,這個(gè)脈沖信號(hào)接到中斷控制器8259A_1的0號(hào)管腳,觸發(fā)一個(gè)周期性的中斷,我們就把這個(gè)中斷叫做時(shí)鐘中斷,時(shí)鐘中斷的周期,也就是脈沖信號(hào)的周期,我們叫做“滴答”或“時(shí)標(biāo)”(tick)。從本質(zhì)上說(shuō),時(shí)鐘中斷只是一個(gè)周期性的信號(hào),完全是硬件行為,該信號(hào)觸發(fā)CPU去執(zhí)行一個(gè)中斷服務(wù)程序,但是為了方便,我們就把這個(gè)服務(wù)程序叫做時(shí)鐘中斷。

?

Linux實(shí)現(xiàn)時(shí)鐘中斷的全過(guò)程

1.可編程定時(shí)/計(jì)數(shù)器的初始化

?

IBM PC中使用的是8253或8254芯片。有關(guān)該芯片的詳細(xì)知識(shí)我們不再詳述,只大體介紹以下它的組成和作用,如下表5.1所示:

?

表 ? ? ? ? 8253/8254的組成及作用

名稱(chēng)

端口地址

工作方式

產(chǎn)生的輸出脈沖的用途

計(jì)數(shù)器0

0x40

方式3

時(shí)鐘中斷,也叫系統(tǒng)時(shí)鐘

計(jì)數(shù)器1

0x41

方式2

動(dòng)態(tài)存儲(chǔ)器刷新

計(jì)數(shù)器2

0x42

方式3

揚(yáng)聲器發(fā)聲

控制寄存器

0x43

/

用于8253的初始化,接收控制字

?

計(jì)數(shù)器0的輸出就是圖5.3中的Out0,它的頻率由操作系統(tǒng)的設(shè)計(jì)者確定,Linux對(duì)8253的初始化程序段如下(在/arch/i386/kernel/i8259.c的init_IRQ()函數(shù)中):

?

set_intr_gate(ox20, interrupt[0]);

/*在IDT的第0x20個(gè)表項(xiàng)中插入一個(gè)中斷門(mén)。這個(gè)門(mén)中的段選擇符設(shè)置成內(nèi)核代碼段的選擇符,偏移域設(shè)置成0號(hào)中斷處理程序的入口地址。*/

?

outb_p(0x34,0x43);?????/*?寫(xiě)計(jì)數(shù)器0的控制字:工作方式2*/

outb_p(LATCH & 0xff , 0x40);???/*?寫(xiě)計(jì)數(shù)初值LSB??計(jì)數(shù)初值低位字節(jié)*/??

outb(LATCH >> 8 , 0x40);???/*?寫(xiě)計(jì)數(shù)初值MSB?計(jì)數(shù)初值高位字節(jié)*/

?

LATCH(英文意思為:鎖存器,即其中鎖存了計(jì)數(shù)器0的初值)為計(jì)數(shù)器0的計(jì)數(shù)初值,在/include/linux/timex.h中定義如下:

?

#define CLOCK_TICK_RATE????1193180????/*?圖5.3中的輸入脈沖?*/

#define LATCH??((CLOCK_TICK_RATE + HZ/2) / HZ)??/*?計(jì)數(shù)器0的計(jì)數(shù)初值?*/

?

CLOCK_TICK_RATE是整個(gè)8253的輸入脈沖,如圖5.3中所示為1.193180MHz,是近似為1MHz的方波信號(hào),8253內(nèi)部的三個(gè)計(jì)數(shù)器都對(duì)這個(gè)時(shí)鐘進(jìn)行計(jì)數(shù),進(jìn)而產(chǎn)生不同的輸出信號(hào),用于不同的用途。

HZ表示計(jì)數(shù)器0的頻率,也就是時(shí)鐘中斷或系統(tǒng)時(shí)鐘的頻率,在/include/asm/param.h中定義如下:

?

#define HZ 100

?

2.與時(shí)鐘中斷相關(guān)的函數(shù)

下面我們看時(shí)鐘中斷觸發(fā)的服務(wù)程序,該程序代碼比較復(fù)雜,分布在不同的源文件中,主要包括如下函數(shù):

時(shí)鐘中斷程序:timer_interrupt( );

中斷服務(wù)通用例程do_timer_interrupt();

時(shí)鐘函數(shù):do_timer( );

中斷安裝程序:setup_irq(?);

中斷返回函數(shù):ret_from_intr(?);

?

前三個(gè)函數(shù)的調(diào)用關(guān)系如下:

?????timer_interrupt(?)

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ????????

? ? ? ? ? ? ? ? ? ? ? ? ? do_timer_interrupt()

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ????

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?do_timer(?)

(1)?timer_interrupt(?)

????這個(gè)函數(shù)大約每10ms被調(diào)用一次,實(shí)際上,?timer_interrupt( )函數(shù)是一個(gè)封裝例程,它真正做的事情并不多,但是,作為一個(gè)中斷程序,它必須在關(guān)中斷的情況下執(zhí)行。如果只考慮單處理機(jī)的情況,該函數(shù)主要語(yǔ)句就是調(diào)用do_timer_interrupt()函數(shù)。

?

(2)?do_timer_interrupt()

do_timer_interrupt()函數(shù)有兩個(gè)主要任務(wù),一個(gè)是調(diào)用do_timer( ),另一個(gè)是維持實(shí)時(shí)時(shí)鐘(RTC,每隔一定時(shí)間段要回寫(xiě)),其實(shí)現(xiàn)代碼在/arch/i386/kernel/time.c中, 為了突出主題,筆者對(duì)以下函數(shù)作了改寫(xiě),以便于讀者理解:

?

static?inline void do_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)

{

???do_timer(regs); /*?調(diào)用時(shí)鐘函數(shù),將時(shí)鐘函數(shù)等同于時(shí)鐘中斷未嘗不可*/

????

???if(xtime.tv_sec > last_rtc_update + 660)

update_RTC();

?

?/*每隔11分鐘就更新RTC中的時(shí)間信息,以使OS時(shí)鐘和RTC時(shí)鐘保持同步,11分鐘即660秒,xtime.tv_sec的單位是秒,last_rtc_update記錄的是上次RTC更新時(shí)的值?*/

???????????????????????????????????????????????????????

}

?

??其中,xtime是前面所提到的timeval類(lèi)型,這是一個(gè)全局變量。

?

(3)?時(shí)鐘函數(shù)do_timer() (在/kernel/sched.c中)

?

void?do_timer(struct pt_regs * regs)

{

???(*(unsigned long *)&jiffies)++;??/*更新系統(tǒng)時(shí)間,這種寫(xiě)法保證對(duì)jiffies

操作的原子性*/

?

?update_process_times();

????++lost_ticks;

???if(?! user_mode ( regs ) )

???????++lost_ticks_system;

?

???????mark_bh(TIMER_BH);???????????

???if?(tq_timer)????????????????????

???????mark_bh(TQUEUE_BH);

}

?

其中,update_process_times()函數(shù)與進(jìn)程調(diào)度有關(guān),從函數(shù)的名子可以看出,它處理的是與當(dāng)前進(jìn)程與時(shí)間有關(guān)的變量,例如,要更新當(dāng)前進(jìn)程的時(shí)間片計(jì)數(shù)器counter,如果counter<=0,則要調(diào)用調(diào)度程序,要處理進(jìn)程的所有定時(shí)器:實(shí)時(shí)、虛擬、概況,另外還要做一些統(tǒng)計(jì)工作。

與時(shí)間有關(guān)的事情很多,不能全都讓這個(gè)函數(shù)去完成,這是因?yàn)檫@個(gè)函數(shù)是在關(guān)中斷的情況下執(zhí)行,必須處理完最重要的時(shí)間信息后退出,以處理其他事情。那么,與時(shí)間相關(guān)的其他信息誰(shuí)去處理,何時(shí)處理?這就是由第三章討論的后半部分去去處理。 上面timer_interrupt()(包括它所調(diào)用的函數(shù))所做的事情就是上半部分。

在該函數(shù)中還有兩個(gè)變量lost_ticks和lost_ticks_system,這是用來(lái)記錄timer_bh()執(zhí)行前時(shí)鐘中斷發(fā)生的次數(shù)。因?yàn)闀r(shí)鐘中斷發(fā)生的頻率很高(每10ms一次),所以在timer_bh()執(zhí)行之前,可能已經(jīng)有時(shí)鐘中斷發(fā)生了,而timer_bh()要提供定時(shí)、記費(fèi)等重要操作,所以為了保證時(shí)間計(jì)量的準(zhǔn)確性,使用了這兩個(gè)變量。lost_ticks用來(lái)記錄timer_bh()執(zhí)行前時(shí)鐘中斷發(fā)生的次數(shù),如果時(shí)鐘中斷發(fā)生時(shí)當(dāng)前進(jìn)程運(yùn)行于內(nèi)核態(tài),則lost_ticks_system用來(lái)記錄timer_bh()執(zhí)行前在內(nèi)核態(tài)發(fā)生時(shí)鐘中斷的次數(shù),這樣可以對(duì)當(dāng)前進(jìn)程精確記費(fèi)。

?

(4)中斷安裝程序

?????從上面的介紹可以看出,時(shí)鐘中斷與進(jìn)程調(diào)度密不可分,因此,一旦開(kāi)始有時(shí)鐘中斷就可能要進(jìn)行調(diào)度,在系統(tǒng)進(jìn)行初始化時(shí),所做的大量工作之一就是對(duì)時(shí)鐘進(jìn)行初始化,其函數(shù)time_init ()的代碼在/arch/i386/kernel/time.c中,對(duì)其簡(jiǎn)寫(xiě)如下:

?void?__init time_init(void)

??{

xtime.tv_sec=get_cmos_time();

xtime.tv_usec=0;

setup_irq(0,&irq0);

}

??

???其中的get_cmos_time()函數(shù)就是把當(dāng)時(shí)的實(shí)際時(shí)間從CMOS時(shí)鐘芯片讀入變量xtime中,時(shí)間精度為秒。而setup_irq(0,&irq0)就是時(shí)鐘中斷安裝函數(shù),那么irq0指的是什么呢,它是一個(gè)結(jié)構(gòu)類(lèi)型irqaction,其定義及初值如下:

?

static?struct irqaction irq0??= { timer_interrupt, SA_INTERRUPT, 0, "timer", NULL, NULL};

?

setup_irq(0, &irq0)的代碼在/arch/i386/kernel/irq.c中,其主要功能就是將中斷程序連入相應(yīng)的中斷請(qǐng)求隊(duì)列,以等待中斷到來(lái)時(shí)相應(yīng)的中斷程序被執(zhí)行。

?

到現(xiàn)在為止,我們僅僅是把時(shí)鐘中斷程序掛入中斷請(qǐng)求隊(duì)列,什么時(shí)候執(zhí)行,怎樣執(zhí)行,這是一個(gè)復(fù)雜的過(guò)程(參見(jiàn)第三章),為了讓讀者對(duì)時(shí)鐘中斷有一個(gè)完整的認(rèn)識(shí),我們忽略中間過(guò)程,而給出一個(gè)整體描述。我們將有關(guān)函數(shù)改寫(xiě)如下,體現(xiàn)時(shí)鐘中斷的大意:

?

do_timer_interrupt( )??????????/*這是一個(gè)偽函數(shù)?*/

{????????????????????????????????????????????

???SAVE_ALL????????????????????/*保存處理機(jī)現(xiàn)場(chǎng)?*/

???intr_count += 1;??????????????/*?這段操作不允許被中斷?*/

???timer_interrupt()?????????????/*?調(diào)用時(shí)鐘中斷程序?*/

???intr_count -= 1;??????????????

???jmp ret_from_intr?????????????/*?中斷返回函數(shù)?*/

}

???

???其中,jmp ret_from_intr?是一段匯編代碼,也是一個(gè)較為復(fù)雜的過(guò)程,它最終要調(diào)用jmp ret_from_sys_call,即系統(tǒng)調(diào)用返回函數(shù),而這個(gè)函數(shù)與進(jìn)程的調(diào)度又密切相關(guān),,因此,我們重點(diǎn)分析??jmp ret_from_sys_call。

???

3.系統(tǒng)調(diào)用返回函數(shù):

??系統(tǒng)調(diào)用返回函數(shù)的源代碼在/arch/i386/kernel/entry.S中

??

ENTRY(ret_from_sys_call)

?????????cli?????????????????# need_resched and signals atomic test

?????????cmpl?$0,need_resched(%ebx)

?????????jne?reschedule

?????????cmpl?$0,sigpending(%ebx)

?????????jne?signal_return

?restore_all:

?????????RESTORE_ALL

?

?????????ALIGN

?signal_return:

?????????sti??????????????# we can get here from an interrupt handler

?????????testl?$(VM_MASK),EFLAGS(%esp)

?????????movl?%esp,%eax

?????????jne?v86_signal_return

?????????xorl?%edx,%edx

?????????call?SYMBOL_NAME(do_signal)

?????????jmp?restore_all

?

?????????ALIGN

????????v86_signal_return:

?????????call?SYMBOL_NAME(save_v86_state)

?????????movl?%eax,%esp

?????????xorl?%edx,%edx

?????????call?SYMBOL_NAME(do_signal)

?????????jmp?restore_all

??….

?reschedule:

?????????call?SYMBOL_NAME(schedule)????# test

????????jmp?ret_from_sys_call

?

這一段匯編代碼就是前面我們所說(shuō)的“從系統(tǒng)調(diào)用返回函數(shù)”ret_from_sys_call,它是從中斷、異常及系統(tǒng)調(diào)用返回時(shí)的通用接口。這段代碼主體就是ret_from_sys_call函數(shù),其執(zhí)行過(guò)程中要調(diào)用其它一些函數(shù)(實(shí)際上是一段代碼,不是真正的函數(shù)),在此我們列出相關(guān)的幾個(gè)函數(shù):

(1)ret_from_sys_call:主體

(2)reschedule:檢測(cè)是否需要重新調(diào)度

(3)signal_return:處理當(dāng)前進(jìn)程接收到的信號(hào)

(4)v86_signal_return:處理虛擬86模式下當(dāng)前進(jìn)程接收到的信號(hào)

(5)RESTORE_ALL:我們把這個(gè)函數(shù)叫做徹底返回函數(shù),因?yàn)閳?zhí)行該函數(shù)之后,就返回到當(dāng)前進(jìn)程的地址空間中去了。

可以看到ret_from_sys_call的主要作用有:

檢測(cè)調(diào)度標(biāo)志need_resched,決定是否要執(zhí)行調(diào)度程序;處理當(dāng)前進(jìn)程的信號(hào);恢復(fù)當(dāng)前進(jìn)程的環(huán)境使之繼續(xù)執(zhí)行。

?

最后我們?cè)俅螐目傮w上瀏覽一下時(shí)鐘中斷:

每個(gè)時(shí)鐘滴答,時(shí)鐘中斷得到執(zhí)行。時(shí)鐘中斷執(zhí)行的頻率很高:100次/秒,時(shí)鐘中斷的主要工作是處理和時(shí)間有關(guān)的所有信息、決定是否執(zhí)行調(diào)度程序以及處理下半部分。和時(shí)間有關(guān)的所有信息包括系統(tǒng)時(shí)間、進(jìn)程的時(shí)間片、延時(shí)、使用CPU的時(shí)間、各種定時(shí)器,進(jìn)程更新后的時(shí)間片為進(jìn)程調(diào)度提供依據(jù),然后在時(shí)鐘中斷返回時(shí)決定是否要執(zhí)行調(diào)度程序。下半部分處理程序是Linux提供的一種機(jī)制,它使一部分工作推遲執(zhí)行。時(shí)鐘中斷要絕對(duì)保證維持系統(tǒng)時(shí)間的準(zhǔn)確性,而下半部分這種機(jī)制的提供不但保證了這種準(zhǔn)確性,還大幅提高了系統(tǒng)性能。

總結(jié)

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

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