Search code examples
cembeddedrace-conditionmsp430atomic

Avoid race condition on check-then-sleep


Take the following example code:

static volatile bool pending = false;

void __attribute__((interrupt(TIMER0_A0_VECTOR))) TIMER0_A0_ISR (void)
{
    pending = true;        
}

int main(void)
{
    while(true) {
        if (!pending)
            sleep();
        pending = false;
        // do stuff
    }
}

Assume that the sleep function puts the hardware to sleep and that an interrupt wakes the hardware up, so that the sleep function will return immidiately after the interrupt.

There is a race condition here: if the interrupt happens after the if statement but before the sleep, we sleep until the next interrupt. This is a problem in my real-world counterpart of this code. How can I avoid this problem?

I am working with the msp430g2433.


Solution

  • To ensure that the check and the going-to-sleep are executed atomically, you have to disable interrupts around them. This also requires that you go to sleep and re-enable interrupts at the same time, but this is easy on the MSP430:

    while (true) {
        _disable_interrupts();
        if (!pending)
            _bis_SR_register(GIE + LPM1_bits);
        else
            _enable_interrupts();
    
        pending = false;
        // do stuff
    }
    

    Alternatively, write the interrupt bit accesses explicitly, which might make the logic clearer:

    while (true) {
        int status_bits = GIE;
        _bic_SR_register(status_bits); // disable interrupts
        if (!pending)
            status_bits |= LPM1_bits;
        _bis_SR_register(status_bits); // enable interrupts, go to sleep if needed
    
        pending = false;
        // do stuff
    }