3

割り込みを無効にする関数がありますが、問題は、それらを無効にし、それらを無効/有効にする関数を呼び出すと、割り込みが再び有効になりすぎることです。これを防ぐには、次のロジックで十分ですか?

static volatile int IrqCounter = 0;

void EnableIRQ()
{
    if(IrqCounter > 0)
    {
        IrqCounter--;
    }

    if(IrqCounter == 0)
    {
        __enable_irq();
    }
}

void DisableIRQ()
{
    if(IrqCounter == 0)
    {
        __disable_irq();
    }

    IrqCounter++;
}
4

4 に答える 4

5

私が知っているすべてのオペレーティング システムでは、IRQ の状態をローカル変数に保存し、それを復元します。

明らかに、コードにはTOCTOUの問題があります。2 つのスレッドが同時に実行され、IrqCounter > 0 をチェックし、IrqCounter == 1 の場合、最初のスレッドはそれを 1 と見なし、2 番目のスレッドはそれを 1 と見なし、両方ともデクリメントします。カウンタ。

私は間違いなく次のようなものを手配しようとします:

int irq_state = irq_save();

irq_disable();

... do stuff with IRQ's turned off ... 

irq_restore(irq_state);

これで、カウンターが同期しなくなるなどの心配をする必要がなくなりました。

于 2013-01-29T12:45:47.603 に答える
2

割り込みが無効になっているときにコンテキストを変更できないシステムがあると仮定すると、 enable() をいつ呼び出すかを注意深く追跡していれば、問題はありません。

以下のコメントで説明している使用法では、割り込みサービス ルーチン内からこれらのセクションを使用する予定です。主な用途は、優先度の高い割り込みが ISR の特定の部分で実行されるのをブロックすることです。

これらのネストされた ISR のスタックの深さを考慮する必要があることに注意してください。割り込みから戻る前に割り込みを有効にすると、ISR で割り込みが有効になります。

他の回答について: enable() のスレッド セーフの欠如 ( によるif(IrqCounter > 0)) は問題ではありません。これは、enable() コンテキスト スイッチにいるときはいつでも、割り込みがオフになっているために既に無効になっているためです。(何らかの理由で無効化/有効化のペアが一致しない場合を除き、その場合は他の問題があります。)

唯一の提案は、実行時チェックの代わりに有効に ASSERT を追加することです。無効にしなかった割り込みを有効にしてはならないからです。

void EnableIRQ()
{
  ASSERT(IrqCounter != 0)  //should never be 0, or we'd have an unmatched enable/disable pair

  IrqCounter--;  //doesn't matter that this isn't thread safe, as the enable is always called with interrupts disabled.

  if(IrqCounter == 0)
  {
      __enable_irq();
  }
}

save(); disable(); restore();割り込みを操作するたびにOSのデータの一部を追跡する必要がないので、テクニックよりもリストしたテクニックを好みます。ただし、いつ (直接または間接的に) ISR から enable() を呼び出すかを認識する必要があります。

于 2013-01-29T14:40:32.907 に答える
0

スレッドセーフではないことを除けば、それは問題ないように見えます。

別の一般的なオプションは、割り込みの有効/無効状態を照会してローカル変数に保存し、次に割り込みを無効にし、割り込みが無効になっている間にやりたいことを行い、ローカル変数から状態を復元することです。

于 2013-01-29T12:21:09.263 に答える
0
static volatile int IrqCounter = 0;

void EnableIRQ(void)
{
    ASSERT(IrqCounter != 0)  //should never be 0, or we'd have an unmatched enable/disable pair

    if (IrqCounter > 0)
    {
        IrqCounter--;
    }

    if (IrqCounter == 0)
    {
        __enable_irq();
    }
}

void DisableIRQ(void)
{
    __disable_irq(); // Fix TOCTOU issues. In CMSIS there is no harm in extra disables, so always disable.
    IrqCounter++;
}
于 2020-11-15T17:58:41.720 に答える