Linuxのカーネルソフトブレーク(softirq)実行分析

12516 ワード

本文はLinuxカーネルのソフトブレークの実行プロセスを分析し、できるだけ現在の実行環境と結びつけて私の理解を詳しく書いたが、これは私の理解が正しいことを示していない.これはフォーラムの中の1篇の招待状で、出すのはレンガを投げて玉を引くためで、もしあなたが本文を読む時私の間違いを発見したら、またあなたの指摘を得ることを望みます.
 
今日は何気なく目2.6コアのソフトブレーク実装を見て、以前私が見たのとは大きく異なることに気づきました(以前も馬鹿げていて、あまり注意していません)、大きく変わったと言えます.softirqの呼び出しポイントまで違います.以前は3つの呼び出しポイントでしたが、今日ソースコードを検索してみると、ksoftirqdが多くなった後、softirqのシステムでの呼び出しポイントはISRの戻り時とlocal_を使用しただけです.bh_enable()関数が呼び出されました.NIC部分の表示呼び出しは、システム内の呼び出しポイントではないと思います.ksoftirqdはdo_を呼び出すために戻りますsoftirq()関数もそのうちの1つの分岐としか言えないはずです.それ自体はソースから言えばISRが戻ったときのirq_であるからです.exit()呼び出しです.これで先日書いたノート(Windows/Linux)と
/Solarisソフト割り込みメカニズム)で紹介されているLinuxカーネル部分のソフト割り込みには出典がありますが、今後Linux kernelコードを議論するには必ずカーネルバージョンを前題にしなければならないようです.Linux側の本を買わなければなりません.毎回直接関連コードを読むのも問題ではありません.時間も許されません.
//

// do_IRQ         ISR          。

//



void irq_exit(void)

{

        account_system_vtime(current);

        trace_hardirq_exit();

        sub_preempt_count(IRQ_EXIT_OFFSET);



        //

        //              ,         

        // pending   ,  :            

        //  ,       do_softirq()      。   

        //                ,         

        //             。

        // 

        if (!in_interrupt() && local_softirq_pending())



                //

                //          do_softirq()   

                //

                invoke_softirq();

        preempt_enable_no_resched();

}





#ifndef __ARCH_HAS_DO_SOFTIRQ



asmlinkage void do_softirq(void)

{

        __u32 pending;

        unsigned long flags;



        //

        //       ,           ,  

        //           ,     。   

        //            ksoftirqd   。

        //

        if (in_interrupt())

                return;



        //

        //          

        //

        local_irq_save(flags);



        //

        //       pending         。

        //

        pending = local_softirq_pending();



        //

        //        __do_softirq()       

        //

        if (pending)

                __do_softirq();



        //

        //        

        //

        local_irq_restore(flags);

}





//

//            10  。

//



#define MAX_SOFTIRQ_RESTART 10



asmlinkage void __do_softirq(void)

{

        //

        //         ,        ISR  

        //        。

        //

        struct softirq_action *h;

        __u32 pending;

        int max_restart = MAX_SOFTIRQ_RESTART;

        int cpu;



        //

        //        pending     。

        // 

        pending = local_softirq_pending();

        account_system_vtime(current);



        //

        //              ,       

        //    CPU               。

        //

        __local_bh_disable((unsigned long)__builtin_return_address(0));

        trace_softirq_enter();



        //

        //    SMP           CPU

        //

        cpu = smp_processor_id();

//

//     

//

restart:

        //

        //           ISR    ,       

        //     。

        //

        /* Reset the pending bitmask before enabling irqs */

        set_softirq_pending(0);



        //

        //          ,  :            

        //   ,                   。  

        //                        。  

        //                   。

        //

        local_irq_enable();



        //

        //      ,                , 

        //      ISR      ,               ,

        //    ,           ,     __local_bh_disable()

        //         。                ,  

        //                   。     ,    

        // __local_bh_disable()               ,   

        //         irq_exit()   do_softirq()     

        // in_interrupt()          ,     in_interrupt() 

        //                   。          

        //           ,               ,  

        //       ,         (   MAX_SOFTIRQ_RESTART)

        //                         。

        //





        //

        //         。

        //

        h = softirq_vec;



        //

        //        softirq        。

        // 

        do {

                //

                //            pending      

                //               。

                //

                if (pending & 1) {

                        //

                        //                    。

                        //

                        h->action(h);

                        rcu_bh_qsctr_inc(cpu);

                }

        //

        //    ,             pending   

        //       。

        //

                h++;



                //

                //             ,       

                //    32          。

                //

                pending >>= 1; 

        } while (pending);



        //

        //          。  :       ,   

        //                。

        //

        local_irq_disable();



        //

        //      ,                    

        //   ,              ,      

        //                  ,        

        //         ,               。

        //                 restart      。

        //

        pending = local_softirq_pending();



        //

        //                      ,    

        //           ,         pending  ,

        //                      ,   

        //   ,   irq_exit()   do_softirq()        

        //         。            。   

        //             。  :         

        //              ,            

        //                           

        //   ,                ,       

        //        ISR                。

        //



        //

        //                  ,        

        //     10    ,       restart        

        //         :        ,       ...

        //   :                        。 

        //

        if (pending && --max_restart)

                goto restart;



        //

        //           10      pending       ,

        //                    ,      。

        //           ksoftirqd      ,      

        //         。   ksoftirqd           ,

        //              ,            ,

        //    ,         preempt_xxx()   schedule()

        //          。                

        // local_softirq_pending()        pending     

        //        ,        do_softirq()      

        //  。    ,        ksoftirqd        

        //         ,                  

        //  ,        do_softirq(),         do_softirq()

        //         in_interrupt()             

        //         ,          。ksoftirqd   

        //      ksoftirqd()      。

        //

        if (pending)



               //

               //          wake_up_process()     ksoftirqd

               // 

                wakeup_softirqd();



        trace_softirq_exit();



        account_system_vtime(current);



        //

        //             ,       。  :  

        //       local_bh_enable(),       do_softirq()

        //    。

        // 

        _local_bh_enable();

}







static int ksoftirqd(void * __bind_cpu)

{



        //

        //                    。  ,

        //                。

        //

        set_user_nice(current, 19);



        //

        //             

        //

        current->flags |= PF_NOFREEZE;



        //

        //                ,     

        //          。

        // 

        set_current_state(TASK_INTERRUPTIBLE);



        //

        //         ,             ,

        //              pending      

        //    。

        //

        while (!kthread_should_stop()) {



                //

                //         ,           

                //        。

                //

                preempt_disable();



                //

                //                 pending    

                //    

                //

                if (!local_softirq_pending()) {



                        //

                        //           CPU        ,  

                        //                  。

                        //

                        preempt_enable_no_resched();



                        //

                        //             CPU            ,

                        //          (          )

                        //

                        schedule();



                        //

                        //   :         schedule()         

                        //           ,              

                        //       。    ,             

                        //  ,        preempt_disable()   。

                        //



                        //

                        //          ,              

                        //    。

                        //

                        preempt_disable();

                }



                //

                //            。  :             

                //       ,                  。  

                //         pending          。       

                //    pending     ,            CPU    

                //    。

                //

                __set_current_state(TASK_RUNNING);



                //

                //         pending     ,       do_softirq()

                //       。  :       do_softirq()     ,

                //     __do_softirq()        10          

                //  ,     pending   ,       。      

                //          __do_softirq()           。  

                //     __do_softirq()       ,   10        

                //             。      ,         

                //        ,        do_softirq()       ,

                //         CPU      ,      cond_resched() 

                //         ,                    

                //         CPU   ,                

                //       CPU。

                //

                while (local_softirq_pending()) {

                        /* Preempt disable stops cpu going offline.

                           If already offline, we'll be on wrong CPU:

                           don't process */

                        if (cpu_is_offline((long)__bind_cpu))



                                //

                                //          CPU          

                                //   wait_to_die    ,       。

                                // 

                                goto wait_to_die;



                        //

                        //    do_softirq()              。 

                        //  :                 ,    

                        //   ,         in_interrupt()    。

                        //

                        do_softirq();



                        //

                        //          。

                        //

                        preempt_enable_no_resched();

                        

                        //

                        //              schedule()      

                        //   ,                。   

                        //                ,       

                        //     。                  

                        //                        CPU,

                        //                        

                        //      。

                        //

                        cond_resched();



                        //

                        //          。

                        //

                        preempt_disable();



                        //

                        //           ?            

                        //

                }



                //

                //          ,         ,   

                //             ,          。

                //

                preempt_enable();

                set_current_state(TASK_INTERRUPTIBLE);

        }

   

        //

        //                        。

        //                  。

        //

        __set_current_state(TASK_RUNNING);

        return 0;



//

//             

//

wait_to_die:



        //

        //          。

        //

        preempt_enable();

        /* Wait for kthread_stop */



        //

        //                ,     

        //          。

        // 

        set_current_state(TASK_INTERRUPTIBLE);



        //

        //             ,      

        //                    CPU

        //     。               

        //          。

        //

        while (!kthread_should_stop()) {

                schedule();

                set_current_state(TASK_INTERRUPTIBLE);

        }



        //

        //                        。

        //                  。

        //

        __set_current_state(TASK_RUNNING);

        return 0;

}