From 91f80d69d68d26dd168d66b0ef0c644b45c5fa44 Mon Sep 17 00:00:00 2001 From: Paul Guyot Date: Tue, 31 Oct 2023 07:49:15 +0100 Subject: [PATCH] Fix sys_poll/enqueue SMP logic on Pico Fix a bug where sys_poll_events would return immediately if there is nothing to do. Also extend this wait logic on non-SMP builds as we now process interrupts and queued elements should wake up the scheduler. Also fix a concurrency bug with enqueue where a message could not be processed until the scheduler is woken by something else. Signed-off-by: Paul Guyot --- src/platforms/rp2040/src/lib/sys.c | 37 ++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/src/platforms/rp2040/src/lib/sys.c b/src/platforms/rp2040/src/lib/sys.c index 842b51371..433d19822 100644 --- a/src/platforms/rp2040/src/lib/sys.c +++ b/src/platforms/rp2040/src/lib/sys.c @@ -100,10 +100,37 @@ bool sys_try_post_listener_event_from_isr(GlobalContext *glb, listener_event_t l return false; } +#ifndef AVM_NO_SMP + uint32_t owner; + bool acquired_mutex = mutex_try_enter(&platform->event_poll_mutex, &owner); + // We're from an ISR, so we cannot wait for the interrupted code (running + // on the same core as we do) to release the mutex. + if (!acquired_mutex) { + // If this core is not the owner, wait for the other core to release + // the mutex. + // TODO: implement queue_try_remove_wait_timeout_ms in Pico SDK to + // simplify this logic + uint32_t caller = (uint32_t) lock_get_caller_owner_id(); // same cast exists in mutex_try_enter + if (caller != owner) { + mutex_enter_blocking(&platform->event_poll_mutex); + acquired_mutex = true; + } + } +#endif if (UNLIKELY(!queue_try_add(&platform->event_queue, &listener_queue))) { +#ifndef AVM_NO_SMP + if (acquired_mutex) { + mutex_exit(&platform->event_poll_mutex); + } +#endif fprintf(stderr, "Lost event from ISR as global event queue is full. System is overloaded or EVENT_QUEUE_LEN is too low\n"); return false; } +#ifndef AVM_NO_SMP + if (acquired_mutex) { + mutex_exit(&platform->event_poll_mutex); + } +#endif #ifndef AVM_NO_SMP sys_signal(glb); @@ -116,9 +143,15 @@ void sys_poll_events(GlobalContext *glb, int timeout_ms) { struct RP2040PlatformData *platform = glb->platform_data; #ifndef AVM_NO_SMP - if (timeout_ms > 0) { + if (timeout_ms != 0) { mutex_enter_blocking(&platform->event_poll_mutex); - cond_wait_timeout_ms(&platform->event_poll_cond, &platform->event_poll_mutex, timeout_ms); + if (queue_is_empty(&platform->event_queue)) { + if (timeout_ms > 0) { + cond_wait_timeout_ms(&platform->event_poll_cond, &platform->event_poll_mutex, timeout_ms); + } else { + cond_wait(&platform->event_poll_cond, &platform->event_poll_mutex); + } + } mutex_exit(&platform->event_poll_mutex); } #endif