gint/src/cpu/atomic.c
Lephe 7aa86235a3
cpu: fix a data race occurring on the cpu_atomic lock
The function was designed with multi-threaded concurrency in mind,
where threads can take over while the lock is held and simply block
trying to acquire it, which allows the lock holder to proceed.

However interrupt handlers are different; they have priority, so once
they start they must complete immediately. The cannot afford to block
on the lock as the program would simply freeze. In exchange, they clean
up before they leave, so there are some guarantees on the execution
state even when interrupted.

The correct protection is therefore not a lock but a temporary block on
interrupts. There is no data race on the value of the saved IMASK
because it is preserved during interrupt handling.
2021-05-12 09:17:25 +02:00

39 lines
801 B
C

//---
// gint:cpu:atomic - Simulated atomic operations
//---
#include <gint/cpu.h>
/* Value of IMASK when atomic mode is entered */
static int saved_IMASK = 0;
/* Number of atomic mode levels */
static unsigned int atomic_level = 0;
void cpu_atomic_start(void)
{
/* There is no access problem to IMASK here because interrupts must
preserve and restore it */
cpu_sr_t SR = cpu_getSR();
cpu_sr_t SR2 = SR;
SR2.IMASK = 15;
cpu_setSR(SR2);
/* Now that we're alone, atomically update the atomic level */
if(atomic_level == 0) saved_IMASK = SR.IMASK;
atomic_level++;
}
void cpu_atomic_end(void)
{
cpu_sr_t SR = cpu_getSR();
/* Update atomic_level before restoring interrupts */
atomic_level--;
if(atomic_level == 0) {
SR.IMASK = saved_IMASK;
saved_IMASK = 0;
}
cpu_setSR(SR);
}