diff --git a/framework/include/fwk_event.h b/framework/include/fwk_event.h index dbbd0a03bed692e353bc1ae508ba7faadc97b4f0..1a69ac198541f5f6f34257e068889cf287cb9129 100644 --- a/framework/include/fwk_event.h +++ b/framework/include/fwk_event.h @@ -76,12 +76,14 @@ struct fwk_event { */ bool is_delayed_response; +#ifdef BUILD_HAS_MULTITHREADING /*! * \internal * \brief Flag indicating whether the event is a response event that a * thread is waiting for to resume execution. */ bool is_thread_wakeup_event; +#endif /*! * \brief Event identifier. diff --git a/framework/include/fwk_multi_thread.h b/framework/include/fwk_multi_thread.h index 68c0b02741a4b4458083bece28ced1405df5e094..133c0e4e5f6cebd821b43ab1e1456029461c8c03 100644 --- a/framework/include/fwk_multi_thread.h +++ b/framework/include/fwk_multi_thread.h @@ -66,6 +66,10 @@ int fwk_thread_create(fwk_id_t id); * The event identifier and target identifier are validated and must * belong to the same module. * + * Warning: As this API could have serious adverse effects on system + * performance and throughput, this API has been deprecated + * and should not be used in single-threaded mode. + * * \param event Event to put into the queue for processing. Must not be \c NULL. * \param[out] resp_event The response event. Must not be \c NULL. * @@ -77,8 +81,16 @@ int fwk_thread_create(fwk_id_t id); * \retval FWK_E_ACCESS The API is called from an ISR, called from the common * thread, or the event targets the calling thread. */ +#ifdef BUILD_HAS_MULTITHREADING +int fwk_thread_put_event_and_wait(struct fwk_event *event, + struct fwk_event *resp_event); + +#else int fwk_thread_put_event_and_wait(struct fwk_event *event, - struct fwk_event *resp_event); + struct fwk_event *resp_event) + __attribute__((deprecated)); + +#endif /*! * @} diff --git a/framework/include/internal/fwk_single_thread.h b/framework/include/internal/fwk_single_thread.h index 2639e0ef31b540abf5d61c21f653264eb1f0e77e..0cfb92fb9e883414597d9d3cc124eaf1185bd9d9 100644 --- a/framework/include/internal/fwk_single_thread.h +++ b/framework/include/internal/fwk_single_thread.h @@ -40,6 +40,30 @@ struct __fwk_thread_ctx { /* The event currently being processed */ struct fwk_event *current_event; + + /* Event being processed when put_event_and_wait was called */ + struct fwk_event *previous_event; + + /* + * Flag indicating the thread is waiting for the completion of the + * processing of an event (true) or not (false). The thread + * enters this waiting state when calling the fwk_thread_put_and_wait() + * framework API requesting that the execution does not resume at the + * caller until this event processing is complete and the response + * received. The thread leaves this waiting state when the processing + * of the aforementioned event is completed. The execution of the + * caller is then resumed immediately: no other event processing occurs + * between the end of the event processing and the caller execution being + * resumed. + * + * Note that nested put_event_and_wait calls are not supported. + */ + bool waiting_event_processing_completion; + + /* + * The cookie of the event we are waiting for + */ + uint32_t cookie; }; /* diff --git a/framework/src/fwk_thread.c b/framework/src/fwk_thread.c index b00261951bd0faae3e2bb2047db33bc4927af1eb..d7ff129f91c94fff3cdd0a899e771fd09292e11e 100644 --- a/framework/src/fwk_thread.c +++ b/framework/src/fwk_thread.c @@ -34,6 +34,12 @@ static struct __fwk_thread_ctx ctx; static const char err_msg_line[] = "[FWK] Error %d in %s @%d"; static const char err_msg_func[] = "[FWK] Error %d in %s"; +/* States for put_event_and_wait */ +enum wait_states { + WAITING_FOR_EVENT = 0, + WAITING_FOR_RESPONSE = 1, +}; + /* * Static functions */ @@ -74,6 +80,7 @@ static int put_event(struct fwk_event *event) { struct fwk_event *allocated_event; unsigned int interrupt; + bool is_wakeup_event = false; if (event->is_delayed_response) { allocated_event = __fwk_thread_search_delayed_response( @@ -91,6 +98,11 @@ static int put_event(struct fwk_event *event) allocated_event->params, event->params, sizeof(allocated_event->params)); + + /* Is this the event put_event_and_wait is waiting for ? */ + if (ctx.waiting_event_processing_completion && + (ctx.cookie == event->cookie)) + is_wakeup_event = true; } else { allocated_event = duplicate_event(event); if (allocated_event == NULL) @@ -99,6 +111,9 @@ static int put_event(struct fwk_event *event) allocated_event->cookie = event->cookie = ctx.event_cookie_counter++; + if (is_wakeup_event) + ctx.cookie = event->cookie; + if (fwk_interrupt_get_current(&interrupt) != FWK_SUCCESS) fwk_list_push_tail(&ctx.event_queue, &allocated_event->slist_node); else @@ -107,6 +122,13 @@ static int put_event(struct fwk_event *event) return FWK_SUCCESS; } +static void free_event(struct fwk_event *event) +{ + fwk_interrupt_global_disable(); + fwk_list_push_tail(&ctx.free_event_queue, &event->slist_node); + fwk_interrupt_global_enable(); +} + static void process_next_event(void) { int status; @@ -154,16 +176,17 @@ static void process_next_event(void) } } else { status = process_event(event, &async_response_event); - if (status != FWK_SUCCESS) - FWK_LOG_CRIT(err_msg_line, status, __func__, __LINE__); + if ((status != FWK_SUCCESS) && (status != FWK_PENDING)) { + FWK_LOG_CRIT( + "[FWK] Process event (%s: %s -> %s) (%d)\n", + FWK_ID_STR(event->id), + FWK_ID_STR(event->source_id), + FWK_ID_STR(event->target_id), status); + } } ctx.current_event = NULL; - - fwk_interrupt_global_disable(); - fwk_list_push_tail(&ctx.free_event_queue, &event->slist_node); - fwk_interrupt_global_enable(); - + free_event(event); return; } @@ -293,3 +316,169 @@ error: FWK_LOG_CRIT(err_msg_func, status, __func__); return status; } + +int fwk_thread_put_event_and_wait(struct fwk_event *event, + struct fwk_event *resp_event) +{ + const struct fwk_module *module; + int (*process_event)(const struct fwk_event *event, + struct fwk_event *resp_event); + struct fwk_event response_event; + struct fwk_event *next_event; + struct fwk_event *allocated_event; + unsigned int interrupt; + int status = FWK_E_PARAM; + enum wait_states wait_state = WAITING_FOR_EVENT; + + if (!ctx.initialized) { + status = FWK_E_INIT; + goto error; + } + + if ((event == NULL) || (resp_event == NULL)) + goto error; + + if (!fwk_module_is_valid_event_id(event->id)) + goto error; + + if (fwk_interrupt_get_current(&interrupt) == FWK_SUCCESS) { + status = FWK_E_STATE; + goto error; + } + + if (ctx.current_event != NULL) + event->source_id = ctx.current_event->target_id; + else if (!fwk_module_is_valid_entity_id(event->source_id)) { + FWK_LOG_ERR( + "[FWK] deprecated put_event_and_wait (%s: %s -> %s)\n", + FWK_ID_STR(event->id), + FWK_ID_STR(event->source_id), + FWK_ID_STR(event->target_id)); + goto error; + } + + /* No support for nested put_event_and_wait calls */ + if (ctx.waiting_event_processing_completion) { + status = FWK_E_BUSY; + goto error; + } + ctx.waiting_event_processing_completion = true; + ctx.previous_event = ctx.current_event; + + FWK_LOG_TRACE( + "[FWK] deprecated put_event_and_wait (%s: %s -> %s)\n", + FWK_ID_STR(event->id), + FWK_ID_STR(event->source_id), + FWK_ID_STR(event->target_id)); + + event->is_response = false; + event->is_delayed_response = false; + event->response_requested = true; + event->is_notification = false; + + status = put_event(event); + if (status != FWK_SUCCESS) + goto exit; + + ctx.cookie = event->cookie; + + for (;;) { + + if (fwk_list_is_empty(&ctx.event_queue)) { + if (!fwk_list_is_empty(&ctx.isr_event_queue)) + process_isr(); + continue; + } + + ctx.current_event = next_event = FWK_LIST_GET(fwk_list_head( + &ctx.event_queue), struct fwk_event, slist_node); + + if (next_event->cookie != ctx.cookie) { + /* + * Process any events waiting on the event_queue until + * we get to the event from the waiting call. + */ + process_next_event(); + if (!fwk_list_is_empty(&ctx.isr_event_queue)) + process_isr(); + continue; + } + + /* This is either the original event or the response event */ + next_event = FWK_LIST_GET( + fwk_list_pop_head(&ctx.event_queue), struct fwk_event, slist_node); + + if (wait_state == WAITING_FOR_EVENT) { + module = __fwk_module_get_ctx(next_event->target_id)->desc; + process_event = module->process_event; + + response_event = *next_event; + response_event.source_id = next_event->target_id; + response_event.target_id = next_event->source_id; + response_event.is_delayed_response = false; + + /* Execute the event handler */ + status = process_event(next_event, &response_event); + if (status != FWK_SUCCESS) + goto exit; + + /* + * The response event goes onto the queue now + * and we update the cookie to wait for the + * response. + */ + response_event.is_response = true; + response_event.response_requested = false; + if (!response_event.is_delayed_response) { + status = put_event(&response_event); + if (status != FWK_SUCCESS) + goto exit; + ctx.cookie = response_event.cookie; + } else { + allocated_event = duplicate_event(&response_event); + if (allocated_event != NULL) { + fwk_list_push_head( + __fwk_thread_get_delayed_response_list( + response_event.source_id), + &allocated_event->slist_node); + } else { + status = FWK_E_NOMEM; + goto exit; + } + ctx.cookie = allocated_event->cookie; + } + + wait_state = WAITING_FOR_RESPONSE; + free_event(next_event); + + /* + * Check for any interrupt events that might have been + * queued while the event was being executed. + */ + while (!fwk_list_is_empty(&ctx.isr_event_queue)) + process_isr(); + continue; + } + + if (wait_state == WAITING_FOR_RESPONSE) { + /* + * The response event has been received, return to + * the caller. + */ + memcpy(resp_event->params, next_event->params, + sizeof(resp_event->params)); + free_event(next_event); + status = FWK_SUCCESS; + goto exit; + } + } + +exit: + ctx.current_event = ctx.previous_event; + ctx.waiting_event_processing_completion = false; + if (status == FWK_SUCCESS) + return status; +error: + FWK_LOG_CRIT(err_msg_func, status, __func__); + return status; +} diff --git a/product/juno/module/juno_debug/src/mod_juno_debug.c b/product/juno/module/juno_debug/src/mod_juno_debug.c index 17330b179c8c12dbd2b5e1e265e2be5716ad2cce..58d92e53409d25e82ab7be134f592da752ffc24e 100644 --- a/product/juno/module/juno_debug/src/mod_juno_debug.c +++ b/product/juno/module/juno_debug/src/mod_juno_debug.c @@ -407,7 +407,11 @@ static int juno_debug_element_init(fwk_id_t element_id, unsigned int sub_element_count, const void *data) { +#ifdef BUILD_HAS_MULTITHREADING return fwk_thread_create(element_id); +#else + return FWK_SUCCESS; +#endif } static int juno_debug_bind(fwk_id_t id, unsigned int round) diff --git a/product/juno/scp_ramfw/firmware.mk b/product/juno/scp_ramfw/firmware.mk index 8ee542da8f52ecc4d894a9f72754e3452fe3e013..ddf46ddf0419a926e492b8f6d53328e891f0f5f3 100644 --- a/product/juno/scp_ramfw/firmware.mk +++ b/product/juno/scp_ramfw/firmware.mk @@ -56,7 +56,6 @@ BS_FIRMWARE_MODULES := \ juno_thermal BS_FIRMWARE_SOURCES := \ - rtx_config.c \ juno_utils.c \ config_sds.c \ config_log.c \ @@ -92,4 +91,8 @@ BS_FIRMWARE_SOURCES := \ config_juno_thermal.c \ config_scmi_power_domain.c +ifeq ($(BS_FIRMWARE_HAS_MULTITHREADING),yes) + BS_FIRMWARE_SOURCES += rtx_config.c +endif + include $(BS_DIR)/firmware.mk diff --git a/tools/build_system/rules.mk b/tools/build_system/rules.mk index fb883d11500f15f36083149ab8ca5d3e07642f5f..016edf169288ee3fd25186ce9c9b9a0aae0b648c 100644 --- a/tools/build_system/rules.mk +++ b/tools/build_system/rules.mk @@ -99,6 +99,7 @@ endif # set of warnings, and any warnings that do occur are upgraded to errors to # prevent the firmware from building. CFLAGS += -Werror +CFLAGS += -Wno-error=deprecated-declarations CFLAGS += -Wall CFLAGS += -Wextra CFLAGS += -pedantic diff --git a/tools/build_system/test.mk b/tools/build_system/test.mk index 7b83a47faf5bcb5f8a8d9820cedc9b6c8d40536b..115afa3e3808327a04976ad5c046c0b90529aee8 100644 --- a/tools/build_system/test.mk +++ b/tools/build_system/test.mk @@ -21,6 +21,7 @@ CFLAGS += -Wall CFLAGS += -Wextra CFLAGS += -Werror CFLAGS += -Wno-missing-field-initializers +CFLAGS += -Wno-error=deprecated-declarations CFLAGS += -Wno-unused-parameter CFLAGS += -Wno-strict-aliasing CFLAGS += -std=c11 diff --git a/tools/check_api.py b/tools/check_api.py index 2dac9c82da746923b6dc35413faf1a2394d947d5..7427a21da8cb6d51ca14c961f7ef48240205d927 100755 --- a/tools/check_api.py +++ b/tools/check_api.py @@ -71,7 +71,7 @@ def main(argv=[], prog_name=''): illegal_use = 0 with open(BANNED_LIST) as file: - for l, fname in enumerate(file): + for fname in file: if fname[0] == '#': continue BANNED_API.append(fname.rstrip()) diff --git a/tools/check_tabs.py b/tools/check_tabs.py index 35110c5523ffacba2c18e36efe01f382e79c16ab..2aae02ce6b288d6a9327afe899dca3cd780eb263 100755 --- a/tools/check_tabs.py +++ b/tools/check_tabs.py @@ -80,7 +80,7 @@ def main(argv=[], prog_name=''): # excluded by .git/info/exclude) git_clean_output = subprocess.check_output("git clean -ndX".split()) git_clean_output = git_clean_output.decode() - git_ignores = [l.split()[-1] for l in git_clean_output.splitlines()] + git_ignores = [line.split()[-1] for line in git_clean_output.splitlines()] cwd = os.getcwd() print("Executing from %s" % cwd)