summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--ports/esp32/mphalport.c2
-rw-r--r--ports/esp32/mphalport.h23
-rw-r--r--tests/extmod/machine_disable_irq.py26
-rw-r--r--tests/extmod/machine_disable_irq.py.exp3
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