久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

內(nèi)核隨記(一)——理解中斷(3)

 clover_xian 2013-11-27
4,、下半部
在中斷處理過(guò)程中,,不能睡眠,。另外,,它運(yùn)行的時(shí)候,會(huì)把當(dāng)前中斷線在所有處理器上都屏蔽(在ack中完成屏蔽),;更糟糕的情況是,,如果一個(gè)處理程序是SA_INTERRUPT類型,它執(zhí)行的時(shí)候會(huì)禁上所有本地中斷(通過(guò)cli指令完成),,所以,,中斷處理應(yīng)該盡可能快的完成。所以Linux把中斷處理分為上半部和下半部,。
上半部由中斷處理程序完成,,它通常完成一些和硬件相關(guān)的操作,比如對(duì)中斷的到達(dá)的確認(rèn),。有時(shí)它還會(huì)從硬件拷貝數(shù)據(jù),,這些工作對(duì)時(shí)間非常敏感,只能靠中斷處理程序自己完成,。而把其它工作放到下半部實(shí)現(xiàn),。
下半部的執(zhí)行不需要一個(gè)確切的時(shí)間,它會(huì)在稍后系統(tǒng)不太繁忙時(shí)執(zhí)行,。下半部執(zhí)行的關(guān)鍵在于運(yùn)行的時(shí)候允許響應(yīng)所有的中斷,。最早,Linux用”bottom half”實(shí)現(xiàn)下半部,,這種機(jī)制簡(jiǎn)稱BH,但是即使屬于不同的處理器,,也不允許任何兩個(gè)bottom half同時(shí)執(zhí)行,,這種機(jī)制簡(jiǎn)單,但是卻有性能瓶頸,。不久,,又引入任務(wù)隊(duì)列(task queue)機(jī)制來(lái)實(shí)現(xiàn)下半部,但該機(jī)制仍不夠靈活,,沒(méi)法代替整個(gè)BH接口,。
從2.3開始,內(nèi)核引入軟中斷(softirqs)和tasklet,,并完全取代了BH,。2.5中,BH最終舍去,,在2.6中,,內(nèi)核用有三種機(jī)制實(shí)現(xiàn)下半部:軟中斷,tasklet和工作隊(duì)列,。Tasklet是基于軟中斷實(shí)現(xiàn)的,。軟中斷可以在多個(gè)CPU上同時(shí)執(zhí)行,,即使它們是同一類型的,所以,,軟中斷處理程序必須是可重入的,,或者顯示的用自旋鎖保護(hù)相應(yīng)的數(shù)據(jù)結(jié)構(gòu)。而相同的tasklet不能同時(shí)在多個(gè)CPU上執(zhí)行,,所以tasklet不必是可重入的,;但是,不同類型的tasklet可以在多個(gè)CPU上同時(shí)執(zhí)行,。一般來(lái)說(shuō),,tasklet比較常用,它可以處理絕大部分的問(wèn)題,;而軟中斷用得比較少,,但是對(duì)于時(shí)間要求較高的地方,比如網(wǎng)絡(luò)子系統(tǒng),,常用軟中斷處理下半部工作,。

4.1、軟中斷
內(nèi)核2.6中定義了6種軟中斷:

下標(biāo)越低,,優(yōu)先級(jí)越高,。

4.1.1、數(shù)據(jù)結(jié)構(gòu)
(1)軟中斷向量
復(fù)制代碼
//linux/interrupt.h
struct softirq_action
{
    void    (*action)(struct softirq_action *); //待執(zhí)行的函數(shù)
    void    *data;  //傳給函數(shù)的參數(shù)
};
//kernel/softirq.c
//軟中斷向量數(shù)組
static struct softirq_action softirq_vec[32] __cacheline_aligned_in_smp;
復(fù)制代碼
內(nèi)核定義了一個(gè)包含32個(gè)軟中斷向量的數(shù)組,,所以最多可有32個(gè)軟中斷,,實(shí)際上,內(nèi)核目前只使用了6個(gè)軟中斷,。
(2)    preempt_count字段
位于任務(wù)描述符的preempt_count是用來(lái)跟蹤內(nèi)核搶占和內(nèi)核控制路徑嵌套關(guān)鍵數(shù)據(jù),。其各個(gè)位的含義如下:
位            描述
0——7    preemption counter,內(nèi)核搶占計(jì)數(shù)器(最大值255)
8——15   softirq counter,,軟中斷計(jì)數(shù)器(最大值255)
16——27  hardirq counter,,硬件中斷計(jì)數(shù)器(最大值4096)
28        PREEMPT_ACTIVE標(biāo)志

第一個(gè)計(jì)數(shù)用來(lái)表示內(nèi)核搶占被關(guān)閉的次數(shù),0表示可以搶占,。第二個(gè)計(jì)數(shù)器表示推遲函數(shù)(下半部)被關(guān)閉的次數(shù),,0表示推遲函數(shù)打開。第三個(gè)計(jì)數(shù)器表示本地CPU中斷嵌套的層數(shù),,irq_enter()增加該值,,irq_exit減該值。
宏in_interrupt()檢查current_thread_info->preempt_count的hardirq和softirq來(lái)斷定是否處于中斷上下文,。如果這兩個(gè)計(jì)數(shù)器之一為正,,則返回非零。
(3) 軟中斷控制/狀態(tài)結(jié)構(gòu)
softirq_vec是個(gè)全局量,系統(tǒng)中每個(gè)CPU所看到的是同一個(gè)數(shù)組,。但是,,每個(gè)CPU各有其自己的“軟中斷控制/狀態(tài)”結(jié)構(gòu),這些數(shù)據(jù)結(jié)構(gòu)形成一個(gè)以CPU編號(hào)為下標(biāo)的數(shù)組irq_stat[](定義在include/asm-i386/hardirq.h中)
復(fù)制代碼
typedef struct {
    unsigned int __softirq_pending;
    unsigned long idle_timestamp;
    unsigned int __nmi_count;    /* arch dependent */
    unsigned int apic_timer_irqs;    /* arch dependent */
} ____cacheline_aligned irq_cpustat_t;
//位于kernel/softirq.c
irq_cpustat_t irq_stat[NR_CPUS] ____cacheline_aligned;
復(fù)制代碼
4.1.2,、軟中斷初始化
可以通過(guò)open_softirq注冊(cè)軟中斷處理程序:
復(fù)制代碼
//位于kernel/softirq.c
//nr:軟中斷的索引號(hào)
// softirq_action:處理函數(shù)
//data:傳遞給處理函數(shù)的參數(shù)值
void open_softirq(int nr, void (*action)(struct softirq_action*), void *data)
{
    softirq_vec[nr].data = data;
    softirq_vec[nr].action = action;
}
//軟中斷初始化
void __init softirq_init(void)
{
    open_softirq(TASKLET_SOFTIRQ, tasklet_action, NULL);
    open_softirq(HI_SOFTIRQ, tasklet_hi_action, NULL);
}
復(fù)制代碼
軟中斷執(zhí)行時(shí),,允許響應(yīng)中斷,但它自己不能睡眠,,
4.1.3,、觸發(fā)軟中斷
raise_softirq會(huì)將軟中斷設(shè)置為掛起狀態(tài),并在下一次運(yùn)行do_softirq中投入運(yùn)行,。
復(fù)制代碼
//位于kernel/softirq.c
void fastcall raise_softirq(unsigned int nr)
{
    unsigned long flags;
    //保存IF值,并關(guān)中斷
    local_irq_save(flags);
    
    //調(diào)用wakeup_softirqd()
    raise_softirq_irqoff(nr);
    //恢復(fù)IF值
    local_irq_restore(flags);
}

inline fastcall void raise_softirq_irqoff(unsigned int nr)
{
    //把軟中斷設(shè)置為掛起狀態(tài)
    __raise_softirq_irqoff(nr);

    
     //喚醒內(nèi)核線程
    if (!in_interrupt())
        wakeup_softirqd();
}
復(fù)制代碼
該函數(shù)觸發(fā)軟中斷前,,先要關(guān)閉中斷,之后再恢復(fù),;如果之前中斷已經(jīng)關(guān)閉,,可以直接調(diào)用raise_softirq_irqoff()觸發(fā)軟中斷。
在中斷服務(wù)例程中觸發(fā)軟中斷是最常見(jiàn)的形式,。而中斷服務(wù)例程通常作為設(shè)備驅(qū)動(dòng)的一部分,。例如,對(duì)于網(wǎng)絡(luò)設(shè)備,,當(dāng)接口收到數(shù)據(jù)時(shí),,會(huì)產(chǎn)生一個(gè)中斷,在中斷服務(wù)例程中,,最終會(huì)調(diào)用netif_rx函數(shù)處理接到的數(shù)據(jù),,而netif_rx作相應(yīng)處理,最終以觸發(fā)一個(gè)軟中斷結(jié)束處理,。之后,,內(nèi)核在執(zhí)行中斷處理任務(wù)后,會(huì)調(diào)用do_softirq(),。于是軟中斷就通過(guò)軟中斷處理函數(shù)去處理留給它的任務(wù)。
4.1.4,、軟中斷執(zhí)行
(1) do_softirq()函數(shù)
復(fù)制代碼
//處理軟中斷,,位于arch/i386/kernel/irq.c
asmlinkage void do_softirq(void)
{
    //處于中斷上下文,表明軟中斷是在中斷上下文中觸發(fā)的,或者軟中斷被關(guān)閉
    /*這個(gè)宏限制了軟中斷服務(wù)例程既不能在一個(gè)硬中斷服務(wù)例程內(nèi)部執(zhí)行,
    *也不能在一個(gè)軟中斷服務(wù)例程內(nèi)部執(zhí)行(即嵌套),。但這個(gè)函數(shù)并沒(méi)有對(duì)中斷服務(wù)例程的執(zhí)行
    *進(jìn)行“串行化”限制,。這也就是說(shuō),不同的CPU可以同時(shí)進(jìn)入對(duì)軟中斷服務(wù)例程的執(zhí)行,,每個(gè)CPU
    *分別執(zhí)行各自所請(qǐng)求的軟中斷服務(wù),。從這個(gè)意義上說(shuō),軟中斷服務(wù)例程的執(zhí)行是“并發(fā)的”、多序的,。
    *但是,,這些軟中斷服務(wù)例程的設(shè)計(jì)和實(shí)現(xiàn)必須十分小心,不能讓它們相互干擾(例如通過(guò)共享的全局變量),。
    
*/
    if (in_interrupt())
        return;
    //保存IF值,并關(guān)中斷
    local_irq_save(flags);
//調(diào)用__do_softirq
        asm volatile(
            "       xchgl   %%ebx,%%esp     \n"
            "       call    __do_softirq    \n"
            "       movl    %%ebx,%%esp     \n"
            : "=b"(isp)
            : "0"(isp)
            : "memory""cc""edx""ecx""eax"
        );
    //恢復(fù)IF值
    local_irq_restore(flags);
復(fù)制代碼
(2)__do_softirq()函數(shù)
復(fù)制代碼
//執(zhí)行軟中斷,位于kernel/softirq.c
asmlinkage void __do_softirq(void)
{
    struct softirq_action *h;
    __u32 pending;
    /*最多迭代執(zhí)行10次.在執(zhí)行軟中斷的過(guò)程中,由于允許中斷,所以新的軟中斷可能產(chǎn)生.為了使推遲函數(shù)能夠在
    *較短的時(shí)間延遲內(nèi)執(zhí)行,__do_softirq會(huì)執(zhí)行所有掛起的軟中斷,這可能會(huì)執(zhí)行太長(zhǎng)的時(shí)間而大大延遲返回用戶
    *空間的時(shí)間.所以,__do_softirq最多允許10次迭代.剩下的軟中斷在軟中斷內(nèi)核線程ksoftirqd中處理.
    
*/
    int max_restart = MAX_SOFTIRQ_RESTART;
    int cpu;
    
    //用局部變量保存軟件中斷位圖
    pending = local_softirq_pending();
    /*增加softirq計(jì)數(shù)器的值.由于執(zhí)行軟中斷時(shí)允許中斷,當(dāng)do_IRQ調(diào)用irq_exit時(shí),另一個(gè)__do_softirq實(shí)例可能
    *開始執(zhí)行.這是不允許的,推遲函數(shù)必須在CPU上串行執(zhí)行.
    
*/
    local_bh_disable();
    cpu = smp_processor_id();
restart:
    /* Reset the pending bitmask before enabling irqs */
    //重置軟中斷位圖,使得新的軟中斷可以發(fā)生
    local_softirq_pending() = 0;
    //開啟本地中斷,執(zhí)行軟中斷時(shí),允許中斷的發(fā)生
    local_irq_enable();

    h = softirq_vec;

    do {
        if (pending & 1) {
            //執(zhí)行軟中斷處理函數(shù)
            h->action(h);
            rcu_bh_qsctr_inc(cpu);
        }
        h++;
        pending >>= 1;
    } while (pending);
       //關(guān)閉中斷
    local_irq_disable();
    //再一次檢查軟中斷位圖,因?yàn)樵趫?zhí)行軟中斷處理函數(shù)時(shí),新的軟中斷可能產(chǎn)生.
    pending = local_softirq_pending();
    if (pending && --max_restart)
        goto restart;
    /*如果還有多的軟中斷沒(méi)有處理,通過(guò)wakeup_softirqd喚醒內(nèi)核線程處理本地CPU余下的軟中斷.
    
*/
    if (pending)
        wakeup_softirqd();
    //減softirq counter的值
    __local_bh_enable();
}
復(fù)制代碼
(3)軟中斷執(zhí)行點(diǎn)
內(nèi)核會(huì)周期性的檢查是否有掛起的軟中斷,,它們位于內(nèi)核代碼的以下幾個(gè)點(diǎn):
(1)內(nèi)核調(diào)用local_bh_enable()函數(shù)打開本地CPU的軟中斷:
復(fù)制代碼
//位于kernel/softirq.c
void local_bh_enable(void)
{
    preempt_count() -= SOFTIRQ_OFFSET - 1;

    if (unlikely(!in_interrupt() && local_softirq_pending()))
        do_softirq(); //軟中斷處理
    
//……
}
復(fù)制代碼
(2)do_IRQ函數(shù)完成I/O中斷處理,調(diào)用irq_exit()時(shí),。
(3)內(nèi)核線程ksoftirqd被喚醒,。
(4) smp_apic_timer_interrupt()完成處理本地時(shí)鐘中斷。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購(gòu)買等信息,,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請(qǐng)點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多