新聞中心

EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > Linux內(nèi)核開(kāi)發(fā)之中斷與時(shí)鐘(一)

Linux內(nèi)核開(kāi)發(fā)之中斷與時(shí)鐘(一)

作者: 時(shí)間:2016-12-05 來(lái)源:網(wǎng)絡(luò) 收藏

  “小王,醒醒,開(kāi)始上課了,今天咱們開(kāi)始講,這可是高級(jí)東西,錯(cuò)過(guò)不補(bǔ)哈”我使勁推著睡夢(mèng)中的小王。

本文引用地址:http://2s4d.com/article/201612/341124.htm

  “嗯?感情好啊,快點(diǎn),快點(diǎn)”小王一聽(tīng)有新東西講,像打了雞血似的興奮,連我都懷疑起她是不是性格中喜新厭舊。

  不管那么多了,我講我的,她厭她的…

  啥叫?就是指cpu在執(zhí)行過(guò)程中,出現(xiàn)了某些突發(fā)事件時(shí)CPU必須暫停執(zhí)行當(dāng)前的程序,轉(zhuǎn)去處理突發(fā)事件,處理完畢后CPU有返回原程序被的位置并繼續(xù)執(zhí)行。

  中斷的分法不懂,分類(lèi)就不同,向什么內(nèi)外部中斷,可/不可屏蔽中斷…等等亂七八糟一大堆,我這里要說(shuō)明的一點(diǎn)是按照中斷入口跳轉(zhuǎn)方法的不同,可分為向量中斷和非向量中斷。采用向量中斷的CPU通常為不同的中斷分配不同的中斷號(hào),當(dāng)檢測(cè)到某中斷號(hào)的中斷到來(lái)后,就自動(dòng)跳轉(zhuǎn)到與該中斷號(hào)對(duì)應(yīng)的地址執(zhí)行。不同的中斷號(hào)有不同的中斷地址(即入口)。而非向量中斷的多個(gè)中斷共享一個(gè)入口地址。進(jìn)入后根據(jù)軟件判斷中斷標(biāo)志來(lái)識(shí)別具體是哪個(gè)中斷。也就是說(shuō),向量中斷是由硬件提供中斷服務(wù)程序入口地址,非向量中斷由軟件提供中斷服務(wù)程序入口地址。

  我們?cè)诤筮厱?huì)說(shuō)到一個(gè)時(shí)鐘定時(shí)器,它也是通過(guò)中斷來(lái)實(shí)現(xiàn)的。它的原理很簡(jiǎn)單,嵌入式微處理器它接入一個(gè)時(shí)鐘輸入,當(dāng)時(shí)鐘脈沖到來(lái)時(shí),就將目前的計(jì)數(shù)器值加1并和預(yù)先設(shè)置的計(jì)數(shù)值比較,若相等,證明計(jì)數(shù)周期滿(mǎn),產(chǎn)生定時(shí)器中斷并復(fù)位目前計(jì)數(shù)器值。

    

 

  中斷處理架構(gòu)

  設(shè)備的中斷會(huì)打斷內(nèi)核中進(jìn)程的正常調(diào)度和運(yùn)行,會(huì)影響系統(tǒng)的性能。為了在中斷執(zhí)行時(shí)間盡可能短和中斷處理需完成大量工作之間找到一個(gè)平衡點(diǎn),將中斷處理程序分解成兩個(gè)半部:頂半部和底半部。其中頂半部盡可能完成盡可能少的比較緊急的功能。而底半部幾乎做了中斷處理程序所有的事情,而且可以被新的中斷打斷。

  在linux設(shè)備驅(qū)動(dòng)中,提供了一系列函數(shù)來(lái)幫助設(shè)備實(shí)現(xiàn)中斷的相關(guān)操作:

  1)設(shè)備申請(qǐng)中斷

  int request_irq(unsigned int irq, //irq是要申請(qǐng)的中斷號(hào)

  void (*handler)(int irq, void *dev_id, struct pt_regs * *regs),//回調(diào)函數(shù),中斷發(fā)生時(shí),系統(tǒng)會(huì)調(diào)用該函數(shù),

  unsigned long irqflags,

  const char *devname,

  void *dev_id);

  其中irqflags是中斷處理的屬性,若設(shè)置為SA_INTERRUPT,則表示中斷處理程序是快速處理程序,它被調(diào)用時(shí)屏蔽所有中斷。若設(shè)置為SA_SHIRQ,則表示多個(gè)設(shè)備共享中斷,dev_id在中斷共享時(shí)會(huì)用到,一般設(shè)置為這個(gè)設(shè)備的設(shè)備結(jié)構(gòu)體或者NULL.

  該函數(shù)返回0表示成功,返回-INVAL表示中斷號(hào)無(wú)效或處理函數(shù)指針為NULL,返回EBUSY表示中斷已經(jīng)被占用且不能共享。

  2)釋放中斷

  free_irq(unsigned int irq, void *dev_id);

  3)使能和屏蔽中斷

  void disable_irq(int irq); //這個(gè)會(huì)立即返回

  void disable_irq_nosync(int irq);//等待目前的中斷處理完成再返回。

  void enable_irq(int irq);

  上述三個(gè)函數(shù)作用于可編程中斷處理器,因此對(duì)系統(tǒng)內(nèi)所有的CPU都生效。

  void local_irq_save(unsigned long flags);//會(huì)將目前的中斷狀態(tài)保留在flags中

  void local_irq_disable(void);//直接中斷

  這兩個(gè)將屏蔽本CPU內(nèi)的所有中斷。對(duì)應(yīng)的上邊兩個(gè)中斷的方法如下

  void local_irq_restore(unsigned long flags);

  void local_irq_enable(void);

  我們兩邊說(shuō)了系統(tǒng)中中斷是分為頂半部和底半部的,那么在系統(tǒng)實(shí)現(xiàn)方面是具體怎樣實(shí)現(xiàn)的呢,這主要有tasklet,工作隊(duì)列,軟中斷:

  1)tasklet:使用比較簡(jiǎn)單,如下:

  void my_tasklet_function(unsigned long); //定義一個(gè)處理函數(shù)

  DECLARE_TASKLET(my_tasklet, my_tasklet_function, data); //定義了一個(gè)名叫my_tasklet的tasklet并將其與處理函數(shù)綁定,而傳入?yún)?shù)為data

  在需要調(diào)度tasklet的時(shí)候引用一個(gè)tasklet_schedule()函數(shù)就能使系統(tǒng)在適當(dāng)?shù)臅r(shí)候進(jìn)行調(diào)度運(yùn)行:tasklet_schedule(&my_tasklet);

  2)工作隊(duì)列:使用方法和tasklet相似,如下:

  struct work_struct my_wq; //定義一個(gè)工作隊(duì)列

  void my_wq_func(unsigned long); //定義一個(gè)處理函數(shù)

  通過(guò)INIT_WORK()可以初始化這個(gè)工作隊(duì)列并將工作隊(duì)列與處理函數(shù)綁定,如下:

  INIT_WORK(&my_wq, (void (*)(void *))my_wq_func, NULL); //初始化工作隊(duì)列并將其與處理函數(shù)綁定

  同樣,使用schedule_work(&my_irq);來(lái)在系統(tǒng)在適當(dāng)?shù)臅r(shí)候需要調(diào)度時(shí)使用運(yùn)行。

  3)軟中斷:使用軟件方式模擬硬件中斷的概念,實(shí)現(xiàn)宏觀上的異步執(zhí)行效果,tasklet也是基于軟中斷實(shí)現(xiàn)的。

  在Linux內(nèi)核中,用softirq_action結(jié)構(gòu)體表征一個(gè)軟中斷,這個(gè)結(jié)構(gòu)體中包含軟中斷處理函數(shù)指針和傳遞給函數(shù)的參數(shù),使用open_softirq()可以注冊(cè)軟中斷對(duì)應(yīng)的處理函數(shù),而raise_softirq()函數(shù)可以觸發(fā)一個(gè)中斷。

  軟中斷和tasklet仍然運(yùn)行與中斷上下文,而工作隊(duì)列則運(yùn)行于進(jìn)程上下文。因此,軟中斷和tasklet的處理函數(shù)不能休眠,但工作隊(duì)列是可以的。

  local_bh_disable()和local_bh_enable()是內(nèi)核用于禁止和使能軟中斷和tasklet底半部機(jī)制的函數(shù)。

  下邊咱們?cè)賮?lái)說(shuō)說(shuō)有關(guān)中斷共享的相關(guān)點(diǎn):中斷共享即是多個(gè)設(shè)備共享一根硬件中斷線(xiàn)的情況。Linux2.6內(nèi)核支持中斷共享,使用方法如下:

  *共享中斷的多個(gè)設(shè)備在申請(qǐng)中斷時(shí)都應(yīng)該使用SA_SHIRQ標(biāo)志,而且一個(gè)設(shè)備以SA_SHIRQ申請(qǐng)某中斷成功的前提是之前該中斷的所有設(shè)備也都以SA_SHIRQ標(biāo)志申請(qǐng)?jiān)摻K端

  *盡管內(nèi)核模塊可訪(fǎng)問(wèn)的全局地址都可以作為request_irq(….,void *dev_id)的最后一個(gè)參數(shù)dev_id,但是設(shè)備結(jié)構(gòu)體指針是可傳入的最佳參數(shù)。

  *在中斷帶來(lái)時(shí),所有共享此中斷的中斷處理程序都會(huì)被執(zhí)行,在中斷處理程序頂半部中,應(yīng)迅速根據(jù)硬件寄存器中的信息比照傳入的dev_id參數(shù)判斷是否是被設(shè)備的中斷,如果不是,應(yīng)迅速返回。

  結(jié)語(yǔ):在這次講解中說(shuō)了三種Linux系統(tǒng)中中斷的頂/底半部機(jī)制和中斷共享的先關(guān)內(nèi)容,但礙于頁(yè)面空間的原因,沒(méi)有給出例子,我在下次博客中會(huì)專(zhuān)門(mén)來(lái)對(duì)每個(gè)點(diǎn)給出典型的模版.



關(guān)鍵詞: Linux 中斷

評(píng)論


相關(guān)推薦

技術(shù)專(zhuān)區(qū)

關(guān)閉