__do_IRQ() について (その3)

次がある意味メイン。 ちなみにコメントに、<超意訳>
「エッヂトリガな割り込みはペンディングなナニを覚えとく必要あり。この処理は(?) do_IRQ か ハンドラ実行中に着信した同一 IRQ の許可された二発目の割り込みを apply する。がしかし二発目だけで、それ以降は却下。SMP な環境でマスクが微妙な PIC についてだいたい使えるのではなかろうか。」
とある。深い。何故に二発目限定なんだろうか。

    for (;;) {
        irqreturn_t action_ret;

        spin_unlock(&desc->lock);

        action_ret = handle_IRQ_event(irq, regs, action);

        spin_lock(&desc->lock);
        if (!noirqdebug)
            note_interrupt(irq, desc, action_ret);
        if (likely(!(desc->status & IRQ_PENDING)))
            break;
        desc->status &= ~IRQ_PENDING;
    }
    desc->status &= ~IRQ_INPROGRESS;

繰り返し先頭の spin_lock 解除なナニが直前エントリでの IRQ_PENDING な所以かも。これ前提で言えば、三度も四度も相手してるとキリが無いわな。って、handle_IRQ_event() 呼んだ直後に再度 spin_lock してるし。このあたりもシビアな理由がありそうだがスルー。(をーい
とは言え、handle_IRQ_event() 内で spin_unlock してなきゃ、な理由はあるんだろうな。このあたりは読んでいく中でどう解決していけば良いのやら。

handle_IRQ_event() は別途掘っていくとして、戻ってきたら再度 spin_lock している。んで、その直後の

        if (!noirqdebug)
            note_interrupt(irq, desc, action_ret);

は、とりあえずスルー。noirqdebug とか掘りかけたんですが、この部分は別途とゆー事にした方が良さげ、との勝手な判断による。
で、次の条件分岐にて IRQ ディスクリプタの状態 (status の値) が IRQ_PENDING なフラグが立っていなければ無限ループ脱出。逆に IRQ_PENDING なフラグが立ってた場合、IRQ_PENDING なフラグを落として再度ループ内の処理を実行、と。これが_二度_な所以ですな。ただ、handle_IRQ_event() 内で IRQ ディスクリプタの状態が変わる可能性があるとナニかもしれんが、この時点ではコメントを信用するしかないかも。

で、ループ脱出後は、IRQ ディスクリプタの状態 (status の値) から IRQ_INPROGRESS なフラグをオトしてこのブロックは終了、と。

残りは少ないんでこのまま続行。以下です。

out:
	/*
	 * The ->end() handler has to deal with interrupts which got
	 * disabled while the handler was running.
	 */
	desc->handler->end(irq);
	spin_unlock(&desc->lock);

	return 1;

end() を呼び出して (8259A の場合、end_8259A_irq())、spin_unlock して終了。IRQ について見事に抽象化されているような印象です。

この後、どうするか微妙なんですが、ちょっと週末だし amazon:Linux カーネル解析入門 やらその他の文書をメモを取りつつきちんと読みこむ必要あるかな、と感じております。