diff options
-rw-r--r-- | ports/esp32/mphalport.c | 2 | ||||
-rw-r--r-- | ports/esp32/mphalport.h | 23 | ||||
-rw-r--r-- | tests/extmod/machine_disable_irq.py | 26 | ||||
-rw-r--r-- | tests/extmod/machine_disable_irq.py.exp | 3 |
4 files changed, 48 insertions, 6 deletions
diff --git a/ports/esp32/mphalport.c b/ports/esp32/mphalport.c index 999d77dad5..59ec6d6b19 100644 --- a/ports/esp32/mphalport.c +++ b/ports/esp32/mphalport.c @@ -57,6 +57,8 @@ TaskHandle_t mp_main_task_handle; static uint8_t stdin_ringbuf_array[260]; ringbuf_t stdin_ringbuf = {stdin_ringbuf_array, sizeof(stdin_ringbuf_array), 0, 0}; +portMUX_TYPE mp_atomic_mux = portMUX_INITIALIZER_UNLOCKED; + // Check the ESP-IDF error code and raise an OSError if it's not ESP_OK. #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_NORMAL void check_esp_err_(esp_err_t code) diff --git a/ports/esp32/mphalport.h b/ports/esp32/mphalport.h index f95cf210de..a908d784d7 100644 --- a/ports/esp32/mphalport.h +++ b/ports/esp32/mphalport.h @@ -54,6 +54,8 @@ extern TaskHandle_t mp_main_task_handle; extern ringbuf_t stdin_ringbuf; +extern portMUX_TYPE mp_atomic_mux; + // Check the ESP-IDF error code and raise an OSError if it's not ESP_OK. #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_NORMAL #define check_esp_err(code) check_esp_err_(code) @@ -63,12 +65,21 @@ void check_esp_err_(esp_err_t code); void check_esp_err_(esp_err_t code, const char *func, const int line, const char *file); #endif -// Note: these "critical nested" macros do not ensure cross-CPU exclusion, -// the only disable interrupts on the current CPU. To full manage exclusion -// one should use portENTER_CRITICAL/portEXIT_CRITICAL instead. -#include "freertos/FreeRTOS.h" -#define MICROPY_BEGIN_ATOMIC_SECTION() portSET_INTERRUPT_MASK_FROM_ISR() -#define MICROPY_END_ATOMIC_SECTION(state) portCLEAR_INTERRUPT_MASK_FROM_ISR(state) +static inline mp_uint_t mp_begin_atomic_section(void) { + portENTER_CRITICAL(&mp_atomic_mux); + return 0; +} + +static inline void mp_end_atomic_section(mp_uint_t state) { + (void)state; + portEXIT_CRITICAL(&mp_atomic_mux); +} + +// Note: These atomic macros disable interrupts on the calling CPU, and on SMP +// systems also protect against concurrent access to an atomic section on the +// other CPU. +#define MICROPY_BEGIN_ATOMIC_SECTION() mp_begin_atomic_section() +#define MICROPY_END_ATOMIC_SECTION(state) mp_end_atomic_section(state) uint32_t mp_hal_ticks_us(void); __attribute__((always_inline)) static inline uint32_t mp_hal_ticks_cpu(void) { diff --git a/tests/extmod/machine_disable_irq.py b/tests/extmod/machine_disable_irq.py new file mode 100644 index 0000000000..3132128722 --- /dev/null +++ b/tests/extmod/machine_disable_irq.py @@ -0,0 +1,26 @@ +# Test executing Python code while IRQs disabled. +try: + from machine import disable_irq, enable_irq + from time import ticks_us +except ImportError: + print("SKIP") + raise SystemExit + + +# Structured to also nest disable_irq() calls +def f(n): + st_irq = disable_irq() + if n: + f(n - 1) + else: + # busy-wait in a tight loop for 1ms, to simulate doing some work in a critical section + # (can't wait for time_us() to increment as not all ports will "tick" with interrupts off.) + for _ in range(100): + ticks_us() + enable_irq(st_irq) + + +for nest in range(3): + print(nest) + for _ in range(5): + f(nest) diff --git a/tests/extmod/machine_disable_irq.py.exp b/tests/extmod/machine_disable_irq.py.exp new file mode 100644 index 0000000000..4539bbf2d2 --- /dev/null +++ b/tests/extmod/machine_disable_irq.py.exp @@ -0,0 +1,3 @@ +0 +1 +2 |