• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            那誰的技術(shù)博客

            感興趣領(lǐng)域:高性能服務(wù)器編程,存儲,算法,Linux內(nèi)核
            隨筆 - 210, 文章 - 0, 評論 - 1183, 引用 - 0
            數(shù)據(jù)加載中……

            linux內(nèi)核V2.6.11學(xué)習(xí)筆記(6)--中斷處理

            每個中斷處理的函數(shù)存放在entry.S中的interrupt數(shù)組中,該數(shù)組有NR_IRQS個元素.
            每個元素做的工作有:
            ENTRY(irq_entries_start)
            .rept NR_IRQS
                ALIGN
            1:    pushl $vector-256
                jmp common_interrupt
            .data
                .
            long 1b
            .text
            vector
            =vector+1
            .endr

                ALIGN
            common_interrupt:
                SAVE_ALL
                movl 
            %esp,%eax
                call do_IRQ
                jmp ret_from_intr

            首先將中斷向量- 256保存在棧中
            其中的SAVE_ALL做的工作包括:
            #define SAVE_ALL \
                cld; \
                pushl 
            %es; \
                pushl 
            %ds; \
                pushl 
            %eax; \
                pushl 
            %ebp; \
                pushl 
            %edi; \
                pushl 
            %esi; \
                pushl 
            %edx; \
                pushl 
            %ecx; \
                pushl 
            %ebx; \
                movl $(__USER_DS), 
            %edx; \
                movl 
            %edx, %ds; \
                movl 
            %edx, %es;

            也就是保存一些寄存器, 然后調(diào)用do_IRQ函數(shù):

            do_IRQ函數(shù)首先調(diào)用irq_enter()函數(shù):
            #define irq_enter()                    \
                
            do {                        \
                    account_system_vtime(current);        \
                    add_preempt_count(HARDIRQ_OFFSET);    \
                } 
            while (0)

            其中要注意的是函數(shù)add_preempt_count, 它改變的是當(dāng)前進程中thread_info中的成員preempt_count,它是一個32位的字段,分為幾個部分,:
            0-7位: 搶占計數(shù)器, 最大值255
            8-15位: 軟中斷計數(shù)器, 最大值255
            16-27位: 硬中斷計數(shù)器, 最大值4096
            28位: PREEMPT_ACTIVE標志

            因此,在hardirq.h中定義了幾個宏:
            #define PREEMPT_BITS    8
            #define SOFTIRQ_BITS    8
            #define HARDIRQ_BITS    12

            #define PREEMPT_SHIFT    0
            #define SOFTIRQ_SHIFT    (PREEMPT_SHIFT + PREEMPT_BITS)
            #define HARDIRQ_SHIFT    (SOFTIRQ_SHIFT + SOFTIRQ_BITS)

            #define PREEMPT_OFFSET    (1UL << PREEMPT_SHIFT)
            #define SOFTIRQ_OFFSET    (1UL << SOFTIRQ_SHIFT)
            #define HARDIRQ_OFFSET    (1UL << HARDIRQ_SHIFT)

            因此, 函數(shù)調(diào)用add_preempt_count(HARDIRQ_OFFSET)是增加其中硬中斷的計數(shù).

            回到do_IRQ函數(shù)調(diào)用中,接下來:
            #ifdef CONFIG_4KSTACKS

                curctx 
            = (union irq_ctx *) current_thread_info();
                irqctx 
            = hardirq_ctx[smp_processor_id()];

                
            /*
                 * this is where we switch to the IRQ stack. However, if we are
                 * already using the IRQ stack (because we interrupted a hardirq
                 * handler) we can't do that and just have to keep using the
                 * current stack (which is the irq stack already after all)
                 
            */
                
            if (curctx != irqctx) {
                    
            int arg1, arg2, ebx;

                    
            /* build the stack frame on the IRQ stack */
                    isp 
            = (u32*) ((char*)irqctx + sizeof(*irqctx));
                    irqctx
            ->tinfo.task = curctx->tinfo.task;
                    irqctx
            ->tinfo.previous_esp = current_stack_pointer;

                    asm 
            volatile(
                        
            "       xchgl   %%ebx,%%esp      \n"
                        
            "       call    __do_IRQ         \n"
                        
            "       movl   %%ebx,%%esp      \n"
                        : 
            "=a" (arg1), "=d" (arg2), "=b" (ebx)
                        :  
            "0" (irq),   "1" (regs),  "2" (isp)
                        : 
            "memory""cc""ecx"
                    );
                } 
            else
            #endif

            這段代碼僅在線程棧大小是4K的情況下被調(diào)用, 有一個名為hardirq_ctx的數(shù)組保存硬中斷的請求棧,它的定義是:
            union irq_ctx {
                
            struct thread_info      tinfo;
                u32                     stack[THREAD_SIZE
            /sizeof(u32)];
            };

            static union irq_ctx *hardirq_ctx[NR_CPUS];
            static union irq_ctx *softirq_ctx[NR_CPUS];
            也就是說, 這兩個數(shù)組的元素數(shù)量由CPU數(shù)量來決定.
            在系統(tǒng)初始化的時候, 調(diào)用函數(shù)irq_ctx_init, 分別把這兩個數(shù)組中的元素(irq_ctx *類型指針)指向hardirq_stack和softirq_stack:
            static char softirq_stack[NR_CPUS * THREAD_SIZE]
                    __attribute__((__aligned__(THREAD_SIZE)));

            static char hardirq_stack[NR_CPUS * THREAD_SIZE]
                    __attribute__((__aligned__(THREAD_SIZE)));
            因此, 上面的那段do_IRQ函數(shù)中的代碼做的工作比較當(dāng)前thread_info描述符地址(通過調(diào)用current_thread_info()函數(shù))與hardirq_ctx
            的內(nèi)容, 如果相同, 說明內(nèi)核已經(jīng)在使用硬件中斷請求棧了, 否則如果不相等那么就要切換內(nèi)核棧,需要保存當(dāng)前進程描述符指針和esp寄存器.

            接著, do_IRQ函數(shù)調(diào)用__do_IRQ函數(shù),這個函數(shù)的主要工作有:
            // 加鎖
            spin_lock(&(irq_desc[irq].lock));
            // 響應(yīng)
            irq_desc[irq].handler->ack(irq);

            // 當(dāng)前狀態(tài)既不是IRQ_REPLAY:The IRQ line has been disabled but the previous IRQ occurrence has not yet been acknowledged to the PIC
            // 也不是IRQ_WAITING:The kernel is using the IRQ line while performing a hardware device probe; moreover, the corresponding interrupt has not been raised
            irq_desc[irq].status &= ~(IRQ_REPLAY | IRQ_WAITING);

            // 當(dāng)前狀態(tài)為IRQ_PENDING:An IRQ has occurred on the line; its occurrence has been acknowledged to the PIC, but it has not yet been serviced by the kernel
            irq_desc[irq].status |= IRQ_PENDING;

            if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)) // 如果當(dāng)前狀態(tài)不是IRQ_DISABLED 或者 IRQ_INPROGRESS
                        && irq_desc[irq].action) {                            // action指針有效
                    irq_desc[irq].status |= IRQ_INPROGRESS;                    // 設(shè)置當(dāng)前當(dāng)前狀態(tài)為IRQ_INPROGRESS: A handler for the IRQ is being executed
                    do {
                        irq_desc[irq].status 
            &= ~IRQ_PENDING;                // 設(shè)置當(dāng)前當(dāng)前狀態(tài)不是IRQ_PENDING,因為下面要開始處理了
                        spin_unlock(&(irq_desc[irq].lock));
                        handle_IRQ_event(irq, regs, irq_desc[irq].action);    
            // 處理事件
                        spin_lock(&(irq_desc[irq].lock));
                    } 
            while (irq_desc[irq].status & IRQ_PENDING);            // 如果當(dāng)前狀態(tài)還是IRQ_PENDING循環(huán)繼續(xù)
                    irq_desc[irq].status &= ~IRQ_INPROGRESS;                // 設(shè)置當(dāng)前狀態(tài)不是IRQ_INPROGRESS
            }

            irq_desc[irq].handler
            ->end(irq);
            spin_unlock(
            &(irq_desc[irq].lock));

            在循環(huán)處理IRQ請求的時候, 最開始要設(shè)置狀態(tài)為 IRQ_INPROGRESS同時不是IRQ_PENDING, 這個循環(huán)處理IRQ請求的過程在當(dāng)前狀態(tài)是IRQ_PENDING則一直進行下去,
            當(dāng)該循環(huán)處理完畢之后, 再將狀態(tài)設(shè)置為IRQ_INPROGRESS.

            在從__do_IRQ函數(shù)返回后, 調(diào)用irq_exit函數(shù):
            void irq_exit(void)
            {
                account_system_vtime(current);
                sub_preempt_count(IRQ_EXIT_OFFSET);
                
            if (!in_interrupt() && local_softirq_pending())
                    invoke_softirq();
                preempt_enable_no_resched();
            }

            該函數(shù)首先調(diào)用sub_preempt_count減少搶占計數(shù), 然后如果當(dāng)前不在中斷狀態(tài)以及當(dāng)前有未處理的軟中斷(softirq)則調(diào)用invoke_softirq函數(shù)(其實就是do_softirq函數(shù))
            處理軟中斷,最后調(diào)用preempt_enable_no_resched允許內(nèi)核搶占.

            posted on 2009-05-03 16:09 那誰 閱讀(4703) 評論(1)  編輯 收藏 引用 所屬分類: linux kernel

            評論

            # re: linux內(nèi)核V2.6.11學(xué)習(xí)筆記(6)--中斷處理  回復(fù)  更多評論   

            好底層哦 呵呵
            2010-01-02 09:05 | 忘憂三毛
            精品久久久久久无码人妻热 | 久久综合给合久久狠狠狠97色| 久久免费美女视频| 久久精品99久久香蕉国产色戒| 久久久久久国产精品无码下载| 久久乐国产综合亚洲精品| 久久成人精品| 亚洲欧洲精品成人久久奇米网| 日本精品久久久久影院日本| 久久国产AVJUST麻豆| 丁香色欲久久久久久综合网| 麻豆成人久久精品二区三区免费 | 久久久WWW免费人成精品| 久久九九久精品国产免费直播| 日本久久中文字幕| 亚洲人成网亚洲欧洲无码久久| 日本久久久久亚洲中字幕 | 久久精品无码av| 久久久久久久97| 久久国产免费观看精品| 日本精品久久久久影院日本 | 精品国产乱码久久久久软件| 久久天天躁狠狠躁夜夜avapp| 成人久久精品一区二区三区| 久久久精品国产亚洲成人满18免费网站 | 亚洲精品白浆高清久久久久久| 97久久久精品综合88久久| 久久高清一级毛片| 亚洲精品乱码久久久久久中文字幕 | 青青青青久久精品国产 | 久久天天躁夜夜躁狠狠| 伊人色综合久久天天| 狠狠色丁香久久婷婷综合图片 | 亚洲国产成人精品91久久久| 久久精品人人做人人爽97| 性做久久久久久久久浪潮| 99久久免费国产精精品| 久久无码AV一区二区三区| 久久精品?ⅴ无码中文字幕| 精品少妇人妻av无码久久| 欧美一区二区久久精品|