割り込みハンドラの関割り込み関数disable_についてIRqとdisable_irq_nosync
disable_IRqは割り込みを閉じ、割り込み処理が完了するのを待って戻ってくるが、disable_irq_Nosyncはすぐに戻ります.では、割り込み処理プログラムでどの関数を使用して割り込みを閉じるべきですか?
のキードライバではdisable_を使用します.IRqは割り込みをオフにしますが、テスト中に割り込みに入ると、システムは割り込み処理プログラムで死んでdisable_に変わります.irq_Nosyncは割り込み処理プログラムを正常に終了します.カーネルコードから原因を探します.
まずdisableを見てみましょうirq_nosync、カーネルコードでは次のように説明されています.
割り込みを閉じるとプログラムは戻る、割り込み処理プログラムであれば、割り込み処理プログラムの実行は継続する.
割り込みを閉じて割り込み処理が完了するのを待って戻る.コードから分かるようにdisable_IRqはまずdisableを呼び出したirq_Nosync、desc->actionが1であるかどうかを検出します.割り込み処理プログラムではactionが1に設定されているのでsynchronize_に入ります.IRq関数では.
注記では、この関数が割り込み処理プログラムの終了を待つことを示します.これもdisable_です.IRqとdisable_irq_Nosyncの主な場所は異なりますが、割り込み処理関数で呼び出されるとどうなりますか?割り込み処理関数に入る前のIRQ_INPROGRESSは_setup_IRqが設定されているため、プログラムはwhileサイクルに陥り続け、カーネルが独占され、システムが死んでしまう.
まとめ:
なぜならIRqでsynchronizeが呼び出されます.IRq関数は割り込み戻りを待つため、割り込みハンドラではdisable_を使用できません.IRq、そうでないとcpuがsynchronize_IRq独占によりシステムクラッシュが発生する.
まずdisableを見てみましょうirq_nosync、カーネルコードでは次のように説明されています.
/**
* disable_irq_nosync - disable an irq without waiting
* @irq: Interrupt to disable
*
* Disable the selected interrupt line. Disables and Enables are
* nested.
* Unlike disable_irq(), this function does not ensure existing
* instances of the IRQ handler have completed before returning.
*
* This function may be called from IRQ context.
*/
void disable_irq_nosync(unsigned int irq)
{
struct irq_desc *desc = irq_to_desc(irq);
unsigned long flags;
if (!desc)
return;
chip_bus_lock(irq, desc);
spin_lock_irqsave(&desc->lock, flags);
__disable_irq(desc, irq, false);
spin_unlock_irqrestore(&desc->lock, flags);
chip_bus_sync_unlock(irq, desc);
}
割り込みを閉じるとプログラムは戻る、割り込み処理プログラムであれば、割り込み処理プログラムの実行は継続する.
/**
* disable_irq - disable an irq and wait for completion
* @irq: Interrupt to disable
*
* Disable the selected interrupt line. Enables and Disables are
* nested.
* This function waits for any pending IRQ handlers for this interrupt
* to complete before returning. If you use this function while
* holding a resource the IRQ handler may need you will deadlock.
*
* This function may be called - with care - from IRQ context.
*/
void disable_irq(unsigned int irq)
{
struct irq_desc *desc = irq_desc + irq;
if (irq >= NR_IRQS)
return;
disable_irq_nosync(irq);
if (desc->action)
synchronize_irq(irq);
}
割り込みを閉じて割り込み処理が完了するのを待って戻る.コードから分かるようにdisable_IRqはまずdisableを呼び出したirq_Nosync、desc->actionが1であるかどうかを検出します.割り込み処理プログラムではactionが1に設定されているのでsynchronize_に入ります.IRq関数では.
/**
* synchronize_irq - wait for pending IRQ handlers (on other CPUs)
* @irq: interrupt number to wait for
*
* This function waits for any pending IRQ handlers for this interrupt
* to complete before returning. If you use this function while
* holding a resource the IRQ handler may need you will deadlock.
*
* This function may be called - with care - from IRQ context.
*/
void synchronize_irq(unsigned int irq)
{
struct irq_desc *desc = irq_to_desc(irq);
unsigned int status;
if (!desc)
return;
do {
unsigned long flags;
/*
* Wait until we're out of the critical section. This might
* give the wrong answer due to the lack of memory barriers.
*/
while (desc->status & IRQ_INPROGRESS)
cpu_relax();
/* Ok, that indicated we're done: double-check carefully. */
spin_lock_irqsave(&desc->lock, flags);
status = desc->status;
spin_unlock_irqrestore(&desc->lock, flags);
/* Oops, that failed? */
} while (status & IRQ_INPROGRESS);
/*
* We made sure that no hardirq handler is running. Now verify
* that no threaded handlers are active.
*/
wait_event(desc->wait_for_threads, !atomic_read(&desc->threads_active));
}
注記では、この関数が割り込み処理プログラムの終了を待つことを示します.これもdisable_です.IRqとdisable_irq_Nosyncの主な場所は異なりますが、割り込み処理関数で呼び出されるとどうなりますか?割り込み処理関数に入る前のIRQ_INPROGRESSは_setup_IRqが設定されているため、プログラムはwhileサイクルに陥り続け、カーネルが独占され、システムが死んでしまう.
まとめ:
なぜならIRqでsynchronizeが呼び出されます.IRq関数は割り込み戻りを待つため、割り込みハンドラではdisable_を使用できません.IRq、そうでないとcpuがsynchronize_IRq独占によりシステムクラッシュが発生する.