ソフトバンクの原理とソースの分析


回転http://blog.csdn.net/ustc_dylan/articale/detail/6334000?reload 
Linuxのソフトバンク機構はSMPと密接に切り離せない.このため、ソフト中断をトリガするCPUは、このソフト中断を実行するという思想を徹底的に実行しています.各CPUは、そのソフト中断を実行するということです.この設計思想はまたソフトワール機構にSMPシステムの性能と特徴を十分に利用させた.複数のソフトバンクは並行して実行でき、さらには同じソフトバンクでも複数のプロシージャで同時に実行できます.
一、ソフトクリームの実現
     各ソフトフェルールはカーネルの中でstruct softirqを通ります.actionで表します.また、グローバル所属グループSoftirq_vecは現在のカーネルサポートのすべてのソフトバンクを識別します.
/* softirq mask and active fields moved to irq_cpustat_t in
 * asm/hardirq.h to get better cache usage. KAO
 */
struct softirq_action
{
    void    (*action)(struct softirq_action *);
};
static struct softirq_action softirq_vec[NR_SOFTIRQS] __cacheline_aligned_in_smp;
Linux        32 softirq(  :    32 ?),       10 ,  :
enum
{
    HI_SOFTIRQ=0,
    TIMER_SOFTIRQ,
    NET_TX_SOFTIRQ,
    NET_RX_SOFTIRQ,
    BLOCK_SOFTIRQ,
    BLOCK_IOPOLL_SOFTIRQ,
    TASKLET_SOFTIRQ,
    SCHED_SOFTIRQ,
    HRTIMER_SOFTIRQ,
    RCU_SOFTIRQ,    /* Preferable RCU should always be the last softirq */
    NR_SOFTIRQS
};
二、ソフトクリーム処理関数
    struct softirq_action構造体には、関数ポインタのメンバーactionだけがあります.すなわち、ユーザー定義のソフトフェルール処理関数を指します.実行時には、下記のコードを通じて実行できます.
                     ソフトクリームvec[i]->action(i)
    登録されたソフトウェアは、実行前にアクティブにしなければならない.用語は「ライザーthe softirq」と呼ばれる.アクティブ化されたソフトバンクは通常すぐに実行されません.一般的にはその後のある時点で現在のシステムにpendingされているソフトバンクがあるかどうかを確認します.もしあれば実行します.Linuxカーネルの中でソフトクリームがかかっているかどうかを確認するのは主に以下の3つのタイプがあります.
(1)ハードウェア中断コードが戻ったとき
/*
 * Exit an interrupt context. Process softirqs if needed and possible:
 */
void irq_exit(void)
{
    account_system_vtime(current);
    trace_hardirq_exit();
    sub_preempt_count(IRQ_EXIT_OFFSET);
    if (!in_interrupt() && local_softirq_pending())
        invoke_softirq();
    rcu_irq_exit();
#ifdef CONFIG_NO_HZ
    /* Make sure that timer wheel updates are propagated */
    if (idle_cpu(smp_processor_id()) && !in_interrupt() && !need_resched())
        tick_nohz_stop_sched_tick(0);
#endif
    preempt_enable_no_resched();
}
(2)ksoftirqdカーネルサービススレッドが実行されている場合
static int run_ksoftirqd(void * __bind_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))
                goto wait_to_die;
            do_softirq();
            preempt_enable_no_resched();
            cond_resched();
            preempt_disable();
            rcu_note_context_switch((long)__bind_cpu);
        }
        preempt_enable();
        set_current_state(TASK_INTERRUPTIBLE);
    }
    __set_current_state(TASK_RUNNING);
    return 0;
... ...
}
(3)一部のカーネルサブシステムに表示されているものは、保留されているソフトクリームをチェックします.
int netif_rx_ni(struct sk_buff *skb)
{
    int err;
    preempt_disable();
    err = netif_rx(skb);
    if (local_softirq_pending())
        do_softirq();
    preemptenable();
    return err;
}
以下のポイントを分析します.ソフトバンク()は、Linuxカーネルが一体どうやって処理されているのかを知る.
asmlinkage void do_softirq(void)
{
    unsigned long flags;
    struct thread_info *curctx;
    union irq_ctx *irqctx;
    u32 *isp;
    if (in_interrupt()) /*             */
        return;
    local_irq_save(flags);
    if (local_softirq_pending()) {
        curctx = current_thread_info();
        irqctx = __get_cpu_var(softirq_ctx);
        irqctx->tinfo.task = curctx->task;
        irqctx->tinfo.previous_esp = current_stack_pointer;
        /* build the stack frame on the softirq stack */
        isp = (u32 *) ((char *)irqctx + sizeof(*irqctx));
        call_on_stack(__do_softirq, isp);
        /*
         * Shouldnt happen, we returned above if in_interrupt():
         */
        WARN_ON_ONCE(softirq_count());
    }
    local_irq_restore(flags);
}
実際の処理関数は_u_u u uである.ドドドドソフトクリーム:
asmlinkage void __do_softirq(void)
{
    struct softirq_action *h;
    __u32 pending;
    int max_restart = MAX_SOFTIRQ_RESTART; /*   ksoftirqd  ,     softirq   ,   */
    int cpu;
    /*        softirq,           Linux      32 softirq,  pending  32bit*/
    pending = local_softirq_pending(); 
    account_system_vtime(current);
    __local_bh_disable((unsigned long)__builtin_return_address(0));
    lockdep_softirq_enter();
    cpu = smp_processor_id();
restart:
    /* Reset the pending bitmask before enabling irqs */
    set_softirq_pending(0);/*   pending softirq  ,    pending softirq   */
    local_irq_enable();

    h = softirq_vec;
    do {

        if (pending & 1) { /*      ,        pending softirq*/
            int prev_count = preempt_count();
            kstat_incr_softirqs_this_cpu(h - softirq_vec);
            trace_softirq_entry(h, softirq_vec);

            h->action(h); /*  softirq     */
            trace_softirq_exit(h, softirq_vec);
            if (unlikely(prev_count != preempt_count())) {
                printk(KERN_ERR "huh, entered softirq %td %s %p"
                 "with preempt_count %08x,"
                 " exited with %08x?/n", h - softirq_vec,
                 softirq_to_name[h - softirq_vec],
                 h->action, prev_count, preempt_count());
                preempt_count() = prev_count;
            }
            rcu_bh_qs(cpu);

        }
        h++;
        pending >>= 1;  /*    */
    } while (pending);
    local_irq_disable();

    pending = local_softirq_pending();
    if (pending && --max_restart)  /*  ksoftirqd   */
        goto restart;
    if (pending)  /*  ksoftirqd   softirq,    pending softirq   ,    ,        ,    softirq pending*/
        wakeup_softirqd();
    lockdep_softirq_exit();

 

    account_system_vtime(current);
    _local_bh_enable();
}
三、ソフトクリームを使う
     ソフトバンクは一般的にリアルタイム性に対する要求が強いところで使われています.現在のLinuxカーネルでは、2つのサブシステムだけがそのままソフトバンクを使用しました.また、新しいソフトバンクを追加するにはカーネルを再コンパイルする必要がありますので、必要でない限り、tasletとkenel timerが現在の必要に適するかどうかを考慮したほうがいいです.
     ソフトバンクを使用しなければならないならないなら、考慮すべき重要な問題は新しく増加したソフトフェルールの優先度であり、デフォルトではソフトフェルールの数値が小さいほど優先度が高く、実際の経験によって新たに増加したソフトフェルールはBLOCK_にあるほうがいいです.SOFTIRQとTASKLET_SOFTIRQ間
     ソフトクリームの処理関数はopen_を通ります.ソフトクリームは登録されています.この関数は二つのパラメータを受け取ります.一つはソフトクリームの整数インデックスで、もう一つはソフトクリームに対応する処理関数です.例えば、ネットワークサブシステムでは、次の2つのソフトバンクとその処理関数が登録されている.
open_ソフトクリーム.
open_ソフトクリーム.
    前に述べたように、ソフト中断処理関数の登録後、ソフト中断を有効化する必要があります.このソフト中断が実行されます.ソフトウェアソフトウェア関数を実装すると、ネットワークサブシステムでコードがアクティブになります.
/* Called with irq disabled */
static inline void ____napi_schedule(struct softnet_data *sd,
                 struct napi_struct *napi)
{
    list_add_tail(&napi->poll_list, &sd->poll_list);
    __raise_softirq_irqoff(NET_RX_SOFTIRQ);
}
ここの_レイセ.ソフトクリームIqoffとライヴソフトバンクの違いは、前者は事前にシャットダウンされている場合に使用され、後者は自分で中断されたシャットダウンと回復を完了するということです.