亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費(fèi)注冊(cè) 查看新帖 |

Chinaunix

  平臺(tái) 論壇 博客 文庫(kù)
最近訪問(wèn)板塊 發(fā)新帖
查看: 4490 | 回復(fù): 2
打印 上一主題 下一主題

Linux中斷處理過(guò)程淺析 [復(fù)制鏈接]

論壇徽章:
0
跳轉(zhuǎn)到指定樓層
1 [收藏(0)] [報(bào)告]
發(fā)表于 2009-03-30 22:37 |只看該作者 |倒序?yàn)g覽
最近在看Linux中斷處理的過(guò)程,寫了以下幾點(diǎn)體會(huì),忘高手給予指點(diǎn),以便我去補(bǔ)充,使得這個(gè)知識(shí)點(diǎn)對(duì)于自己更加完整。

    首先看一下中斷發(fā)生時(shí)硬件和軟件的大致處理過(guò)程,然后再來(lái)對(duì)每一步做稍微詳細(xì)的介紹。
    1.當(dāng)中斷發(fā)生時(shí),cpu control unit會(huì)截獲這一事件,并做一些基本的保留,同時(shí)disable local interrupt,表示不再響應(yīng)中斷。這里涉及到control unit保存的內(nèi)容和來(lái)讀取相應(yīng)idt、gdt的內(nèi)容來(lái)驗(yàn)證中斷源的合法性和interrupt handler的指令地址,接下來(lái)執(zhí)行的第一條軟件指令便是interrupt handler。
    2.Interrupt handler的首要?jiǎng)幼鞅闶莝ave all,保存一切有可能會(huì)被中斷處理程序用到的寄存器值,然后執(zhí)行函數(shù)do_irq,do_irq調(diào)用irq_enter增加preemt_count的Hardirq counter數(shù)值。做一些與8k內(nèi)核堆棧相關(guān)的動(dòng)作,然后調(diào)用__do_irq。
    3.__do_irq的首要任務(wù)便是acknowledge apic并且mask掉產(chǎn)生中斷的線,使得該線在中斷處理完成之前不再接收再次中斷。此時(shí)local interrupt也是disable的(由1中的control unit關(guān)閉),接下來(lái)調(diào)用isr。
    4.在執(zhí)行isr之前,首先根據(jù)該isr的要求,開啟或關(guān)閉local interrupt,一般都是開啟local interrupt,然后依次調(diào)用isr。除非注冊(cè)isr(request_irq)的時(shí)候特別用flag指明必須local interrupt disable,否則一般的isr都是運(yùn)行在產(chǎn)生中斷的那根線disable掉和local interrupt enable的情況下,執(zhí)行完成之后并關(guān)閉local interrupt。
    5.退到上層的__do_irq,該函數(shù)會(huì)調(diào)用pic的end函數(shù),使得對(duì)應(yīng)那根線(irq line)的中斷開啟。
    6.退到上層的do_irq,此時(shí)會(huì)調(diào)用irq_exit,在irq_exit中首先減少preemt_count中的Hardirq counter,然后調(diào)用了softirq.可知softirq是運(yùn)行在全部的中斷線和local interrupt enable的情況下,意味著此時(shí)內(nèi)核已經(jīng)可以再次響應(yīng)同樣的中斷。
    7.完成之后。。。。。。。。。。。。。調(diào)用iret指令。
    8.iret指令使得control unit恢復(fù)先前保存的所有東西,enable local interrupt。
   上述第一點(diǎn)中,中斷源的合法性比較重要,那么硬件上有哪些機(jī)制保證了該中斷源的合法性呢?要了解此我們先來(lái)看一下當(dāng)中斷發(fā)生時(shí),control unit做了哪些動(dòng)作。首先它會(huì)根據(jù)中斷源和idtr一起來(lái)找到相應(yīng)的idt中的某個(gè)entry,并從該entry當(dāng)中取出segment seletor,由此seletor再加上gdtr寄存器,就可以找到該interrupt handler的segment descriptor,由于該segment descriptor當(dāng)中有個(gè)DPL,它表示了中斷處理程序應(yīng)該在哪個(gè)級(jí)別下運(yùn)行,一般都是在0的level即kernel態(tài)下運(yùn)行interrupt handler。因此如果發(fā)現(xiàn)當(dāng)前進(jìn)程的cs中的低兩位數(shù)值比中斷處理程序的DPL還。〝(shù)值越小,level也高,kernel的數(shù)值為0),那么就直接出現(xiàn)異常,因?yàn)椴豢赡軙?huì)有某個(gè)進(jìn)程它的運(yùn)行級(jí)別會(huì)被interrupt handler還低。經(jīng)過(guò)這部確認(rèn)之后,cs和eip分別被賦值成IDT當(dāng)中的segment selector和offset,做完這一步意味著下一個(gè)執(zhí)行的指令便是interrupt handler中的指令了。

    第二步當(dāng)中的interrupt handler的整條命令如下:
pushl $n-256
jmp common_interrupt
common_interrupt:
SAVE_ALL
movl %esp,%eax
call do_IRQ
jmp ret_from_intr
       其實(shí)存在于idt的地址指向的指令便是上述的前兩條語(yǔ)句,接下來(lái)就是統(tǒng)一地保存所有cpu的寄存器,以免丟失。然后就調(diào)用函數(shù)do_IRQ來(lái)執(zhí)行。 do_IRQ如上述所說(shuō),它基本就是增加硬中斷的數(shù)值,然后直接調(diào)用__do_irq,__do_irq基本會(huì)通知中斷控制器已經(jīng)收到中斷信號(hào),告訴它將中斷線的信號(hào)取消,一般此時(shí)會(huì)中斷控制器會(huì)mask掉該跳線的中斷。接下來(lái)__do_irq會(huì)調(diào)用ISR也即驅(qū)動(dòng)程序利用函數(shù) request_irq函數(shù)注冊(cè)進(jìn)去的中斷處理歷程。一般來(lái)說(shuō),在執(zhí)行中斷處理歷程的時(shí)候,kernel會(huì)根據(jù)driver傳進(jìn)來(lái)的flag決定是否開啟 local的中斷,一般來(lái)說(shuō)都是開啟的,但是這里需要我們注意的是對(duì)于8259A這個(gè)中斷控制芯片來(lái)說(shuō),此時(shí)盡管cpu local的中斷是enabled,但是8259A上產(chǎn)生中斷的哪條線還是disable的,意味著這條線上的中斷不會(huì)被硬件覺(jué)察到。對(duì)于intel IO apic還沒(méi)有研究過(guò)。由此可以看出,一般driver的中斷處理歷程都是運(yùn)行l(wèi)ocal interrupt enable的情況下進(jìn)行的,因此會(huì)產(chǎn)生中斷嵌套之說(shuō)。當(dāng)__do_irq執(zhí)行完ISR之后,并enable8259A上的哪條中斷線,意味著將接收該線上產(chǎn)生的中斷。到此,__do_irq算基本完成,退到上層函數(shù)do_irq,do_irq會(huì)執(zhí)行irq_exit,在該函數(shù)中會(huì)減掉由 irq_enter增加的硬中斷數(shù)值,接下來(lái)就判斷是否是中斷context,即如果函數(shù)in_interrupt返回false,且有pending 的軟中斷,那么就去執(zhí)行軟中斷,即中斷的底半步。關(guān)于linux中斷的上半步和底半步就不詳細(xì)說(shuō)明了,這里只說(shuō)明整個(gè)流程是怎么走的。
     kernel在系統(tǒng)初始化的時(shí)候注冊(cè)了6個(gè)不同的softirq,分別為HI_SOFTIRQ,TIMER_SOFTIRQ(內(nèi)核定時(shí)器的實(shí)現(xiàn)就是依賴這個(gè)softirq),NET_TX_SOFTIRQ,NET_RX_SOFTIRQ,BLOCK_SOFTIRQ,TASKLET_SOFTIRQ(tasklet的實(shí)現(xiàn)就是依賴于這個(gè)softirq),SCHED_SOFTIRQ,RCU_SOFTIRQ。。。。。當(dāng)中斷處理程序執(zhí)行到irq_exit函數(shù),在該函數(shù)中調(diào)用invoke_softirq即__do_softirq,正是在這個(gè)函數(shù)里,kernel對(duì)每個(gè)有pending的softirq執(zhí)行起其相應(yīng)的函數(shù)。那么哪個(gè)softirq pending是誰(shuí)來(lái)設(shè)置的呢?可以參考函數(shù)raise_softirq_irqoff,這個(gè)函數(shù)傳進(jìn)來(lái)的參數(shù)就是上述6個(gè)softirq的值。softirq會(huì)在每次中斷返回時(shí)會(huì)被檢查是否要調(diào)用,到真正執(zhí)行softirq的各個(gè)函數(shù)時(shí),in_interrupt()值一定不為真。(由于softirq不能嵌套執(zhí)行,因此它在執(zhí)行之前會(huì)local_bh_disable來(lái)提升preemt_count的softirq counter值,使得下次softirq在in_interrupt()的時(shí)候直接返回。那么在什么情況下會(huì)發(fā)生softirq的中斷嵌套呢?因?yàn)閟oftirq的時(shí)候所有中斷都是打開的,因此有可能新的interrupt handler里面又注冊(cè)了這個(gè)softirq,等到嵌套的中斷退出時(shí)(此時(shí)preemt_count中的hardirq counter 為0,請(qǐng)參考do_irq分析),又會(huì)調(diào)到softirq,此時(shí)就實(shí)現(xiàn)了softirq的中斷嵌套。
     這里將tasklet(即軟中斷中的一種)做個(gè)簡(jiǎn)單的解析,使用過(guò)tasklet來(lái)幫助我們driver中的實(shí)現(xiàn)中斷底半步的兄弟都知道,一般我們都是通過(guò)如下兩個(gè)步驟來(lái)實(shí)現(xiàn):
tasklet_init
tasklet_schedule。
我們來(lái)看看上述兩個(gè)函數(shù)的代碼實(shí)現(xiàn):
void tasklet_init(struct tasklet_struct *t,
                  void (*func)(unsigned long), unsigned long data)
{
        t->next = NULL;
        t->state = 0;
        atomic_set(&t->count, 0);
        t->func = func;
        t->data = data;
}
tasklet_init很簡(jiǎn)單,它只是將一個(gè)tasklet_struct賦值成想要的函數(shù)和參數(shù),為該tasklet被運(yùn)行做了一些初始化工作。
再來(lái)看
static inline void tasklet_schedule(struct tasklet_struct *t)
{
        if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state))
                __tasklet_schedule(t);
}
void __tasklet_schedule(struct tasklet_struct *t)
{
        unsigned long flags;

        local_irq_save(flags);
        t->next = NULL;
        *__get_cpu_var(tasklet_vec).tail = t;
        __get_cpu_var(tasklet_vec).tail = &(t->next);
        raise_softirq_irqoff(TASKLET_SOFTIRQ);
        local_irq_restore(flags);
}
inline void raise_softirq_irqoff(unsigned int nr)
{
        __raise_softirq_irqoff(nr);

        /*
         * If we're in an interrupt or softirq, we're done
         * (this also catches softirq-disabled code). We will
         * actually run the softirq once we return from
         * the irq or softirq.
         *
         * Otherwise we wake up ksoftirqd to make sure we
         * schedule the softirq soon.
         */
        if (!in_interrupt())
                wakeup_softirqd();
}
#define __raise_softirq_irqoff(nr) do { or_softirq_pending(1UL << (nr)); } while (0)
由紅色的代碼我們可以看到函數(shù)tasklet_schedule只是將每個(gè)cpu對(duì)應(yīng)的關(guān)于軟中斷的變量的那個(gè)關(guān)于tasklet的bit置成1,就結(jié)束了。
到此為止,我們?cè)倩叵氘?dāng)中斷處理程序完成之后,它會(huì)根據(jù)當(dāng)前是否有pending的softirq,此時(shí)有,因此函數(shù)tasklet_action就會(huì)被調(diào)用,原因是內(nèi)核初始化的時(shí)候有這么一條語(yǔ)句:open_softirq(TASKLET_SOFTIRQ, tasklet_action);。再看函數(shù)tasklet_action:
static void tasklet_action(struct softirq_action *a)
{
        struct tasklet_struct *list;

        local_irq_disable();
        list = __get_cpu_var(tasklet_vec).head;
        __get_cpu_var(tasklet_vec).head = NULL;
        __get_cpu_var(tasklet_vec).tail = &__get_cpu_var(tasklet_vec).head;
        local_irq_enable();

        while (list) {
                struct tasklet_struct *t = list;

                list = list->next;

                if (tasklet_trylock(t)) {
                        if (!atomic_read(&t->count)) {
                                if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state))
                                        BUG();
                                t->func(t->data);
                                tasklet_unlock(t);
                                continue;
                        }
                        tasklet_unlock(t);
                }

                local_irq_disable();
                t->next = NULL;
                *__get_cpu_var(tasklet_vec).tail = t;
                __get_cpu_var(tasklet_vec).tail = &(t->next);
                __raise_softirq_irqoff(TASKLET_SOFTIRQ);
                local_irq_enable();
        }
}
紅色的代碼就是我們通過(guò)函數(shù)tasklet_init注冊(cè)進(jìn)去的函數(shù)。

以此類推,我們可以找到kernel timer的實(shí)現(xiàn)原理和其他一些軟中斷的執(zhí)行過(guò)程。

論壇徽章:
3
金牛座
日期:2014-06-14 22:04:062015年辭舊歲徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:49:45
2 [報(bào)告]
發(fā)表于 2009-03-31 12:19 |只看該作者
寫得不錯(cuò),你可以對(duì)照一下情景分析,呵呵

論壇徽章:
0
3 [報(bào)告]
發(fā)表于 2009-03-31 12:22 |只看該作者

回復(fù) #2 dreamice 的帖子

是不是情景分析描述地更詳細(xì)一些。
我要去好好仰慕一下。
您需要登錄后才可以回帖 登錄 | 注冊(cè)

本版積分規(guī)則 發(fā)表回復(fù)

  

北京盛拓優(yōu)訊信息技術(shù)有限公司. 版權(quán)所有 京ICP備16024965號(hào)-6 北京市公安局海淀分局網(wǎng)監(jiān)中心備案編號(hào):11010802020122 niuxiaotong@pcpop.com 17352615567
未成年舉報(bào)專區(qū)
中國(guó)互聯(lián)網(wǎng)協(xié)會(huì)會(huì)員  聯(lián)系我們:huangweiwei@itpub.net
感謝所有關(guān)心和支持過(guò)ChinaUnix的朋友們 轉(zhuǎn)載本站內(nèi)容請(qǐng)注明原作者名及出處

清除 Cookies - ChinaUnix - Archiver - WAP - TOP