aboutsummaryrefslogtreecommitdiff
path: root/py/vm.c
diff options
context:
space:
mode:
authorJim Mussared <jim.mussared@gmail.com>2020-04-03 14:15:18 +1100
committerDamien George <damien.p.george@gmail.com>2020-04-13 21:55:47 +1000
commit243805d776a19b16545d542b2f51ae88b6e314fe (patch)
tree939e150defb51389c670ba20585876f32947dca3 /py/vm.c
parentc2cfbcc8d491d225cddbce71de5052ba8048c121 (diff)
py/scheduler: Fix race in checking scheduler pending state.
Because the atomic section starts after checking whether the scheduler state is pending, it's possible it can become a different state by the time the atomic section starts. This is especially likely on ports where MICROPY_BEGIN_ATOMIC_SECTION is implemented with a mutex (i.e. it might block), but the race exists regardless, i.e. if a context switch occurs between those two lines.
Diffstat (limited to 'py/vm.c')
-rw-r--r--py/vm.c21
1 files changed, 13 insertions, 8 deletions
diff --git a/py/vm.c b/py/vm.c
index cd2cd347f..f30aed8ff 100644
--- a/py/vm.c
+++ b/py/vm.c
@@ -1366,18 +1366,23 @@ pending_exception_check:
#if MICROPY_ENABLE_SCHEDULER
// This is an inlined variant of mp_handle_pending
if (MP_STATE_VM(sched_state) == MP_SCHED_PENDING) {
- MARK_EXC_IP_SELECTIVE();
mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION();
- mp_obj_t obj = MP_STATE_VM(mp_pending_exception);
- if (obj != MP_OBJ_NULL) {
- MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL;
- if (!mp_sched_num_pending()) {
- MP_STATE_VM(sched_state) = MP_SCHED_IDLE;
+ // Re-check state is still pending now that we're in the atomic section.
+ if (MP_STATE_VM(sched_state) == MP_SCHED_PENDING) {
+ MARK_EXC_IP_SELECTIVE();
+ mp_obj_t obj = MP_STATE_VM(mp_pending_exception);
+ if (obj != MP_OBJ_NULL) {
+ MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL;
+ if (!mp_sched_num_pending()) {
+ MP_STATE_VM(sched_state) = MP_SCHED_IDLE;
+ }
+ MICROPY_END_ATOMIC_SECTION(atomic_state);
+ RAISE(obj);
}
+ mp_handle_pending_tail(atomic_state);
+ } else {
MICROPY_END_ATOMIC_SECTION(atomic_state);
- RAISE(obj);
}
- mp_handle_pending_tail(atomic_state);
}
#else
// This is an inlined variant of mp_handle_pending