Strange behavior on RP2350 with mutexes and alarms #2706

Closed
opened 2025-10-20 20:34:28 -05:00 by writeonlymemory · 3 comments
writeonlymemory commented 2025-10-20 20:34:28 -05:00 (Migrated from github.com)

Hello,

I have been having some trouble with some code that makes use of mutexes to protect a data structure shared between core 0 and core 1 on the RP2350 [but the code works fine on the RP2040]. SDK version is 2.2.0.

[Note: after filing this issue I noticed that I was building with -O2 -- the problem seems to go away with optimizations turned off.]

The minimal [silly] program below demonstrates the behavior. If executed on an RP2040 [or an RP2350 with PICO_USE_SW_SPIN_LOCKS=0] the program runs as I expect with "Core 1 frames" printing and climbing at a regular cadence of ~2-3/second. There's no obvious change in anything after the timer expires.

If it is run on RP2350 with PICO_USE_SW_SPIN_LOCKS=1 [the default], the program does not advance usefully until after the timer expires - maybe 1-3 "frames" lines will be output - then the timer expires and the program advances as normal at the expected cadence of output.

Removing the add_alarm_in_ms(5000, ... call makes things proceed normally [no stall on the rp2350].

Adding a second periodic timer on a short interval [say 50ms] also seems to make things work as expected [even with USE_SW_SPIN_LOCKS=1].

Thanks for any insight and sorry if I'm missing something obvious...

#include <stdio.h>

#include <pico/multicore.h>
#include <pico/stdlib.h>
#include <pico/sync.h>
#include <pico/time.h>

#define N 1000000

auto_init_mutex(lock);

static uint32_t core1_frames = 0;

void core1_entry() {
  for (;;) {
    if (!mutex_enter_timeout_ms(&lock, 500)) {
      continue;
    }
    core1_frames++;
    for (volatile int i = 0; i < N; ++i);
    mutex_exit(&lock);
    sleep_ms(10);
  }
}

int64_t do_nothing(alarm_id_t, void*) { return 0; }

void main() {
  stdio_init_all();
  sleep_ms(5000); // just wait for USB

  printf("Starting test\n");

  multicore_launch_core1(core1_entry);

  add_alarm_in_ms(5000, do_nothing, NULL, true);

  for (;;) {
    mutex_enter_blocking(&lock);
    uint32_t current = core1_frames;
    for (volatile int i = 0; i < N; ++i);
    mutex_exit(&lock);
    printf("Core 1 Frames: %u\n", current);
    sleep_ms(10);
  }
}
Hello, I have been having some trouble with some code that makes use of mutexes to protect a data structure shared between core 0 and core 1 on the RP2350 [but the code works fine on the RP2040]. SDK version is 2.2.0. [**Note:** after filing this issue I noticed that I was building with `-O2` -- the problem seems to go away with optimizations turned off.] The minimal [silly] program below demonstrates the behavior. If executed on an RP2040 [or an RP2350 with PICO_USE_SW_SPIN_LOCKS=0] the program runs as I expect with "Core 1 frames" printing and climbing at a regular cadence of ~2-3/second. There's no obvious change in anything after the timer expires. If it is run on RP2350 with PICO_USE_SW_SPIN_LOCKS=1 [the default], the program does not advance usefully until after the timer expires - maybe 1-3 "frames" lines will be output - then the timer expires and the program advances as normal at the expected cadence of output. Removing the `add_alarm_in_ms(5000, ...` call makes things proceed normally [no stall on the rp2350]. Adding a second periodic timer on a short interval [say 50ms] also seems to make things work as expected [even with USE_SW_SPIN_LOCKS=1]. Thanks for any insight and sorry if I'm missing something obvious... ``` #include <stdio.h> #include <pico/multicore.h> #include <pico/stdlib.h> #include <pico/sync.h> #include <pico/time.h> #define N 1000000 auto_init_mutex(lock); static uint32_t core1_frames = 0; void core1_entry() { for (;;) { if (!mutex_enter_timeout_ms(&lock, 500)) { continue; } core1_frames++; for (volatile int i = 0; i < N; ++i); mutex_exit(&lock); sleep_ms(10); } } int64_t do_nothing(alarm_id_t, void*) { return 0; } void main() { stdio_init_all(); sleep_ms(5000); // just wait for USB printf("Starting test\n"); multicore_launch_core1(core1_entry); add_alarm_in_ms(5000, do_nothing, NULL, true); for (;;) { mutex_enter_blocking(&lock); uint32_t current = core1_frames; for (volatile int i = 0; i < N; ++i); mutex_exit(&lock); printf("Core 1 Frames: %u\n", current); sleep_ms(10); } } ```
writeonlymemory commented 2025-10-20 21:15:46 -05:00 (Migrated from github.com)

CMakeLists.txt for reference

cmake_minimum_required(VERSION 3.17)

unset(ENV{PICO_SDK_PATH})
set(PICO_SDK_FETCH_FROM_GIT_TAG "2.2.0")
set(PICO_SDK_FETCH_FROM_GIT TRUE)

include(pico_sdk_import.cmake)

project(locktest)

pico_sdk_init()

add_compile_options(-O2)

#add_compile_options(-DPICO_USE_SW_SPIN_LOCKS=0)
  
add_executable(locktest main.c)

target_link_libraries(locktest
  pico_stdlib
  pico_multicore
)

pico_add_extra_outputs(locktest)

pico_enable_stdio_usb(locktest TRUE)
CMakeLists.txt for reference ``` cmake_minimum_required(VERSION 3.17) unset(ENV{PICO_SDK_PATH}) set(PICO_SDK_FETCH_FROM_GIT_TAG "2.2.0") set(PICO_SDK_FETCH_FROM_GIT TRUE) include(pico_sdk_import.cmake) project(locktest) pico_sdk_init() add_compile_options(-O2) #add_compile_options(-DPICO_USE_SW_SPIN_LOCKS=0) add_executable(locktest main.c) target_link_libraries(locktest pico_stdlib pico_multicore ) pico_add_extra_outputs(locktest) pico_enable_stdio_usb(locktest TRUE) ```
geurtv commented 2026-01-28 03:42:26 -06:00 (Migrated from github.com)

I think I have a similar problem, which remains when implementing spinlocks using "proper c++ atomics". The problem goes away when I compile with PICO_SW_SPIN_LOCKS_NO_EXTEXCLALL=1. Then also your example seems to work correctly (also with -O3):

add_compile_options(-DPICO_SW_SPIN_LOCKS_NO_EXTEXCLALL=1)

I, however, don't know if exclusive access for atomics now still works properly or even at all (see sync_spin_lock.c in pico-sdk). There doesn't seem to be any actual documentation on PICO_SW_SPIN_LOCKS_NO_EXTEXCLALL except for the comments in spinlock_set_extexclall().

I think I have a similar problem, which remains when implementing spinlocks using "proper c++ atomics". The problem goes away when I compile with `PICO_SW_SPIN_LOCKS_NO_EXTEXCLALL=1`. Then also your example seems to work correctly (also with -O3): `add_compile_options(-DPICO_SW_SPIN_LOCKS_NO_EXTEXCLALL=1)` I, however, don't know if exclusive access for atomics now still works properly or even at all (see sync_spin_lock.c in pico-sdk). There doesn't seem to be any actual documentation on `PICO_SW_SPIN_LOCKS_NO_EXTEXCLALL` except for the comments in `spinlock_set_extexclall()`.
kilograham commented 2026-06-29 12:14:49 -05:00 (Migrated from github.com)

fix merged into develop

fix merged into develop
Sign in to join this conversation.
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
gh-raspberrypi/pico-sdk#2706
No description provided.