'ARM real-time - How to avoid race conditions in interrupt service routines

On ARM Cortex M3 bare-metal real-time microcontroller application, I need to ensure that function dispatch() is called exactly once per interrupt. dispatch() uses global data and is hence not reentrant, so I also need to ensure that it does not get called in an ISR if it is already in the middle of running.

In pseudocode, I can achieve these goals like this:

atomic bool dispatcher_running;
atomic uint dispatch_count;

ISR 0:
    flag0 = true;
    dispatch_count++;
    if (!dispatcher_running)
         dispatch();
ISR 1:
    flag1 = true;
    dispatch_count++;
    if (!dispatcher_running)
         dispatch();
...
void dispatch() {
    if (dispatcher_running)     // Line A
        return;
    dispatcher_running = true;  // Line B
    while (dispatch_count--) {
       // Actual work goes here
    }
    dispatcher_running = false;
}

The challenge, however, is that dispatch_count and dispatcher_running need to be atomic or barriered. Otherwise, race conditions could result. Even pure atomic isn't enough: An ISR could call dispatch(), which passes the check at Line A, and, before it gets to Line B, another ISR calls dispatch(); this would result in two instances of dispatch running simultaneously.

My questions are:

  1. What type of atomic or barriers do I need to make this work?
  2. Which ARM instructions (e.g. DMB) can be used to achieve them?
  3. Is there a portable std C++ way to do something similar? I don't intend to use e.g. std::atomic, as this is bare metal. But I would like to have a similar C++ lib that does the equivalent, as I am prototyping parts of the application on a PC.


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source