Skip to content

Commit 16bab9c

Browse files
committed
Fix a concurrency issue yielding a timeout bug
Ensure that `scheduler_make_ready` and `scheduler_set_timeout` calls `sys_signal`. As `global->waiting_scheduler` was cached or read without holding `global->schedulers_mutex`, in some cases `sys_signal` was not called yielding a timeout bug where a message is in the queue but the process is not awaken. Signed-off-by: Paul Guyot <pguyot@kallisys.net>
1 parent 49c37fd commit 16bab9c

File tree

1 file changed

+20
-12
lines changed

1 file changed

+20
-12
lines changed

src/libAtomVM/scheduler.c

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -305,18 +305,16 @@ static void scheduler_make_ready(Context *ctx)
305305
}
306306
list_remove(&ctx->processes_list_head);
307307
#ifndef AVM_NO_SMP
308-
bool waiting_scheduler = global->waiting_scheduler;
309-
if (!waiting_scheduler) {
308+
if (SMP_MUTEX_TRYLOCK(global->schedulers_mutex)) {
310309
// Start a new scheduler if none are going to take this process.
311-
if (SMP_MUTEX_TRYLOCK(global->schedulers_mutex)) {
312-
if (global->running_schedulers > 0
313-
&& global->running_schedulers < global->online_schedulers
314-
&& !context_get_flags(ctx, Running)) {
315-
global->running_schedulers++;
316-
smp_scheduler_start(global);
317-
}
318-
SMP_MUTEX_UNLOCK(global->schedulers_mutex);
310+
if (!global->waiting_scheduler
311+
&& global->running_schedulers > 0
312+
&& global->running_schedulers < global->online_schedulers
313+
&& !context_get_flags(ctx, Running)) {
314+
global->running_schedulers++;
315+
smp_scheduler_start(global);
319316
}
317+
SMP_MUTEX_UNLOCK(global->schedulers_mutex);
320318
}
321319
#endif
322320
// Move to ready queue (from waiting or running)
@@ -326,7 +324,12 @@ static void scheduler_make_ready(Context *ctx)
326324
list_append(&global->ready_processes, &ctx->processes_list_head);
327325
SMP_SPINLOCK_UNLOCK(&global->processes_spinlock);
328326
#ifndef AVM_NO_SMP
329-
if (waiting_scheduler) {
327+
if (SMP_MUTEX_TRYLOCK(global->schedulers_mutex)) {
328+
if (global->waiting_scheduler) {
329+
sys_signal(global);
330+
}
331+
SMP_MUTEX_UNLOCK(global->schedulers_mutex);
332+
} else {
330333
sys_signal(global);
331334
}
332335
#elif defined(AVM_TASK_DRIVER_ENABLED)
@@ -410,7 +413,12 @@ void scheduler_set_timeout(Context *ctx, avm_int64_t timeout)
410413
SMP_SPINLOCK_UNLOCK(&glb->timer_spinlock);
411414

412415
#ifndef AVM_NO_SMP
413-
if (glb->waiting_scheduler) {
416+
if (SMP_MUTEX_TRYLOCK(glb->schedulers_mutex)) {
417+
if (glb->waiting_scheduler) {
418+
sys_signal(glb);
419+
}
420+
SMP_MUTEX_UNLOCK(glb->schedulers_mutex);
421+
} else {
414422
sys_signal(glb);
415423
}
416424
#elif defined(AVM_TASK_DRIVER_ENABLED)

0 commit comments

Comments
 (0)