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>
This commit is contained in:
Damien George 2025-07-13 22:49:15 +10:00
parent b15065b95e
commit b070765427
16 changed files with 34 additions and 15 deletions

View file

@ -2,6 +2,7 @@
#
# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd
import time
import _thread
# the shared bytearray
@ -36,7 +37,7 @@ for i in range(n_thread):
# busy wait for threads to finish
while n_finished < n_thread:
pass
time.sleep(0)
# check bytearray has correct contents
print(len(ba))

View file

@ -2,6 +2,7 @@
#
# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd
import time
import _thread
# the shared dict
@ -38,7 +39,7 @@ for i in range(n_thread):
# busy wait for threads to finish
while n_finished < n_thread:
pass
time.sleep(0)
# check dict has correct contents
print(sorted(di.items()))

View file

@ -2,6 +2,7 @@
#
# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd
import time
import _thread
@ -40,7 +41,7 @@ for i in range(n_thread):
# busy wait for threads to finish
while n_finished < n_thread:
pass
time.sleep(0)
# check user instance has correct contents
print(user.a, user.b, user.c)

View file

@ -2,6 +2,7 @@
#
# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd
import time
import _thread
# the shared list
@ -39,7 +40,7 @@ for i in range(n_thread):
# busy wait for threads to finish
while n_finished < n_thread:
pass
time.sleep(0)
# check list has correct contents
li.sort()

View file

@ -2,6 +2,7 @@
#
# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd
import time
import _thread
# the shared set
@ -33,7 +34,7 @@ for i in range(n_thread):
# busy wait for threads to finish
while n_finished < n_thread:
pass
time.sleep(0)
# check set has correct contents
print(sorted(se))

View file

@ -2,6 +2,7 @@
#
# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd
import time
import _thread
@ -24,5 +25,5 @@ _thread.start_new_thread(thread_entry, ())
# busy wait for thread to finish
while not finished:
pass
time.sleep(0)
print("done")

View file

@ -27,6 +27,8 @@ def task(x):
n += 1
# This function must always use the bytecode emitter so it bounces the GIL when running.
@micropython.bytecode
def thread():
while thread_run:
try:
@ -46,7 +48,7 @@ for i in range(8):
# Wait up to 10 seconds for 10000 tasks to be scheduled.
t = time.ticks_ms()
while n < _NUM_TASKS and time.ticks_diff(time.ticks_ms(), t) < _TIMEOUT_MS:
pass
time.sleep(0)
# Stop all threads.
thread_run = False

View file

@ -7,6 +7,7 @@
import _thread
import sys
from time import ticks_ms, ticks_diff, sleep_ms
import micropython
done = False
@ -21,6 +22,8 @@ if sys.platform in ("win32", "linux", "darwin"):
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

View file

@ -2,6 +2,7 @@
#
# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd
import time
import _thread
@ -34,5 +35,5 @@ for i in range(n_thread):
# busy wait for threads to finish
while n_finished < n_thread:
pass
time.sleep(0)
print("done")

View file

@ -2,6 +2,7 @@
#
# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd
import time
import gc
import _thread
@ -44,6 +45,6 @@ n_thread += 1
# busy wait for threads to finish
while n_finished < n_thread:
pass
time.sleep(0)
print(n_correct == n_finished)

View file

@ -2,6 +2,7 @@
#
# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd
import time
import _thread
@ -27,6 +28,6 @@ print("main", type(tid_main) == int, tid_main != 0)
new_tid = _thread.start_new_thread(thread_entry, ())
while not finished:
pass
time.sleep(0)
print("done", type(new_tid) == int, new_tid == tid)

View file

@ -2,6 +2,7 @@
#
# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd
import time
import _thread
lock = _thread.allocate_lock()
@ -26,4 +27,4 @@ for i in range(n_thread):
# busy wait for threads to finish
while n_finished < n_thread:
pass
time.sleep(0)

View file

@ -2,6 +2,7 @@
#
# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd
import time
import _thread
@ -40,5 +41,5 @@ n_thread += 1
# busy wait for threads to finish
while n_finished < n_thread:
pass
time.sleep(0)
print(tup)

View file

@ -3,6 +3,7 @@
#
# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd
import time
import _thread
@ -31,5 +32,5 @@ for i in range(n_thread):
# busy wait for threads to finish
while n_finished < n_thread:
pass
time.sleep(0)
print(lst)

View file

@ -3,6 +3,7 @@
# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd
import sys
import time
import _thread
# different implementations have different minimum sizes
@ -51,5 +52,5 @@ _thread.stack_size()
# busy wait for threads to finish
while n_finished < n_thread:
pass
time.sleep(0)
print("done")

View file

@ -5,6 +5,7 @@
# This is a regression test for https://github.com/micropython/micropython/issues/15230
# on rp2, but doubles as a general property to test across all ports.
import sys
import time
import _thread
try:
@ -38,7 +39,7 @@ StdinWaiter().wait_stdin(1000)
# have run yet. The actual delay is <20ms but spinning here instead of
# sleep(0.1) means the test can run on MP builds without float support.
while not thread_waiter.is_done():
pass
time.sleep(0)
# The background thread should have completed its wait by now.
print(thread_waiter.is_done())