I have a function to disable interrupts, but the problem is that if I disable them and I call a function which also disables/enables them, they get re-enabled too early. Is the following logic enough to prevent this?
static volatile int IrqCounter = 0;
void EnableIRQ()
{
if(IrqCounter > 0)
{
IrqCounter--;
}
if(IrqCounter == 0)
{
__enable_irq();
}
}
void DisableIRQ()
{
if(IrqCounter == 0)
{
__disable_irq();
}
IrqCounter++;
}
Assuming that you’ve got a system where you can’t change context when interrupts are disabled, then what you’ve got is fine, assuming you keep careful track of when call the enable().
In the usage you’re describing in the comments below, you plan on using these sections from within an interrupt service routine. Your main use is blocking higher-priority interrupts from running for a certain portion of an ISR.
Be aware that you’ll have to consider the stack depth of these nested ISRs, as when you enable interrupts before your return from interrupt, you’ll have interrupts enabled in the ISR.
Regarding other answers: the lack of thread-safety of the enable() (due to the
if(IrqCounter > 0)) doesn’t matter, because anytime you’re in the enable() context switches are already disabled due to interrupts being off. (Unless for some reason you have unmatched disable/enable pairs, and in that case you’ve got other issues.)The only suggestion I’d have would be to add an ASSERT to the enable instead of the run-time check, as you should never be enabling interrupts that you didn’t disable.
I prefer the technique you’ve listed over the
save(); disable(); restore();technique as I don’t like having to keep track of a piece of the OS’ data every time I work with the interrupts. But, you do have to be aware of when you (directly or indirectly) make a call to the enable() from an ISR.