1

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.

Christian Gibbons
  • 4,272
  • 1
  • 16
  • 29
Cheiron
  • 3,620
  • 4
  • 32
  • 63
  • @KamilCuk Might be MSP430 – Christian Gibbons Mar 24 '20 at 15:06
  • It is MSP430! I did not know this was platform specific, I will mention it in the question – Cheiron Mar 24 '20 at 15:08
  • Can you not just signal a semaphore? – Martin James Mar 24 '20 at 19:00
  • @MartinJames This is most likely not in a hosted environment; the construct of a semaphore probably doesn't exist here. – Christian Gibbons Mar 24 '20 at 19:37
  • @martinJames How would you design it? You need to tie the if-statement, the semaphore and the sleep call together. How would you do that? – Cheiron Mar 25 '20 at 07:05
  • Why bother with the sleep at all? Can you not just wait on a semaphore and signal it in the interrupt-handler? 'stuff' would then be run exactly as many times as the interrupt occurs. – Martin James Mar 25 '20 at 13:27
  • @ChristianGibbons if it has sleep(), it probably has a tasker with threads, mutex, event, semaphore. If not, then sure, my idea is a non-starter, which is why I commented instead of answering:) – Martin James Mar 25 '20 at 13:32
  • This is indeed an embedded system, there is no operating system. The MSP430 has multiple sleep modes wherin the processor stops executing code until some interrupt. The function sleep just puts the processor in such a mode. With an operating system, a sempahore would have been a good idea, – Cheiron Mar 25 '20 at 13:35

1 Answers1

2

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
}
CL.
  • 173,858
  • 17
  • 217
  • 259