Skip to content

Commit 8470cd0

Browse files
jimmodpgeorge
authored andcommitted
py/scheduler: Add assert that scheduler is locked when unlocking.
And add a test that shows how this can happen when multiple threads are accessing the scheduler, which fails if atomic sections are not used.
1 parent 243805d commit 8470cd0

3 files changed

Lines changed: 51 additions & 0 deletions

File tree

py/scheduler.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ void mp_sched_lock(void) {
108108

109109
void mp_sched_unlock(void) {
110110
mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION();
111+
assert(MP_STATE_VM(sched_state) < 0);
111112
if (++MP_STATE_VM(sched_state) == 0) {
112113
// vm became unlocked
113114
if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL || mp_sched_num_pending()) {

tests/thread/stress_schedule.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# This test ensures that the scheduler doesn't trigger any assertions
2+
# while dealing with concurrent access from multiple threads.
3+
4+
import _thread
5+
import utime
6+
import micropython
7+
import gc
8+
9+
try:
10+
micropython.schedule
11+
except AttributeError:
12+
print("SKIP")
13+
raise SystemExit
14+
15+
gc.disable()
16+
17+
n = 0 # How many times the task successfully ran.
18+
19+
20+
def task(x):
21+
global n
22+
n += 1
23+
24+
25+
def thread():
26+
while True:
27+
try:
28+
micropython.schedule(task, None)
29+
except RuntimeError:
30+
# Queue full, back off.
31+
utime.sleep_ms(10)
32+
33+
34+
for i in range(8):
35+
_thread.start_new_thread(thread, ())
36+
37+
_NUM_TASKS = const(10000)
38+
_TIMEOUT_MS = const(10000)
39+
40+
# Wait up to 10 seconds for 10000 tasks to be scheduled.
41+
t = utime.ticks_ms()
42+
while n < _NUM_TASKS and utime.ticks_diff(utime.ticks_ms(), t) < _TIMEOUT_MS:
43+
pass
44+
45+
if n < _NUM_TASKS:
46+
# Not all the tasks were scheduled, likely the scheduler stopped working.
47+
print(n)
48+
else:
49+
print("PASS")
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
PASS

0 commit comments

Comments
 (0)