From 9d2a3d20f221dbd8149783077a129769904d2dd1 Mon Sep 17 00:00:00 2001 From: Samuel Berkun Date: Thu, 1 Feb 2024 01:18:19 -0800 Subject: [PATCH 01/13] initial draft for multithreaded rp2040 --- core/CMakeLists.txt | 6 + .../api/platform/lf_rp2040_support.h | 37 ++++ .../impl/src/lf_rp2040_support.c | 176 +++++++++++++++++- 3 files changed, 215 insertions(+), 4 deletions(-) diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index ca51fd50c..b3bc26906 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -135,6 +135,12 @@ if (NOT DEFINED INITIAL_EVENT_QUEUE_SIZE) endif() if (NOT DEFINED INITIAL_REACT_QUEUE_SIZE) set(INITIAL_REACT_QUEUE_SIZE 10) +# Link with thread library, unless we are on the Zephyr platform. +if(NOT DEFINED LF_SINGLE_THREADED OR DEFINED LF_TRACE) + if (NOT (PLATFORM_ZEPHYR OR ${CMAKE_SYSTEM_NAME} STREQUAL "Rp2040")) + find_package(Threads REQUIRED) + target_link_libraries(reactor-c PUBLIC Threads::Threads) + endif() endif() target_compile_definitions(reactor-c PRIVATE INITIAL_EVENT_QUEUE_SIZE=${INITIAL_EVENT_QUEUE_SIZE}) diff --git a/low_level_platform/api/platform/lf_rp2040_support.h b/low_level_platform/api/platform/lf_rp2040_support.h index 670f7afb4..c3384a2dc 100644 --- a/low_level_platform/api/platform/lf_rp2040_support.h +++ b/low_level_platform/api/platform/lf_rp2040_support.h @@ -21,4 +21,41 @@ #define LF_TIME_BUFFER_LENGTH 80 #define _LF_TIMEOUT 1 +#ifndef LF_SINGLE_THREADED +#warning "Threaded support on rp2040 is still experimental" + +typedef mutex_t lf_mutex_t; +typedef struct { + semaphore_t sema; + mutex_t* mutex; +} lf_cond_t; +typedef int lf_thread_t; + + +/** + * @brief Add `value` to `*ptr` and return original value of `*ptr` + */ +int _rp2040_atomic_fetch_add(int *ptr, int value); +/** + * @brief Add `value` to `*ptr` and return new updated value of `*ptr` + */ +int _rp2040_atomic_add_fetch(int *ptr, int value); + +/** + * @brief Compare and swap for boolaen value. + * If `*ptr` is equal to `value` then overwrite it + * with `newval`. If not do nothing. Retruns true on overwrite. + */ +bool _rp2040_bool_compare_and_swap(bool *ptr, bool value, bool newval); + +/** + * @brief Compare and swap for integers. If `*ptr` is equal + * to `value`, it is updated to `newval`. The function returns + * the original value of `*ptr`. + */ +int _rp2040_val_compare_and_swap(int *ptr, int value, int newval); + + +#endif // LF_THREADED + #endif // LF_PICO_SUPPORT_H diff --git a/low_level_platform/impl/src/lf_rp2040_support.c b/low_level_platform/impl/src/lf_rp2040_support.c index 88940dd94..a0a78314a 100644 --- a/low_level_platform/impl/src/lf_rp2040_support.c +++ b/low_level_platform/impl/src/lf_rp2040_support.c @@ -31,9 +31,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * @author{Abhi Gundrala } */ -#if !defined(LF_SINGLE_THREADED) -#error "Only the single-threaded runtime has support for RP2040" -#endif + #include "platform/lf_rp2040_support.h" #include "low_level_platform.h" @@ -51,6 +49,11 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ static critical_section_t _lf_crit_sec; +/** + * critical section struct for atomics implementation + */ +static critical_section_t _lf_atomics_crit_sec; + /** * binary semaphore for lf event notification * used by external isr or second core thread. @@ -70,6 +73,7 @@ void _lf_initialize_clock(void) { stdio_init_all(); // init sync structs critical_section_init(&_lf_crit_sec); + critical_section_init(&_lf_atomics_crit_sec); sem_init(&_lf_sem_irq_event, 0, 1); } @@ -161,7 +165,7 @@ int lf_disable_interrupts_nested() { return 1; } // check crit sec count - // enter non-rentrant state by disabling interrupts + // enter non-reentrant state by disabling interrupts // lock second core execution if (_lf_num_nested_crit_sec == 0) { // block if associated spin lock in use @@ -205,6 +209,170 @@ int _lf_single_threaded_notify_of_event() { sem_release(&_lf_sem_irq_event); return 0; } + +#else // LF_SINGLE_THREADED + +#warning "Threaded runtime on RP2040 is still experimental" + +/** + * @brief Get the number of cores on the host machine. + */ +int lf_available_cores() { + // Right now, runtime creates 1 main thread and 1 worker thread + // In the future, this may be changed to 2 (if main thread also functions + // as a worker thread) + return 1; +} + +static void *(*thread_1) (void *); +static void* thread_1_args; +static int num_create_threads_called = 0; +static semaphore_t thread_1_done; +static void* thread_1_return; + +#define MAGIC_THREAD1_ID 314159 + +void core1_entry() { + thread_1_return = thread_1(thread_1_args); + sem_release(&thread_1_done); + + // infinite loop; core1 should never exit + while (1){ + tight_loop_contents(); + } +} + +int lf_thread_create(lf_thread_t* thread, void *(*lf_thread) (void *), void* arguments) { + // make sure this fn is only called once + if (num_create_threads_called != 0) { + return 1; + } + thread_1 = lf_thread; + thread_1_args = arguments; + num_create_threads_called += 1; + sem_init(&thread_1_done, 0, 1); + multicore_launch_core1(core1_entry); + *thread = MAGIC_THREAD1_ID; + return 0; +} + +int lf_thread_join(lf_thread_t thread, void** thread_return) { + if (thread != MAGIC_THREAD1_ID) { + return 1; + } + sem_acquire_blocking(&thread_1_done); + sem_release(&thread_1_done); // in case join is called again + if (thread_return) { + *thread_return = thread_1_return; + } + return 0; +} + +int lf_mutex_init(lf_mutex_t* mutex) { + mutex_init(mutex); + return 0; +} + +int lf_mutex_lock(lf_mutex_t* mutex) { + mutex_enter_blocking(mutex); + return 0; +} + +int lf_mutex_unlock(lf_mutex_t* mutex) { + mutex_exit(mutex); + return 0; +} + +int lf_cond_init(lf_cond_t* cond, lf_mutex_t* mutex) { + sem_init(&(cond->sema), 0, 1); + cond->mutex = mutex; + return 0; +} + +int lf_cond_broadcast(lf_cond_t* cond) { + sem_reset(&(cond->sema), 1); + return 0; +} + +int lf_cond_signal(lf_cond_t* cond) { + sem_reset(&(cond->sema), 1); + return 0; +} + +int lf_cond_wait(lf_cond_t* cond) { + mutex_exit(cond->mutex); + sem_acquire_blocking(&(cond->sema)); + mutex_enter_blocking(cond->mutex); + return 0; +} + +int lf_cond_timedwait(lf_cond_t* cond, instant_t absolute_time_ns) { + absolute_time_t a = from_us_since_boot(absolute_time_ns / 1000); + bool acquired_permit = sem_acquire_block_until(&(cond->sema), a); + return acquired_permit ? 0 : LF_TIMEOUT; +} + + +// Atomics +// Implemented by just entering a critical section and doing the arithmetic. +// This is somewhat inefficient considering enclaves. Since we get a critical +// section in between different enclaves + + +/** + * @brief Add `value` to `*ptr` and return original value of `*ptr` + */ +int _rp2040_atomic_fetch_add(int *ptr, int value) { + critical_section_enter_blocking(&_lf_atomics_crit_sec); + int res = *ptr; + *ptr += value; + critical_section_exit(&_lf_atomics_crit_sec); + return res; +} +/** + * @brief Add `value` to `*ptr` and return new updated value of `*ptr` + */ +int _rp2040_atomic_add_fetch(int *ptr, int value) { + critical_section_enter_blocking(&_lf_atomics_crit_sec); + int res = *ptr + value; + *ptr = res; + critical_section_exit(&_lf_atomics_crit_sec); + return res; +} + +/** + * @brief Compare and swap for boolean value. + * If `*ptr` is equal to `value` then overwrite it + * with `newval`. If not do nothing. Returns true on overwrite. + */ +bool _rp2040_bool_compare_and_swap(bool *ptr, bool value, bool newval) { + critical_section_enter_blocking(&_lf_atomics_crit_sec); + bool res = false; + if (*ptr == value) { + *ptr = newval; + res = true; + } + critical_section_exit(&_lf_atomics_crit_sec); + return res; +} + +/** + * @brief Compare and swap for integers. If `*ptr` is equal + * to `value`, it is updated to `newval`. The function returns + * the original value of `*ptr`. + */ +int _rp2040_val_compare_and_swap(int *ptr, int value, int newval) { + critical_section_enter_blocking(&_lf_atomics_crit_sec); + int res = *ptr; + if (*ptr == value) { + *ptr = newval; + } + critical_section_exit(&_lf_atomics_crit_sec); + return res; +} + + + #endif // LF_SINGLE_THREADED #endif // PLATFORM_RP2040 From 7784f3ddfe56c4dda322d8bcf0d30e54ac55abe4 Mon Sep 17 00:00:00 2001 From: Samuel Berkun Date: Thu, 1 Feb 2024 12:17:10 -0800 Subject: [PATCH 02/13] add PLATFORM_RP2040 cmake variable --- core/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index b3bc26906..8c9f445ca 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -137,7 +137,7 @@ if (NOT DEFINED INITIAL_REACT_QUEUE_SIZE) set(INITIAL_REACT_QUEUE_SIZE 10) # Link with thread library, unless we are on the Zephyr platform. if(NOT DEFINED LF_SINGLE_THREADED OR DEFINED LF_TRACE) - if (NOT (PLATFORM_ZEPHYR OR ${CMAKE_SYSTEM_NAME} STREQUAL "Rp2040")) + if (NOT (PLATFORM_ZEPHYR OR PLATFORM_RP2040)) find_package(Threads REQUIRED) target_link_libraries(reactor-c PUBLIC Threads::Threads) endif() From 754c5d0f834aa7aa690ced19c380f21c84228405 Mon Sep 17 00:00:00 2001 From: Samuel Berkun Date: Sat, 3 Feb 2024 02:14:34 -0800 Subject: [PATCH 03/13] allow core 1 to sleep --- low_level_platform/impl/src/lf_rp2040_support.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/low_level_platform/impl/src/lf_rp2040_support.c b/low_level_platform/impl/src/lf_rp2040_support.c index a0a78314a..2d2ba0550 100644 --- a/low_level_platform/impl/src/lf_rp2040_support.c +++ b/low_level_platform/impl/src/lf_rp2040_support.c @@ -235,11 +235,6 @@ static void* thread_1_return; void core1_entry() { thread_1_return = thread_1(thread_1_args); sem_release(&thread_1_done); - - // infinite loop; core1 should never exit - while (1){ - tight_loop_contents(); - } } int lf_thread_create(lf_thread_t* thread, void *(*lf_thread) (void *), void* arguments) { From 488afddcf0d69752539c512c75421585509c41cb Mon Sep 17 00:00:00 2001 From: Samuel Berkun Date: Tue, 6 Feb 2024 00:41:42 -0800 Subject: [PATCH 04/13] mutex to recursive mutex, check return values of sem_release --- .../impl/src/lf_rp2040_support.c | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/low_level_platform/impl/src/lf_rp2040_support.c b/low_level_platform/impl/src/lf_rp2040_support.c index 2d2ba0550..295b06e96 100644 --- a/low_level_platform/impl/src/lf_rp2040_support.c +++ b/low_level_platform/impl/src/lf_rp2040_support.c @@ -70,6 +70,8 @@ static uint32_t _lf_num_nested_crit_sec = 0; */ void _lf_initialize_clock(void) { // init stdio lib + // may fail, but failure may be ok/expected if printing is not needed + // (i.e. if neither USB nor UART are enabled) stdio_init_all(); // init sync structs critical_section_init(&_lf_crit_sec); @@ -206,8 +208,10 @@ int lf_enable_interrupts_nested() { */ int _lf_single_threaded_notify_of_event() { // notify main sleep loop of event - sem_release(&_lf_sem_irq_event); - return 0; + if (sem_release(&_lf_sem_irq_event)) { + return 0; + } + return 1; } #else // LF_SINGLE_THREADED @@ -234,7 +238,7 @@ static void* thread_1_return; void core1_entry() { thread_1_return = thread_1(thread_1_args); - sem_release(&thread_1_done); + sem_reset(&thread_1_done, 1); } int lf_thread_create(lf_thread_t* thread, void *(*lf_thread) (void *), void* arguments) { @@ -253,28 +257,32 @@ int lf_thread_create(lf_thread_t* thread, void *(*lf_thread) (void *), void* arg int lf_thread_join(lf_thread_t thread, void** thread_return) { if (thread != MAGIC_THREAD1_ID) { - return 1; + return 1; } sem_acquire_blocking(&thread_1_done); - sem_release(&thread_1_done); // in case join is called again + // release in case join is called again + if (!sem_release(&thread_1_done)) { + // shouldn't be possible; lf_thread_join is only called from main thread + return 1; + } if (thread_return) { - *thread_return = thread_1_return; + *thread_return = thread_1_return; } return 0; } int lf_mutex_init(lf_mutex_t* mutex) { - mutex_init(mutex); + recursive_mutex_init(mutex); return 0; } int lf_mutex_lock(lf_mutex_t* mutex) { - mutex_enter_blocking(mutex); + recursive_mutex_enter_blocking(mutex); return 0; } int lf_mutex_unlock(lf_mutex_t* mutex) { - mutex_exit(mutex); + recursive_mutex_exit(mutex); return 0; } From bcd8a2bb938268c4208b18fc26cc474e1b4256a5 Mon Sep 17 00:00:00 2001 From: Samuel Berkun Date: Wed, 21 Feb 2024 23:13:02 -0800 Subject: [PATCH 05/13] fixed bug with recursive mutex --- low_level_platform/api/platform/lf_rp2040_support.h | 4 ++-- low_level_platform/impl/src/lf_rp2040_support.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/low_level_platform/api/platform/lf_rp2040_support.h b/low_level_platform/api/platform/lf_rp2040_support.h index c3384a2dc..3687db254 100644 --- a/low_level_platform/api/platform/lf_rp2040_support.h +++ b/low_level_platform/api/platform/lf_rp2040_support.h @@ -24,10 +24,10 @@ #ifndef LF_SINGLE_THREADED #warning "Threaded support on rp2040 is still experimental" -typedef mutex_t lf_mutex_t; +typedef recursive_mutex_t lf_mutex_t; typedef struct { semaphore_t sema; - mutex_t* mutex; + lf_mutex_t* mutex; } lf_cond_t; typedef int lf_thread_t; diff --git a/low_level_platform/impl/src/lf_rp2040_support.c b/low_level_platform/impl/src/lf_rp2040_support.c index 295b06e96..bef9e2a45 100644 --- a/low_level_platform/impl/src/lf_rp2040_support.c +++ b/low_level_platform/impl/src/lf_rp2040_support.c @@ -303,9 +303,9 @@ int lf_cond_signal(lf_cond_t* cond) { } int lf_cond_wait(lf_cond_t* cond) { - mutex_exit(cond->mutex); + lf_mutex_unlock(cond->mutex); sem_acquire_blocking(&(cond->sema)); - mutex_enter_blocking(cond->mutex); + lf_mutex_lock(cond->mutex); return 0; } From 46ed5c83b7afb14497090e48a1b933beb2862560 Mon Sep 17 00:00:00 2001 From: Samuel Berkun Date: Wed, 21 Feb 2024 23:50:37 -0800 Subject: [PATCH 06/13] cleanup; atomics were seperated last week --- .../api/platform/lf_rp2040_support.h | 27 +------- .../impl/src/lf_rp2040_support.c | 67 ------------------- 2 files changed, 1 insertion(+), 93 deletions(-) diff --git a/low_level_platform/api/platform/lf_rp2040_support.h b/low_level_platform/api/platform/lf_rp2040_support.h index 3687db254..10285851e 100644 --- a/low_level_platform/api/platform/lf_rp2040_support.h +++ b/low_level_platform/api/platform/lf_rp2040_support.h @@ -31,31 +31,6 @@ typedef struct { } lf_cond_t; typedef int lf_thread_t; - -/** - * @brief Add `value` to `*ptr` and return original value of `*ptr` - */ -int _rp2040_atomic_fetch_add(int *ptr, int value); -/** - * @brief Add `value` to `*ptr` and return new updated value of `*ptr` - */ -int _rp2040_atomic_add_fetch(int *ptr, int value); - -/** - * @brief Compare and swap for boolaen value. - * If `*ptr` is equal to `value` then overwrite it - * with `newval`. If not do nothing. Retruns true on overwrite. - */ -bool _rp2040_bool_compare_and_swap(bool *ptr, bool value, bool newval); - -/** - * @brief Compare and swap for integers. If `*ptr` is equal - * to `value`, it is updated to `newval`. The function returns - * the original value of `*ptr`. - */ -int _rp2040_val_compare_and_swap(int *ptr, int value, int newval); - - -#endif // LF_THREADED +#endif // LF_SINGLE_THREADED #endif // LF_PICO_SUPPORT_H diff --git a/low_level_platform/impl/src/lf_rp2040_support.c b/low_level_platform/impl/src/lf_rp2040_support.c index bef9e2a45..0751dcd2c 100644 --- a/low_level_platform/impl/src/lf_rp2040_support.c +++ b/low_level_platform/impl/src/lf_rp2040_support.c @@ -49,11 +49,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ static critical_section_t _lf_crit_sec; -/** - * critical section struct for atomics implementation - */ -static critical_section_t _lf_atomics_crit_sec; - /** * binary semaphore for lf event notification * used by external isr or second core thread. @@ -75,7 +70,6 @@ void _lf_initialize_clock(void) { stdio_init_all(); // init sync structs critical_section_init(&_lf_crit_sec); - critical_section_init(&_lf_atomics_crit_sec); sem_init(&_lf_sem_irq_event, 0, 1); } @@ -315,67 +309,6 @@ int lf_cond_timedwait(lf_cond_t* cond, instant_t absolute_time_ns) { return acquired_permit ? 0 : LF_TIMEOUT; } - -// Atomics -// Implemented by just entering a critical section and doing the arithmetic. -// This is somewhat inefficient considering enclaves. Since we get a critical -// section in between different enclaves - - -/** - * @brief Add `value` to `*ptr` and return original value of `*ptr` - */ -int _rp2040_atomic_fetch_add(int *ptr, int value) { - critical_section_enter_blocking(&_lf_atomics_crit_sec); - int res = *ptr; - *ptr += value; - critical_section_exit(&_lf_atomics_crit_sec); - return res; -} -/** - * @brief Add `value` to `*ptr` and return new updated value of `*ptr` - */ -int _rp2040_atomic_add_fetch(int *ptr, int value) { - critical_section_enter_blocking(&_lf_atomics_crit_sec); - int res = *ptr + value; - *ptr = res; - critical_section_exit(&_lf_atomics_crit_sec); - return res; -} - -/** - * @brief Compare and swap for boolean value. - * If `*ptr` is equal to `value` then overwrite it - * with `newval`. If not do nothing. Returns true on overwrite. - */ -bool _rp2040_bool_compare_and_swap(bool *ptr, bool value, bool newval) { - critical_section_enter_blocking(&_lf_atomics_crit_sec); - bool res = false; - if (*ptr == value) { - *ptr = newval; - res = true; - } - critical_section_exit(&_lf_atomics_crit_sec); - return res; -} - -/** - * @brief Compare and swap for integers. If `*ptr` is equal - * to `value`, it is updated to `newval`. The function returns - * the original value of `*ptr`. - */ -int _rp2040_val_compare_and_swap(int *ptr, int value, int newval) { - critical_section_enter_blocking(&_lf_atomics_crit_sec); - int res = *ptr; - if (*ptr == value) { - *ptr = newval; - } - critical_section_exit(&_lf_atomics_crit_sec); - return res; -} - - - #endif // LF_SINGLE_THREADED #endif // PLATFORM_RP2040 From 82f42e1971ead9806732ade53f85223b2ed41f1e Mon Sep 17 00:00:00 2001 From: Samuel Berkun Date: Thu, 22 Feb 2024 00:24:52 -0800 Subject: [PATCH 07/13] rename _lf_cond_timedwait --- low_level_platform/impl/src/lf_rp2040_support.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/low_level_platform/impl/src/lf_rp2040_support.c b/low_level_platform/impl/src/lf_rp2040_support.c index 0751dcd2c..465e16d5c 100644 --- a/low_level_platform/impl/src/lf_rp2040_support.c +++ b/low_level_platform/impl/src/lf_rp2040_support.c @@ -303,7 +303,7 @@ int lf_cond_wait(lf_cond_t* cond) { return 0; } -int lf_cond_timedwait(lf_cond_t* cond, instant_t absolute_time_ns) { +int _lf_cond_timedwait(lf_cond_t* cond, instant_t absolute_time_ns) { absolute_time_t a = from_us_since_boot(absolute_time_ns / 1000); bool acquired_permit = sem_acquire_block_until(&(cond->sema), a); return acquired_permit ? 0 : LF_TIMEOUT; From 5d1f1a3db4205aefc3334df09c8e059239090143 Mon Sep 17 00:00:00 2001 From: Samuel Berkun Date: Sat, 25 May 2024 04:46:33 -0700 Subject: [PATCH 08/13] move thingy --- core/CMakeLists.txt | 6 ------ low_level_platform/impl/CMakeLists.txt | 6 ++++++ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 8c9f445ca..ca51fd50c 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -135,12 +135,6 @@ if (NOT DEFINED INITIAL_EVENT_QUEUE_SIZE) endif() if (NOT DEFINED INITIAL_REACT_QUEUE_SIZE) set(INITIAL_REACT_QUEUE_SIZE 10) -# Link with thread library, unless we are on the Zephyr platform. -if(NOT DEFINED LF_SINGLE_THREADED OR DEFINED LF_TRACE) - if (NOT (PLATFORM_ZEPHYR OR PLATFORM_RP2040)) - find_package(Threads REQUIRED) - target_link_libraries(reactor-c PUBLIC Threads::Threads) - endif() endif() target_compile_definitions(reactor-c PRIVATE INITIAL_EVENT_QUEUE_SIZE=${INITIAL_EVENT_QUEUE_SIZE}) diff --git a/low_level_platform/impl/CMakeLists.txt b/low_level_platform/impl/CMakeLists.txt index 8773f1e99..2ebb5fef2 100644 --- a/low_level_platform/impl/CMakeLists.txt +++ b/low_level_platform/impl/CMakeLists.txt @@ -59,6 +59,12 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "Zephyr") zephyr_library_named(lf-low-level-platform-impl) zephyr_library_sources(${LF_LOW_LEVEL_PLATFORM_FILES}) zephyr_library_link_libraries(kernel) +elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Rp2040") + add_library(lf-low-level-platform-impl STATIC ${LF_LOW_LEVEL_PLATFORM_FILES}) + if (DEFINED NUMBER_OF_WORKERS AND ${NUMBER_OF_WORKERS} GREATER 2) + message(FATAL_ERROR "RP2040 can have at most 2 workers (one per core).\ + Number of requested workers is ${NUMBER_OF_WORKERS}.") + endif() elseif(${CMAKE_SYSTEM_NAME} STREQUAL "FlexPRET") add_library(lf-low-level-platform-impl STATIC ${LF_LOW_LEVEL_PLATFORM_FILES}) target_link_libraries(lf-low-level-platform-impl PRIVATE fp-sdk) From f34d0c60df004c6f08b2250b7dd8efc6b13a880c Mon Sep 17 00:00:00 2001 From: Samuel Berkun Date: Sat, 25 May 2024 05:41:11 -0700 Subject: [PATCH 09/13] peter... --- platform/impl/platform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/impl/platform.c b/platform/impl/platform.c index 361f36992..e15a1710e 100644 --- a/platform/impl/platform.c +++ b/platform/impl/platform.c @@ -11,7 +11,7 @@ #include #include "low_level_platform.h" -#include "platform.h" +#include "../api/platform.h" // MUTEXES ********************************************************************* From e00d73ab3bb1a7bfcd28c1786ab4bfc9772a2b3f Mon Sep 17 00:00:00 2001 From: Samuel Berkun Date: Sat, 25 May 2024 05:52:22 -0700 Subject: [PATCH 10/13] ??? --- platform/impl/platform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/impl/platform.c b/platform/impl/platform.c index e15a1710e..361f36992 100644 --- a/platform/impl/platform.c +++ b/platform/impl/platform.c @@ -11,7 +11,7 @@ #include #include "low_level_platform.h" -#include "../api/platform.h" +#include "platform.h" // MUTEXES ********************************************************************* From 37918269ec81b38e035890e30808511c2aa35437 Mon Sep 17 00:00:00 2001 From: Samuel Berkun Date: Sat, 25 May 2024 06:43:53 -0700 Subject: [PATCH 11/13] fix compile errors --- low_level_platform/api/CMakeLists.txt | 3 +++ .../api/platform/lf_rp2040_support.h | 1 - low_level_platform/impl/src/lf_rp2040_support.c | 15 +++++++++------ 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/low_level_platform/api/CMakeLists.txt b/low_level_platform/api/CMakeLists.txt index 6993dfa52..9803476d6 100644 --- a/low_level_platform/api/CMakeLists.txt +++ b/low_level_platform/api/CMakeLists.txt @@ -9,6 +9,9 @@ elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Zephyr") target_compile_definitions(lf-low-level-platform-api INTERFACE PLATFORM_ZEPHYR) elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Rp2040") target_compile_definitions(lf-low-level-platform-api INTERFACE PLATFORM_RP2040) + target_link_libraries(lf-low-level-platform-api INTERFACE pico_stdlib) + target_link_libraries(lf-low-level-platform-api INTERFACE pico_multicore) + target_link_libraries(lf-low-level-platform-api INTERFACE pico_sync) elseif(${CMAKE_SYSTEM_NAME} STREQUAL "FlexPRET") target_compile_definitions(lf-low-level-platform-api INTERFACE PLATFORM_FLEXPRET) target_link_libraries(lf-low-level-platform-api INTERFACE fp-sdk) diff --git a/low_level_platform/api/platform/lf_rp2040_support.h b/low_level_platform/api/platform/lf_rp2040_support.h index 10285851e..611faed09 100644 --- a/low_level_platform/api/platform/lf_rp2040_support.h +++ b/low_level_platform/api/platform/lf_rp2040_support.h @@ -7,7 +7,6 @@ #ifndef LF_RP2040_SUPPORT_H #define LF_RP2040_SUPPORT_H -#include #include #define NO_CLI diff --git a/low_level_platform/impl/src/lf_rp2040_support.c b/low_level_platform/impl/src/lf_rp2040_support.c index 465e16d5c..67cc96fe0 100644 --- a/low_level_platform/impl/src/lf_rp2040_support.c +++ b/low_level_platform/impl/src/lf_rp2040_support.c @@ -35,7 +35,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "platform/lf_rp2040_support.h" #include "low_level_platform.h" -#include "utils/util.h" #include "tag.h" #include @@ -216,10 +215,7 @@ int _lf_single_threaded_notify_of_event() { * @brief Get the number of cores on the host machine. */ int lf_available_cores() { - // Right now, runtime creates 1 main thread and 1 worker thread - // In the future, this may be changed to 2 (if main thread also functions - // as a worker thread) - return 1; + return 2; } static void *(*thread_1) (void *); @@ -309,6 +305,13 @@ int _lf_cond_timedwait(lf_cond_t* cond, instant_t absolute_time_ns) { return acquired_permit ? 0 : LF_TIMEOUT; } -#endif // LF_SINGLE_THREADED +void initialize_lf_thread_id() {} + +int lf_thread_id() { + return get_core_num(); +} + + +#endif // !LF_SINGLE_THREADED #endif // PLATFORM_RP2040 From 331cc91d728048fa8275f47e445b873f9e239d0a Mon Sep 17 00:00:00 2001 From: Samuel Berkun Date: Sat, 25 May 2024 07:00:09 -0700 Subject: [PATCH 12/13] make cond_broadcast from interrupts sound --- .../api/platform/lf_rp2040_support.h | 3 ++- .../impl/src/lf_rp2040_support.c | 20 +++++++++++++------ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/low_level_platform/api/platform/lf_rp2040_support.h b/low_level_platform/api/platform/lf_rp2040_support.h index 611faed09..fe5b33508 100644 --- a/low_level_platform/api/platform/lf_rp2040_support.h +++ b/low_level_platform/api/platform/lf_rp2040_support.h @@ -7,6 +7,7 @@ #ifndef LF_RP2040_SUPPORT_H #define LF_RP2040_SUPPORT_H +#include #include #define NO_CLI @@ -25,7 +26,7 @@ typedef recursive_mutex_t lf_mutex_t; typedef struct { - semaphore_t sema; + semaphore_t notifs[NUM_CORES]; lf_mutex_t* mutex; } lf_cond_t; typedef int lf_thread_t; diff --git a/low_level_platform/impl/src/lf_rp2040_support.c b/low_level_platform/impl/src/lf_rp2040_support.c index 67cc96fe0..ebbfcbbd8 100644 --- a/low_level_platform/impl/src/lf_rp2040_support.c +++ b/low_level_platform/impl/src/lf_rp2040_support.c @@ -276,32 +276,40 @@ int lf_mutex_unlock(lf_mutex_t* mutex) { return 0; } +// condition variables "notify" threads using a semaphore per core. +// although there are only two cores, may not use just a single semaphore +// as a cond_broadcast may be called from within an interrupt int lf_cond_init(lf_cond_t* cond, lf_mutex_t* mutex) { - sem_init(&(cond->sema), 0, 1); + for (int i = 0; i < NUM_CORES; i++) { + sem_init(&(cond->notifs[i]), 0, 1); + } cond->mutex = mutex; return 0; } int lf_cond_broadcast(lf_cond_t* cond) { - sem_reset(&(cond->sema), 1); + for (int i = 0; i < NUM_CORES; i++) { + sem_reset(&(cond->notifs[i]), 1); + } return 0; } int lf_cond_signal(lf_cond_t* cond) { - sem_reset(&(cond->sema), 1); - return 0; + return lf_cond_broadcast(cond); // spurious wakeups, but that's ok } int lf_cond_wait(lf_cond_t* cond) { + semaphore_t* mailbox = &(cond->notifs[get_core_num()]); lf_mutex_unlock(cond->mutex); - sem_acquire_blocking(&(cond->sema)); + sem_acquire_blocking(mailbox); lf_mutex_lock(cond->mutex); return 0; } int _lf_cond_timedwait(lf_cond_t* cond, instant_t absolute_time_ns) { + semaphore_t* mailbox = &(cond->notifs[get_core_num()]); absolute_time_t a = from_us_since_boot(absolute_time_ns / 1000); - bool acquired_permit = sem_acquire_block_until(&(cond->sema), a); + bool acquired_permit = sem_acquire_block_until(mailbox, a); return acquired_permit ? 0 : LF_TIMEOUT; } From b58a3a5cc1d9c6854104719597db21895872081c Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Sun, 26 May 2024 10:04:57 +0200 Subject: [PATCH 13/13] Ran formatter --- .../api/platform/lf_rp2040_support.h | 4 +-- .../impl/src/lf_rp2040_support.c | 25 +++++++------------ 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/low_level_platform/api/platform/lf_rp2040_support.h b/low_level_platform/api/platform/lf_rp2040_support.h index fe5b33508..0cea2b1ea 100644 --- a/low_level_platform/api/platform/lf_rp2040_support.h +++ b/low_level_platform/api/platform/lf_rp2040_support.h @@ -26,8 +26,8 @@ typedef recursive_mutex_t lf_mutex_t; typedef struct { - semaphore_t notifs[NUM_CORES]; - lf_mutex_t* mutex; + semaphore_t notifs[NUM_CORES]; + lf_mutex_t* mutex; } lf_cond_t; typedef int lf_thread_t; diff --git a/low_level_platform/impl/src/lf_rp2040_support.c b/low_level_platform/impl/src/lf_rp2040_support.c index ebbfcbbd8..fcbc71078 100644 --- a/low_level_platform/impl/src/lf_rp2040_support.c +++ b/low_level_platform/impl/src/lf_rp2040_support.c @@ -31,8 +31,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * @author{Abhi Gundrala } */ - - #include "platform/lf_rp2040_support.h" #include "low_level_platform.h" #include "tag.h" @@ -202,7 +200,7 @@ int lf_enable_interrupts_nested() { int _lf_single_threaded_notify_of_event() { // notify main sleep loop of event if (sem_release(&_lf_sem_irq_event)) { - return 0; + return 0; } return 1; } @@ -214,11 +212,9 @@ int _lf_single_threaded_notify_of_event() { /** * @brief Get the number of cores on the host machine. */ -int lf_available_cores() { - return 2; -} +int lf_available_cores() { return 2; } -static void *(*thread_1) (void *); +static void* (*thread_1)(void*); static void* thread_1_args; static int num_create_threads_called = 0; static semaphore_t thread_1_done; @@ -231,7 +227,7 @@ void core1_entry() { sem_reset(&thread_1_done, 1); } -int lf_thread_create(lf_thread_t* thread, void *(*lf_thread) (void *), void* arguments) { +int lf_thread_create(lf_thread_t* thread, void* (*lf_thread)(void*), void* arguments) { // make sure this fn is only called once if (num_create_threads_called != 0) { return 1; @@ -247,16 +243,16 @@ int lf_thread_create(lf_thread_t* thread, void *(*lf_thread) (void *), void* arg int lf_thread_join(lf_thread_t thread, void** thread_return) { if (thread != MAGIC_THREAD1_ID) { - return 1; + return 1; } sem_acquire_blocking(&thread_1_done); // release in case join is called again if (!sem_release(&thread_1_done)) { - // shouldn't be possible; lf_thread_join is only called from main thread - return 1; + // shouldn't be possible; lf_thread_join is only called from main thread + return 1; } if (thread_return) { - *thread_return = thread_1_return; + *thread_return = thread_1_return; } return 0; } @@ -315,10 +311,7 @@ int _lf_cond_timedwait(lf_cond_t* cond, instant_t absolute_time_ns) { void initialize_lf_thread_id() {} -int lf_thread_id() { - return get_core_num(); -} - +int lf_thread_id() { return get_core_num(); } #endif // !LF_SINGLE_THREADED