circuitpython/tests/thread/thread_coop.py
Damien George b070765427 tests/thread: Allow thread tests to pass with the native emitter.
The native emitter will not release/bounce the GIL when running code, so
if it runs tight loops then no other threads get a chance to run (if the
GIL is enabled).  So for the thread tests, explicitly include a call to
`time.sleep(0)` (or equivalent) to bounce the GIL and give other threads a
chance to run.

For some tests (eg `thread_coop.py`) the whole point of the test is to test
that the GIL is correctly bounced.  So for those cases force the use of the
bytecode emitter for the busy functions.

Signed-off-by: Damien George <damien@micropython.org>
2025-07-23 11:37:00 +10:00

56 lines
1.3 KiB
Python

# Threads should be semi-cooperative, to the point where one busy
# thread can't starve out another.
#
# (Note on ports without the GIL this one should always be true, on ports with GIL it's
# a test of the GIL behaviour.)
import _thread
import sys
from time import ticks_ms, ticks_diff, sleep_ms
import micropython
done = False
ITERATIONS = 5
SLEEP_MS = 250
MAX_DELTA = 30
if sys.platform in ("win32", "linux", "darwin"):
# Conventional operating systems get looser timing restrictions
SLEEP_MS = 300
MAX_DELTA = 100
# This function must always use the bytecode emitter so the VM can bounce the GIL when running.
@micropython.bytecode
def busy_thread():
while not done:
pass
def test_sleeps():
global done
ok = True
for _ in range(ITERATIONS):
t0 = ticks_ms()
sleep_ms(SLEEP_MS)
t1 = ticks_ms()
d = ticks_diff(t1, t0)
if d < SLEEP_MS - MAX_DELTA or d > SLEEP_MS + MAX_DELTA:
print("Slept too long ", d)
ok = False
print("OK" if ok else "Not OK")
done = True
# make the thread the busy one, and check sleep time on main task
_thread.start_new_thread(busy_thread, ())
test_sleeps()
sleep_ms(100)
done = False
# now swap them
_thread.start_new_thread(test_sleeps, ())
busy_thread()