summaryrefslogtreecommitdiffstatshomepage
path: root/tests/extmod/machine_disable_irq.py
diff options
context:
space:
mode:
authorAngus Gratton <angus@redyak.com.au>2024-09-25 18:18:22 +1000
committerAngus Gratton <angus@redyak.com.au>2024-10-10 10:59:51 +1100
commit05ac69329d259b3853c2d3a89d669eba7f6eef46 (patch)
treee56589e1ab4147b762ed70861136e21fc24deb07 /tests/extmod/machine_disable_irq.py
parent197becbdcc0f8e6fd03ddaa921c32193a4a409db (diff)
downloadmicropython-05ac69329d259b3853c2d3a89d669eba7f6eef46.tar.gz
micropython-05ac69329d259b3853c2d3a89d669eba7f6eef46.zip
esp32: Fix hang in taskYIELD() on riscv CPUs when IRQs disabled.
Regression introduced in 337742f. The hang occurs because the esp32 port was calling "from ISR" port-layer functions to set/clear the interrupt mask. FreeRTOS kernel therefore doesn't know the CPU is in a critical section. In taskYIELD() the riscv port layer blocks after yielding until it knows the yield has happened, and would block indefinitely if IRQs are disabled (until INT WDT triggers). Moving to the "public" portENTER_CRITICAL/portEXIT_CRITICAL API means that FreeRTOS knows we're in a critical section and can react accordingly. Adds a regression test for this case (should be safe to run on all ports). On single core CPUs, this should result in almost exactly the same behaviour apart from fixing this case. On dual core CPUs, we now have cross-CPU mutual exclusion for atomic sections. This also shouldn't change anything, mostly because all the code which enters an atomic section runs on the same CPU. If it does change something, it will be to fix a thread safety bug. There is some risk that this change triggers a FreeRTOS crash where there is a call to a blocking FreeRTOS API with interrupts disabled. Previously this code might have worked, but was probably thread unsafe and would have hung in some circumstances. This work was funded through GitHub Sponsors. Signed-off-by: Angus Gratton <angus@redyak.com.au>
Diffstat (limited to 'tests/extmod/machine_disable_irq.py')
-rw-r--r--tests/extmod/machine_disable_irq.py26
1 files changed, 26 insertions, 0 deletions
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)