summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ports/rp2/main.c1
-rw-r--r--ports/rp2/pendsv.c32
-rw-r--r--ports/rp2/pendsv.h1
3 files changed, 27 insertions, 7 deletions
diff --git a/ports/rp2/main.c b/ports/rp2/main.c
index 668017668..5fb47cc40 100644
--- a/ports/rp2/main.c
+++ b/ports/rp2/main.c
@@ -76,6 +76,7 @@ int main(int argc, char **argv) {
// This is a tickless port, interrupts should always trigger SEV.
SCB->SCR |= SCB_SCR_SEVONPEND_Msk;
+ pendsv_init();
soft_timer_init();
#if MICROPY_HW_ENABLE_UART_REPL
diff --git a/ports/rp2/pendsv.c b/ports/rp2/pendsv.c
index e4f662715..d24b4cb01 100644
--- a/ports/rp2/pendsv.c
+++ b/ports/rp2/pendsv.c
@@ -25,6 +25,7 @@
*/
#include <assert.h>
+#include "pico/mutex.h"
#include "py/mpconfig.h"
#include "pendsv.h"
#include "RP2040.h"
@@ -34,15 +35,21 @@
#endif
static pendsv_dispatch_t pendsv_dispatch_table[PENDSV_DISPATCH_NUM_SLOTS];
-static int pendsv_lock;
+static recursive_mutex_t pendsv_mutex;
+
+void pendsv_init(void) {
+ recursive_mutex_init(&pendsv_mutex);
+}
void pendsv_suspend(void) {
- pendsv_lock++;
+ // Recursive Mutex here as either core may call pendsv_suspend() and expect
+ // both mutual exclusion (other core can't enter pendsv_suspend() at the
+ // same time), and that no PendSV handler will run.
+ recursive_mutex_enter_blocking(&pendsv_mutex);
}
void pendsv_resume(void) {
- pendsv_lock--;
- assert(pendsv_lock >= 0);
+ recursive_mutex_exit(&pendsv_mutex);
// Run pendsv if needed. Find an entry with a dispatch and call pendsv dispatch
// with it. If pendsv runs it will service all slots.
int count = PENDSV_DISPATCH_NUM_SLOTS;
@@ -55,9 +62,11 @@ void pendsv_resume(void) {
}
void pendsv_schedule_dispatch(size_t slot, pendsv_dispatch_t f) {
- assert(pendsv_lock >= 0);
pendsv_dispatch_table[slot] = f;
- if (pendsv_lock == 0) {
+ if (pendsv_mutex.enter_count == 0) {
+ // There is a race here where other core calls pendsv_suspend() before
+ // ISR can execute, but dispatch will happen later when other core
+ // calls pendsv_resume().
SCB->ICSR = SCB_ICSR_PENDSVSET_Msk;
} else {
#if MICROPY_PY_NETWORK_CYW43
@@ -68,7 +77,14 @@ void pendsv_schedule_dispatch(size_t slot, pendsv_dispatch_t f) {
// PendSV interrupt handler to perform background processing.
void PendSV_Handler(void) {
- assert(pendsv_lock == 0);
+
+ if (!recursive_mutex_try_enter(&pendsv_mutex, NULL)) {
+ // Failure here means core 1 holds pendsv_mutex. ISR will
+ // run again after core 1 calls pendsv_resume().
+ return;
+ }
+ // Core 0 should not already have locked pendsv_mutex
+ assert(pensv_mutex.enter_count == 1);
#if MICROPY_PY_NETWORK_CYW43
CYW43_STAT_INC(PENDSV_RUN_COUNT);
@@ -81,4 +97,6 @@ void PendSV_Handler(void) {
f();
}
}
+
+ recursive_mutex_exit(&pendsv_mutex);
}
diff --git a/ports/rp2/pendsv.h b/ports/rp2/pendsv.h
index c9bdb2763..a5d944021 100644
--- a/ports/rp2/pendsv.h
+++ b/ports/rp2/pendsv.h
@@ -47,6 +47,7 @@ enum {
typedef void (*pendsv_dispatch_t)(void);
+void pendsv_init(void);
void pendsv_suspend(void);
void pendsv_resume(void);
void pendsv_schedule_dispatch(size_t slot, pendsv_dispatch_t f);