diff options
author | Angus Gratton <angus@redyak.com.au> | 2024-09-25 18:18:22 +1000 |
---|---|---|
committer | Angus Gratton <angus@redyak.com.au> | 2024-10-10 10:59:51 +1100 |
commit | 05ac69329d259b3853c2d3a89d669eba7f6eef46 (patch) | |
tree | e56589e1ab4147b762ed70861136e21fc24deb07 /tests/extmod/machine_disable_irq.py | |
parent | 197becbdcc0f8e6fd03ddaa921c32193a4a409db (diff) | |
download | micropython-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.py | 26 |
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) |