From ac028c6e727ed90cb79c6e1449d904ba9eadf0a4 Mon Sep 17 00:00:00 2001 From: Samuel Berkun Date: Thu, 1 Feb 2024 01:18:19 -0800 Subject: [PATCH 1/9] initial draft for multithreaded rp2040 --- core/CMakeLists.txt | 2 +- core/platform/lf_rp2040_support.c | 176 +++++++++++++++++++++- include/core/platform/lf_rp2040_support.h | 37 +++++ 3 files changed, 209 insertions(+), 6 deletions(-) diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 73d8e4b93..28138f96f 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -93,7 +93,7 @@ endif() # 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) + if (NOT (PLATFORM_ZEPHYR OR ${CMAKE_SYSTEM_NAME} STREQUAL "Rp2040")) find_package(Threads REQUIRED) target_link_libraries(reactor-c PUBLIC Threads::Threads) endif() diff --git a/core/platform/lf_rp2040_support.c b/core/platform/lf_rp2040_support.c index 6a0194f5e..745e59a14 100644 --- a/core/platform/lf_rp2040_support.c +++ b/core/platform/lf_rp2040_support.c @@ -31,10 +31,6 @@ 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 "lf_rp2040_support.h" #include "platform.h" #include "utils/util.h" @@ -51,6 +47,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. @@ -63,13 +64,14 @@ static uint32_t _lf_num_nested_crit_sec = 0; /** * Initialize basic runtime infrastructure and - * synchronization structs for an single-threaded runtime. + * synchronization structs for a single-threaded runtime. */ void _lf_initialize_clock(void) { // init stdio lib 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); } @@ -206,6 +208,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 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) { + 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 diff --git a/include/core/platform/lf_rp2040_support.h b/include/core/platform/lf_rp2040_support.h index 1b23e3a2e..c919577cd 100644 --- a/include/core/platform/lf_rp2040_support.h +++ b/include/core/platform/lf_rp2040_support.h @@ -20,4 +20,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 From 5f5e95d70ac84eaf61800d360a838152184385c6 Mon Sep 17 00:00:00 2001 From: Samuel Berkun Date: Thu, 1 Feb 2024 12:17:10 -0800 Subject: [PATCH 2/9] add PLATFORM_RP2040 cmake variable --- core/CMakeLists.txt | 2 +- core/platform/CMakeLists.txt | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 28138f96f..996a6fb23 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -93,7 +93,7 @@ endif() # 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() diff --git a/core/platform/CMakeLists.txt b/core/platform/CMakeLists.txt index eec94db65..dd0fe4239 100644 --- a/core/platform/CMakeLists.txt +++ b/core/platform/CMakeLists.txt @@ -24,6 +24,7 @@ elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Zephyr") set(PLATFORM_ZEPHYR true) elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Rp2040") list(APPEND REACTORC_COMPILE_DEFS PLATFORM_RP2040) + set(PLATFORM_RP2040 true) endif() # Prepend all sources with platform From 0dbbf740c15178368487a93a71f5fd4a3ce9835f Mon Sep 17 00:00:00 2001 From: Samuel Berkun Date: Sat, 3 Feb 2024 02:14:34 -0800 Subject: [PATCH 3/9] allow core 1 to sleep --- core/platform/lf_rp2040_support.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/core/platform/lf_rp2040_support.c b/core/platform/lf_rp2040_support.c index 745e59a14..f4f3e14ba 100644 --- a/core/platform/lf_rp2040_support.c +++ b/core/platform/lf_rp2040_support.c @@ -234,11 +234,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 0e91e74b4ece2465c71b46d31fa5ac700b763a53 Mon Sep 17 00:00:00 2001 From: Samuel Berkun Date: Tue, 6 Feb 2024 00:41:42 -0800 Subject: [PATCH 4/9] mutex to recursive mutex, check return values of sem_release --- core/platform/lf_rp2040_support.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/core/platform/lf_rp2040_support.c b/core/platform/lf_rp2040_support.c index f4f3e14ba..bd42e1cca 100644 --- a/core/platform/lf_rp2040_support.c +++ b/core/platform/lf_rp2040_support.c @@ -68,6 +68,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); @@ -205,8 +207,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 @@ -233,7 +237,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) { @@ -255,7 +259,11 @@ int lf_thread_join(lf_thread_t thread, void** thread_return) { 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; } @@ -263,17 +271,17 @@ int lf_thread_join(lf_thread_t thread, void** thread_return) { } 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 37c8e664ed505c133484240765f60c7a1ecb5457 Mon Sep 17 00:00:00 2001 From: Samuel Berkun Date: Wed, 21 Feb 2024 23:13:02 -0800 Subject: [PATCH 5/9] fixed bug with recursive mutex --- core/platform/lf_rp2040_support.c | 4 ++-- include/core/platform/lf_rp2040_support.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/platform/lf_rp2040_support.c b/core/platform/lf_rp2040_support.c index bd42e1cca..0c0fae43e 100644 --- a/core/platform/lf_rp2040_support.c +++ b/core/platform/lf_rp2040_support.c @@ -302,9 +302,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; } diff --git a/include/core/platform/lf_rp2040_support.h b/include/core/platform/lf_rp2040_support.h index c919577cd..babb1b84b 100644 --- a/include/core/platform/lf_rp2040_support.h +++ b/include/core/platform/lf_rp2040_support.h @@ -23,10 +23,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; From b9e1d9a8a4cb64f5aac302bd202cc0b5dbfccc0e Mon Sep 17 00:00:00 2001 From: Samuel Berkun Date: Wed, 21 Feb 2024 23:50:37 -0800 Subject: [PATCH 6/9] cleanup; atomics were seperated last week --- core/platform/lf_rp2040_support.c | 61 ----------------------- include/core/platform/lf_rp2040_support.h | 27 +--------- 2 files changed, 1 insertion(+), 87 deletions(-) diff --git a/core/platform/lf_rp2040_support.c b/core/platform/lf_rp2040_support.c index 0c0fae43e..356553b3c 100644 --- a/core/platform/lf_rp2040_support.c +++ b/core/platform/lf_rp2040_support.c @@ -314,67 +314,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 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) { - 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 diff --git a/include/core/platform/lf_rp2040_support.h b/include/core/platform/lf_rp2040_support.h index babb1b84b..c355afaed 100644 --- a/include/core/platform/lf_rp2040_support.h +++ b/include/core/platform/lf_rp2040_support.h @@ -30,31 +30,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 From 9bc9c9a1ddcdb28091da715a729163e602da8c3e Mon Sep 17 00:00:00 2001 From: Samuel Berkun Date: Thu, 22 Feb 2024 00:24:52 -0800 Subject: [PATCH 7/9] rename _lf_cond_timedwait --- core/platform/lf_rp2040_support.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/platform/lf_rp2040_support.c b/core/platform/lf_rp2040_support.c index 356553b3c..052348567 100644 --- a/core/platform/lf_rp2040_support.c +++ b/core/platform/lf_rp2040_support.c @@ -308,7 +308,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 7dc0016755c0979675b9c58e37aee48c9943ee3a Mon Sep 17 00:00:00 2001 From: Samuel Berkun Date: Thu, 29 Feb 2024 04:12:40 -0800 Subject: [PATCH 8/9] main thread worker --- core/platform/lf_rp2040_support.c | 5 +--- core/threaded/reactor_threaded.c | 50 ++++++++++++++++++++----------- 2 files changed, 33 insertions(+), 22 deletions(-) diff --git a/core/platform/lf_rp2040_support.c b/core/platform/lf_rp2040_support.c index 052348567..40da158ec 100644 --- a/core/platform/lf_rp2040_support.c +++ b/core/platform/lf_rp2040_support.c @@ -221,10 +221,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 *); diff --git a/core/threaded/reactor_threaded.c b/core/threaded/reactor_threaded.c index ef507a565..b8be4b336 100644 --- a/core/threaded/reactor_threaded.c +++ b/core/threaded/reactor_threaded.c @@ -1026,17 +1026,6 @@ void lf_print_snapshot(environment_t* env) { } } -// Start threads in the thread pool. -void start_threads(environment_t* env) { - assert(env != GLOBAL_ENVIRONMENT); - - LF_PRINT_LOG("Starting %u worker threads in environment", env->num_workers); - for (unsigned int i = 0; i < env->num_workers; i++) { - if (lf_thread_create(&env->thread_ids[i], worker, env) != 0) { - lf_print_error_and_exit("Could not start thread-%u", i); - } - } -} /** * @brief Determine the number of workers. @@ -1161,23 +1150,48 @@ int lf_reactor_c_main(int argc, const char* argv[]) { _lf_initialize_start_tag(env); lf_print("Environment %u: ---- Spawning %d workers.",env->id, env->num_workers); - start_threads(env); + + for (unsigned int j = 0; j < env->num_workers; j++) { + if (i == 0 && j == 0) { + // The first worker thread of the first environment will be + // run on the main thread, rather than creating a new thread. + // This is important for bare-metal platforms, who can't + // afford to have the main thread sit idle. + continue; + } + if (lf_thread_create(&env->thread_ids[j], worker, env) != 0) { + lf_print_error_and_exit("Could not start thread-%u", j); + } + } + // Unlock mutex and allow threads proceed LF_MUTEX_UNLOCK(&env->mutex); } + + // main thread worker (first worker thread of first environment) + void* main_thread_exit_status = NULL; + if (num_envs > 0 && envs[0].num_workers > 0) { + environment_t *env = &envs[0]; + main_thread_exit_status = worker(env); + } for (int i = 0; inum_workers; i++) { - int failure = lf_thread_join(env->thread_ids[i], &worker_thread_exit_status); - if (failure) { - lf_print_error("Failed to join thread listening for incoming messages: %s", strerror(failure)); - } + for (int j = 0; j < env->num_workers; j++) { + if (i == 0 && j == 0) { + // main thread worker + worker_thread_exit_status = main_thread_exit_status; + } else { + int failure = lf_thread_join(env->thread_ids[j], &worker_thread_exit_status); + if (failure) { + lf_print_error("Failed to join thread listening for incoming messages: %s", strerror(failure)); + } + } if (worker_thread_exit_status != NULL) { - lf_print_error("---- Worker %d reports error code %p", i, worker_thread_exit_status); + lf_print_error("---- Worker %d reports error code %p", j, worker_thread_exit_status); ret = 1; } } From 87af1c4263d5661beef598580478faa41830813a Mon Sep 17 00:00:00 2001 From: Samuel Berkun Date: Wed, 6 Mar 2024 14:23:43 -0800 Subject: [PATCH 9/9] Apply suggestions from code review Co-authored-by: Edward A. Lee --- core/threaded/reactor_threaded.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/threaded/reactor_threaded.c b/core/threaded/reactor_threaded.c index b8be4b336..0713c7e05 100644 --- a/core/threaded/reactor_threaded.c +++ b/core/threaded/reactor_threaded.c @@ -1190,10 +1190,10 @@ int lf_reactor_c_main(int argc, const char* argv[]) { lf_print_error("Failed to join thread listening for incoming messages: %s", strerror(failure)); } } - if (worker_thread_exit_status != NULL) { + if (worker_thread_exit_status != NULL) { lf_print_error("---- Worker %d reports error code %p", j, worker_thread_exit_status); ret = 1; - } + } } if (ret == 0) {