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>
63 lines
1.4 KiB
Python
63 lines
1.4 KiB
Python
# This test ensures that the scheduler doesn't trigger any assertions
|
|
# while dealing with concurrent access from multiple threads.
|
|
|
|
import _thread
|
|
import time
|
|
import micropython
|
|
import gc
|
|
|
|
try:
|
|
micropython.schedule
|
|
except AttributeError:
|
|
print("SKIP")
|
|
raise SystemExit
|
|
|
|
gc.disable()
|
|
|
|
_NUM_TASKS = 10000
|
|
_TIMEOUT_MS = 10000
|
|
|
|
n = 0 # How many times the task successfully ran.
|
|
t = None # Start time of test, assigned here to preallocate entry in globals dict.
|
|
thread_run = True # If the thread should continue running.
|
|
|
|
|
|
def task(x):
|
|
global n
|
|
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:
|
|
micropython.schedule(task, None)
|
|
except RuntimeError:
|
|
# Queue full, back off.
|
|
time.sleep_ms(10)
|
|
|
|
|
|
for i in range(8):
|
|
try:
|
|
_thread.start_new_thread(thread, ())
|
|
except OSError:
|
|
# System cannot create a new thead, so stop trying to create them.
|
|
break
|
|
|
|
# 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:
|
|
time.sleep(0)
|
|
|
|
# Stop all threads.
|
|
thread_run = False
|
|
time.sleep_ms(20)
|
|
|
|
gc.enable()
|
|
|
|
if n < _NUM_TASKS:
|
|
# Not all the tasks were scheduled, likely the scheduler stopped working.
|
|
print(n)
|
|
else:
|
|
print("PASS")
|