Skip to content

Commit 3af006e

Browse files
projectgusdpgeorge
authored andcommitted
rp2: Support calling pendsv_suspend/resume from core 1.
Previously, this was subject to races incrementing/decrementing the counter variable pendsv_lock. Technically, all that's needed here would be to make pendsv_lock an atomic counter. This implementation fulfils a stronger guarantee: it also provides mutual exclusion for the core which calls pendsv_suspend(). This is because the current use of pendsv_suspend/resume in MicroPython is to ensure exclusive access to softtimer data structures, and this does require mutual exclusion. The conceptually cleaner implementation would split the mutual exclusion part out into a softtimer-specific spinlock, but this increases the complexity and doesn't seem like it makes for a better implementation in the long run. This work was funded through GitHub Sponsors. Signed-off-by: Angus Gratton <angus@redyak.com.au>
1 parent 83e82c5 commit 3af006e

File tree

3 files changed

+27
-7
lines changed

3 files changed

+27
-7
lines changed

ports/rp2/main.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ int main(int argc, char **argv) {
7676
// This is a tickless port, interrupts should always trigger SEV.
7777
SCB->SCR |= SCB_SCR_SEVONPEND_Msk;
7878

79+
pendsv_init();
7980
soft_timer_init();
8081

8182
#if MICROPY_HW_ENABLE_UART_REPL

ports/rp2/pendsv.c

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
*/
2626

2727
#include <assert.h>
28+
#include "pico/mutex.h"
2829
#include "py/mpconfig.h"
2930
#include "pendsv.h"
3031
#include "RP2040.h"
@@ -34,15 +35,21 @@
3435
#endif
3536

3637
static pendsv_dispatch_t pendsv_dispatch_table[PENDSV_DISPATCH_NUM_SLOTS];
37-
static int pendsv_lock;
38+
static recursive_mutex_t pendsv_mutex;
39+
40+
void pendsv_init(void) {
41+
recursive_mutex_init(&pendsv_mutex);
42+
}
3843

3944
void pendsv_suspend(void) {
40-
pendsv_lock++;
45+
// Recursive Mutex here as either core may call pendsv_suspend() and expect
46+
// both mutual exclusion (other core can't enter pendsv_suspend() at the
47+
// same time), and that no PendSV handler will run.
48+
recursive_mutex_enter_blocking(&pendsv_mutex);
4149
}
4250

4351
void pendsv_resume(void) {
44-
pendsv_lock--;
45-
assert(pendsv_lock >= 0);
52+
recursive_mutex_exit(&pendsv_mutex);
4653
// Run pendsv if needed. Find an entry with a dispatch and call pendsv dispatch
4754
// with it. If pendsv runs it will service all slots.
4855
int count = PENDSV_DISPATCH_NUM_SLOTS;
@@ -55,9 +62,11 @@ void pendsv_resume(void) {
5562
}
5663

5764
void pendsv_schedule_dispatch(size_t slot, pendsv_dispatch_t f) {
58-
assert(pendsv_lock >= 0);
5965
pendsv_dispatch_table[slot] = f;
60-
if (pendsv_lock == 0) {
66+
if (pendsv_mutex.enter_count == 0) {
67+
// There is a race here where other core calls pendsv_suspend() before
68+
// ISR can execute, but dispatch will happen later when other core
69+
// calls pendsv_resume().
6170
SCB->ICSR = SCB_ICSR_PENDSVSET_Msk;
6271
} else {
6372
#if MICROPY_PY_NETWORK_CYW43
@@ -68,7 +77,14 @@ void pendsv_schedule_dispatch(size_t slot, pendsv_dispatch_t f) {
6877

6978
// PendSV interrupt handler to perform background processing.
7079
void PendSV_Handler(void) {
71-
assert(pendsv_lock == 0);
80+
81+
if (!recursive_mutex_try_enter(&pendsv_mutex, NULL)) {
82+
// Failure here means core 1 holds pendsv_mutex. ISR will
83+
// run again after core 1 calls pendsv_resume().
84+
return;
85+
}
86+
// Core 0 should not already have locked pendsv_mutex
87+
assert(pensv_mutex.enter_count == 1);
7288

7389
#if MICROPY_PY_NETWORK_CYW43
7490
CYW43_STAT_INC(PENDSV_RUN_COUNT);
@@ -81,4 +97,6 @@ void PendSV_Handler(void) {
8197
f();
8298
}
8399
}
100+
101+
recursive_mutex_exit(&pendsv_mutex);
84102
}

ports/rp2/pendsv.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ enum {
4747

4848
typedef void (*pendsv_dispatch_t)(void);
4949

50+
void pendsv_init(void);
5051
void pendsv_suspend(void);
5152
void pendsv_resume(void);
5253
void pendsv_schedule_dispatch(size_t slot, pendsv_dispatch_t f);

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy