From 5ecafab83dc46869bba22d08a08af2c481ea10a6 Mon Sep 17 00:00:00 2001 From: Marian Buschsieweke Date: Wed, 29 Apr 2020 11:14:00 +0200 Subject: [PATCH] sys/pm: Correctly access pm_blocker Replace `volatile` access to pm_blocker by guarding the accesses with `irq_disable()` ... `irq_restore()`. `volatile` does only guarantee that no compiler optimizations are performed on a variable access, but does not provide atomic access. E.g. on systems with a memory bus of less than 32 bit, the access to pm_blocker cannot be done with a single CPU instruction. Thus, resorting to disabling IRQs is the easiest and most portable way to actually achieve atomic access. --- sys/pm_layered/pm.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/sys/pm_layered/pm.c b/sys/pm_layered/pm.c index 5b1f37b45e..0559da27d5 100644 --- a/sys/pm_layered/pm.c +++ b/sys/pm_layered/pm.c @@ -36,11 +36,13 @@ /** * @brief Global variable for keeping track of blocked modes */ -static volatile pm_blocker_t pm_blocker = { .val_u32 = PM_BLOCKER_INITIAL }; +static pm_blocker_t pm_blocker = { .val_u32 = PM_BLOCKER_INITIAL }; void pm_set_lowest(void) { + unsigned state = irq_disable(); pm_blocker_t blocker = pm_blocker; + irq_restore(state); unsigned mode = PM_NUM_MODES; while (mode) { if (blocker.val_u8[mode-1]) { @@ -50,7 +52,7 @@ void pm_set_lowest(void) } /* set lowest mode if blocker is still the same */ - unsigned state = irq_disable(); + state = irq_disable(); if (blocker.val_u32 == pm_blocker.val_u32) { DEBUG("pm: setting mode %u\n", mode); pm_set(mode); @@ -81,7 +83,10 @@ void pm_unblock(unsigned mode) pm_blocker_t pm_get_blocker(void) { - return pm_blocker; + unsigned state = irq_disable(); + pm_blocker_t result = pm_blocker; + irq_restore(state); + return result; } #ifndef PROVIDES_PM_LAYERED_OFF