From 40f5d074c9c58019f9cb5f515beef835fdf0e41a Mon Sep 17 00:00:00 2001 From: Souvik Chakravarty Date: Fri, 15 Nov 2019 13:59:26 +0000 Subject: [PATCH 1/2] fwk: Split delayed response from fwk_multi_thread We need to support delayed responses in non-MULTITHREADED mode. As a first step, we split delayed response functionality from fwk_multi_thread.c into a separate file which can be used by both MULTITHREADED and non-MULTITHREADED modes of compilation. We also include the appropriate headers to fix compilation issues in affected files as a result of this change. Change-Id: I3c48e130d3c8a61b06d2432bcf51760bfd19abd8 Tested-by: Nicola Mazzucato Signed-off-by: Souvik Chakravarty --- framework/include/fwk_thread.h | 27 ++-- .../internal/fwk_thread_delayed_resp.h | 46 +++++++ framework/src/Makefile | 1 + framework/src/fwk_multi_thread.c | 119 +++--------------- framework/src/fwk_thread.c | 6 - framework/src/fwk_thread_delayed_resp.c | 89 +++++++++++++ framework/test/Makefile | 11 +- 7 files changed, 178 insertions(+), 121 deletions(-) create mode 100644 framework/include/internal/fwk_thread_delayed_resp.h create mode 100644 framework/src/fwk_thread_delayed_resp.c diff --git a/framework/include/fwk_thread.h b/framework/include/fwk_thread.h index 54dd89fa0..92534fb43 100644 --- a/framework/include/fwk_thread.h +++ b/framework/include/fwk_thread.h @@ -13,6 +13,8 @@ #include +#include + /*! * \addtogroup GroupLibFramework Framework * @{ @@ -49,14 +51,16 @@ * \ref fwk_event.cookie field of \p event must match that of the event * it is responding to. * - * \param event Pointer to the event to queue. Must not be \c NULL. + * \param[in] event Pointer to the event to queue. Must not be \c NULL. * - * \retval FWK_SUCCESS The event was queued. - * \retval FWK_E_INIT The thread framework component is not initialized. - * \retval FWK_E_PARAM One or more parameters were invalid. - * \retval FWK_E_PARAM One or more fields in the \p event parameter were + * \retval ::FWK_SUCCESS The event was queued. + * \retval ::FWK_E_INIT The thread framework component is not initialized. + * \retval ::FWK_E_PARAM One or more parameters were invalid. + * \retval ::FWK_E_PARAM One or more fields in the \p event parameter were * invalid. - * \retval FWK_E_OS Operating system error. + * \retval ::FWK_E_OS Operating system error. + * + * \return Status code representing the result of the operation. */ int fwk_thread_put_event(struct fwk_event *event); @@ -70,14 +74,17 @@ int fwk_thread_put_event(struct fwk_event *event); * event. The event is not removed from the module or element internal * data. * - * \param id Identifier of the module or element that delayed the response. - * \param cookie Cookie of the event which the response has been delayed + * \param[in] id Identifier of the module or element that delayed the response. + * \param[in] cookie Cookie of the event which the response has been delayed * for. The cookie identifies the response event among the response events * the entity \p id may have delayed. * \param[out] event The copy of the response event. * - * \retval FWK_E_SUPPORT Not supported. - * \return One of the standard framework error codes. + * \retval ::FWK_SUCCESS The event was queued. + * \retval ::FWK_E_PARAM One or more parameters were invalid. + * \retval ::FWK_E_ACCESS Access violation due to call from interrupt handler. + * + * \return Status code representing the result of the operation. */ int fwk_thread_get_delayed_response(fwk_id_t id, uint32_t cookie, struct fwk_event *event); diff --git a/framework/include/internal/fwk_thread_delayed_resp.h b/framework/include/internal/fwk_thread_delayed_resp.h new file mode 100644 index 000000000..ab2718918 --- /dev/null +++ b/framework/include/internal/fwk_thread_delayed_resp.h @@ -0,0 +1,46 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2019, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef FWK_INTERNAL_THREAD_DELAYED_RESP_H +#define FWK_INTERNAL_THREAD_DELAYED_RESP_H + +#include + +#include + +/*! + * \internal + * + * \brief Get the list of delayed responses for a given module or element. + * + * \note The function assumes the validity of all its input parameters. + * + * \param id Identifier of the module or element. + * + * \return A pointer to the list of delayed responses. + */ +struct fwk_slist *__fwk_thread_get_delayed_response_list(fwk_id_t id); + +/*! + * \internal + * + * \brief Search delayed response. + * + * \note The function assumes the validity of all its input parameters. + * + * \param id Identifier of the module or element that delayed the response. + * \param cookie Cookie of the event which the response has been delayed + * for. This cookie identifies the response among the several responses + * that the entity 'id' may have delayed. + * + * \return A pointer to the delayed response event, \c NULL if not found. + */ +struct fwk_event *__fwk_thread_search_delayed_response( + fwk_id_t id, + uint32_t cookie); + +#endif /* FWK_INTERNAL_THREAD_DELAYED_RESP_H */ diff --git a/framework/src/Makefile b/framework/src/Makefile index 4cbf903ef..8024231f6 100644 --- a/framework/src/Makefile +++ b/framework/src/Makefile @@ -15,6 +15,7 @@ BS_LIB_SOURCES += fwk_interrupt.c BS_LIB_SOURCES += fwk_mm.c BS_LIB_SOURCES += fwk_module.c BS_LIB_SOURCES += fwk_slist.c +BS_LIB_SOURCES += fwk_thread_delayed_resp.c ifeq ($(BUILD_HAS_MULTITHREADING),yes) BS_LIB_SOURCES += fwk_multi_thread.c else diff --git a/framework/src/fwk_multi_thread.c b/framework/src/fwk_multi_thread.c index 546d2fc75..16b5a6c06 100644 --- a/framework/src/fwk_multi_thread.c +++ b/framework/src/fwk_multi_thread.c @@ -5,19 +5,23 @@ * SPDX-License-Identifier: BSD-3-Clause */ -#include -#include -#include +#include + +#include +#include +#include +#include + #include +#include #include #include -#include #include #include -#include -#include -#include -#include + +#include +#include +#include #define SIGNAL_ISR_EVENT 0x01 #define SIGNAL_EVENT_TO_PROCESS 0x02 @@ -138,57 +142,6 @@ static struct __fwk_thread_ctx *thread_get_ctx(fwk_id_t id) return NULL; } -/* - * Get the list of delayed responses for a given module or element. - * - * \note The function assumes the validity of all its input parameters. - * - * \param id Identifier of the module or element. - * - * \return A pointer to the list of subscriptions. - */ -static struct fwk_slist *get_delayed_response_list(fwk_id_t id) -{ - if (fwk_id_is_type(id, FWK_ID_TYPE_MODULE)) - return &__fwk_module_get_ctx(id)->delayed_response_list; - - return &__fwk_module_get_element_ctx(id)->delayed_response_list; -} - -/* - * Search delayed response. - * - * \note The function assumes the validity of all its input parameters. - * - * \param id Identifier of the module or element that delayed the response. - * \param cookie Cookie of the event which the response has been delayed - * for. This cookie identifies the response among the several responses - * that the entity 'id' may have delayed. - * - * \return A pointer to the delayed response event, NULL if not found. - */ -static struct fwk_event *search_delayed_response(fwk_id_t id, uint32_t cookie) -{ - struct fwk_slist *delayed_response_list; - struct fwk_slist_node *delayed_response_node; - struct fwk_event *delayed_response; - - delayed_response_list = get_delayed_response_list(id); - delayed_response_node = fwk_list_head(delayed_response_list); - - while (delayed_response_node != NULL) { - delayed_response = FWK_LIST_GET(delayed_response_node, - struct fwk_event, slist_node); - if (delayed_response->cookie == cookie) - return delayed_response; - - delayed_response_node = fwk_list_next(delayed_response_list, - delayed_response_node); - } - - return NULL; -} - /* * Put an event in the ISR event queue. * @@ -287,12 +240,13 @@ static int put_event(struct __fwk_thread_ctx *target_thread_ctx, target_thread_ctx, event); if (event->is_delayed_response) { - allocated_event = search_delayed_response(event->source_id, - event->cookie); + allocated_event = __fwk_thread_search_delayed_response( + event->source_id, event->cookie); if (allocated_event == NULL) goto error; - fwk_list_remove(get_delayed_response_list(event->source_id), + fwk_list_remove( + __fwk_thread_get_delayed_response_list(event->source_id), &allocated_event->slist_node); memcpy(allocated_event->params, event->params, @@ -368,8 +322,9 @@ static void process_event_requiring_response(struct fwk_event *event) else { allocated_event = duplicate_event(&resp_event); if (allocated_event != NULL) { - fwk_list_push_tail(get_delayed_response_list(resp_event.source_id), - &allocated_event->slist_node); + fwk_list_push_tail( + __fwk_thread_get_delayed_response_list(resp_event.source_id), + &allocated_event->slist_node); } } } @@ -917,39 +872,3 @@ error: FWK_HOST_PRINT(err_msg_func, status, __func__); return status; } - -int fwk_thread_get_delayed_response(fwk_id_t id, uint32_t cookie, - struct fwk_event *event) -{ - int status = FWK_E_PARAM; - struct fwk_event *delayed_response; - unsigned int interrupt; - - if (!ctx.initialized) { - status = FWK_E_INIT; - goto error; - } - - if (fwk_interrupt_get_current(&interrupt) == FWK_SUCCESS) { - status = FWK_E_ACCESS; - goto error; - } - - if (!fwk_module_is_valid_entity_id(id)) - goto error; - - if (event == NULL) - goto error; - - delayed_response = search_delayed_response(id, cookie); - if (delayed_response == NULL) - goto error; - - *event = *delayed_response; - - return FWK_SUCCESS; - -error: - FWK_HOST_PRINT(err_msg_func, status, __func__); - return status; -} diff --git a/framework/src/fwk_thread.c b/framework/src/fwk_thread.c index 0982a3194..97f9a49ac 100644 --- a/framework/src/fwk_thread.c +++ b/framework/src/fwk_thread.c @@ -239,9 +239,3 @@ error: FWK_HOST_PRINT(err_msg_func, status, __func__); return status; } - -int fwk_thread_get_delayed_response(fwk_id_t id, uint32_t cookie, - struct fwk_event *event) -{ - return FWK_E_SUPPORT; -} diff --git a/framework/src/fwk_thread_delayed_resp.c b/framework/src/fwk_thread_delayed_resp.c new file mode 100644 index 000000000..45ae38aeb --- /dev/null +++ b/framework/src/fwk_thread_delayed_resp.c @@ -0,0 +1,89 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2019, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +#include +#include +#include + +#include + +#ifdef BUILD_HOST +static const char err_msg_func[] = "[THR] Error %d in %s\n"; +#endif + +/* + * Internal interface functions for use by framework only + */ +struct fwk_slist *__fwk_thread_get_delayed_response_list(fwk_id_t id) +{ + if (fwk_id_is_type(id, FWK_ID_TYPE_MODULE)) + return &__fwk_module_get_ctx(id)->delayed_response_list; + + return &__fwk_module_get_element_ctx(id)->delayed_response_list; +} + +struct fwk_event *__fwk_thread_search_delayed_response( + fwk_id_t id, + uint32_t cookie) +{ + struct fwk_slist *delayed_response_list; + struct fwk_slist_node *delayed_response_node; + struct fwk_event *delayed_response; + + delayed_response_list = __fwk_thread_get_delayed_response_list(id); + delayed_response_node = fwk_list_head(delayed_response_list); + + while (delayed_response_node != NULL) { + delayed_response = + FWK_LIST_GET(delayed_response_node, struct fwk_event, slist_node); + if (delayed_response->cookie == cookie) + return delayed_response; + + delayed_response_node = + fwk_list_next(delayed_response_list, delayed_response_node); + } + + return NULL; +} + +/* + * Public Interface functions for use by Modules + */ +int fwk_thread_get_delayed_response( + fwk_id_t id, + uint32_t cookie, + struct fwk_event *event) +{ + int status = FWK_E_PARAM; + struct fwk_event *delayed_response; + unsigned int interrupt; + + if (fwk_interrupt_get_current(&interrupt) == FWK_SUCCESS) { + status = FWK_E_ACCESS; + goto error; + } + + if (!fwk_module_is_valid_entity_id(id)) + goto error; + + if (event == NULL) + goto error; + + delayed_response = __fwk_thread_search_delayed_response(id, cookie); + if (delayed_response == NULL) + goto error; + + *event = *delayed_response; + + return FWK_SUCCESS; + +error: + FWK_HOST_PRINT(err_msg_func, status, __func__); + return status; +} diff --git a/framework/test/Makefile b/framework/test/Makefile index fef860acc..12a0f2cc0 100644 --- a/framework/test/Makefile +++ b/framework/test/Makefile @@ -111,7 +111,7 @@ test_fwk_notification_WRAP := fwk_mm_calloc fwk_module_is_valid_entity_id \ # Multi-thread tests TESTS += test_fwk_multi_thread_init test_fwk_multi_thread_init_SRC := test_fwk_multi_thread_init.c \ - fwk_multi_thread.c fwk_test.c fwk_slist.c fwk_id.c + fwk_multi_thread.c fwk_test.c fwk_slist.c fwk_id.c fwk_thread_delayed_resp.c test_fwk_multi_thread_init_WRAP := fwk_mm_calloc fwk_interrupt_get_current \ osThreadFlagsWait osThreadFlagsSet osThreadNew __fwk_module_get_ctx \ fwk_interrupt_global_disable fwk_interrupt_global_enable \ @@ -123,7 +123,7 @@ test_fwk_multi_thread_init_WRAP := fwk_mm_calloc fwk_interrupt_get_current \ TESTS += test_fwk_multi_thread_create test_fwk_multi_thread_create_SRC := test_fwk_multi_thread_create.c \ - fwk_multi_thread.c fwk_test.c fwk_slist.c fwk_id.c + fwk_multi_thread.c fwk_test.c fwk_slist.c fwk_id.c fwk_thread_delayed_resp.c test_fwk_multi_thread_create_WRAP := fwk_mm_calloc fwk_interrupt_get_current \ osThreadFlagsWait osThreadFlagsSet osThreadNew __fwk_module_get_ctx \ fwk_interrupt_global_disable fwk_interrupt_global_enable \ @@ -135,7 +135,8 @@ test_fwk_multi_thread_create_WRAP := fwk_mm_calloc fwk_interrupt_get_current \ TESTS += test_fwk_multi_thread_common_thread test_fwk_multi_thread_common_thread_SRC := fwk_multi_thread.c fwk_test.c \ - test_fwk_multi_thread_common_thread.c fwk_slist.c fwk_id.c + test_fwk_multi_thread_common_thread.c fwk_slist.c fwk_id.c \ + fwk_thread_delayed_resp.c test_fwk_multi_thread_common_thread_WRAP := fwk_mm_calloc \ osThreadFlagsWait osThreadFlagsSet osThreadNew __fwk_module_get_ctx \ fwk_interrupt_global_disable fwk_interrupt_global_enable \ @@ -147,7 +148,7 @@ test_fwk_multi_thread_common_thread_WRAP := fwk_mm_calloc \ TESTS += test_fwk_multi_thread_put_event test_fwk_multi_thread_put_event_SRC := test_fwk_multi_thread_put_event.c \ - fwk_multi_thread.c fwk_test.c fwk_slist.c fwk_id.c + fwk_multi_thread.c fwk_test.c fwk_slist.c fwk_id.c fwk_thread_delayed_resp.c test_fwk_multi_thread_put_event_WRAP := fwk_mm_calloc __fwk_module_get_state \ fwk_interrupt_get_current osThreadFlagsWait osThreadFlagsSet osThreadNew \ fwk_interrupt_global_disable fwk_interrupt_global_enable \ @@ -159,7 +160,7 @@ test_fwk_multi_thread_put_event_WRAP := fwk_mm_calloc __fwk_module_get_state \ TESTS += test_fwk_multi_thread_util test_fwk_multi_thread_util_SRC := test_fwk_multi_thread_util.c \ - fwk_multi_thread.c fwk_test.c fwk_slist.c fwk_id.c + fwk_multi_thread.c fwk_test.c fwk_slist.c fwk_id.c fwk_thread_delayed_resp.c test_fwk_multi_thread_util_WRAP := fwk_mm_calloc __fwk_module_get_state \ fwk_interrupt_get_current osThreadFlagsWait osThreadFlagsSet osThreadNew \ fwk_interrupt_global_disable fwk_interrupt_global_enable \ -- GitLab From 7994ae890360f25e2d3446f46459e22f5eb6fedd Mon Sep 17 00:00:00 2001 From: Souvik Chakravarty Date: Fri, 18 Oct 2019 17:11:01 +0100 Subject: [PATCH 2/2] fwk: Extend delayed response support Add delayed response support when !BUILD_HAS_MULTITHREADING is not defined. This will enable all build modes to utilize deferred responses. Change-Id: I2c3d6b020ae3a5b9af605c18d6244dea679a913b Tested-by: Nicola Mazzucato Signed-off-by: Souvik Chakravarty --- .../include/internal/fwk_single_thread.h | 5 + framework/src/fwk_thread.c | 99 ++++++++++++++----- framework/test/Makefile | 5 +- framework/test/test_fwk_thread.c | 7 ++ 4 files changed, 92 insertions(+), 24 deletions(-) diff --git a/framework/include/internal/fwk_single_thread.h b/framework/include/internal/fwk_single_thread.h index 90cbf0d54..5d1adeb99 100644 --- a/framework/include/internal/fwk_single_thread.h +++ b/framework/include/internal/fwk_single_thread.h @@ -20,6 +20,11 @@ struct __fwk_thread_ctx { /* Thread framework component initialization completed flag */ bool initialized; + /* + * Counter used to generate event cookies. + */ + uint32_t event_cookie_counter; + /* * Queue of event structures that are free to be filled in and linked * to the event queue or the ISR event queue. diff --git a/framework/src/fwk_thread.c b/framework/src/fwk_thread.c index 97f9a49ac..4a8a84087 100644 --- a/framework/src/fwk_thread.c +++ b/framework/src/fwk_thread.c @@ -8,8 +8,12 @@ * Single-thread facilities. */ -#include -#include +#include +#include +#include +#include +#include + #include #include #include @@ -17,10 +21,9 @@ #include #include #include -#include -#include -#include -#include + +#include +#include static struct __fwk_thread_ctx ctx; @@ -33,26 +36,71 @@ static const char err_msg_func[] = "[THR] Error %d in %s\n"; * Static functions */ -static int put_event(struct fwk_event *event) +/* + * Duplicate an event. + * + * \param event Pointer to the event to duplicate. + * + * \pre \p event must not be NULL + * + * \return The pointer to the duplicated event, NULL if the allocation to + * duplicate the event failed. + */ +static struct fwk_event *duplicate_event(struct fwk_event *event) { - struct fwk_event *free_event; - unsigned int interrupt; + struct fwk_event *allocated_event = NULL; - free_event = FWK_LIST_GET(fwk_list_pop_head(&ctx.free_event_queue), - struct fwk_event, slist_node); + fwk_assert(event != NULL); - if (free_event == NULL) { + fwk_interrupt_global_disable(); + allocated_event = FWK_LIST_GET( + fwk_list_pop_head(&ctx.free_event_queue), struct fwk_event, slist_node); + fwk_interrupt_global_enable(); + + if (allocated_event == NULL) { FWK_HOST_PRINT(err_msg_func, FWK_E_NOMEM, __func__); - assert(false); - return FWK_E_NOMEM; + fwk_assert(false); + } + + *allocated_event = *event; + allocated_event->slist_node = (struct fwk_slist_node){ 0 }; + + return allocated_event; +} + +static int put_event(struct fwk_event *event) +{ + struct fwk_event *allocated_event; + unsigned int interrupt; + + if (event->is_delayed_response) { + allocated_event = __fwk_thread_search_delayed_response( + event->source_id, event->cookie); + if (allocated_event == NULL) { + FWK_HOST_PRINT(err_msg_func, FWK_E_NOMEM, __func__); + return FWK_E_PARAM; + } + + fwk_list_remove( + __fwk_thread_get_delayed_response_list(event->source_id), + &allocated_event->slist_node); + + memcpy( + allocated_event->params, + event->params, + sizeof(allocated_event->params)); + } else { + allocated_event = duplicate_event(event); + if (allocated_event == NULL) + return FWK_E_NOMEM; } - *free_event = *event; + allocated_event->cookie = event->cookie = ctx.event_cookie_counter++; if (fwk_interrupt_get_current(&interrupt) != FWK_SUCCESS) - fwk_list_push_tail(&ctx.event_queue, &free_event->slist_node); + fwk_list_push_tail(&ctx.event_queue, &allocated_event->slist_node); else - fwk_list_push_tail(&ctx.isr_event_queue, &free_event->slist_node); + fwk_list_push_tail(&ctx.isr_event_queue, &allocated_event->slist_node); return FWK_SUCCESS; } @@ -60,7 +108,7 @@ static int put_event(struct fwk_event *event) static void process_next_event(void) { int status; - struct fwk_event *event, async_response_event = {0}; + struct fwk_event *event, *allocated_event, async_response_event = { 0 }; const struct fwk_module *module; int (*process_event)(const struct fwk_event *event, struct fwk_event *resp_event); @@ -78,11 +126,10 @@ static void process_next_event(void) module->process_event; if (event->response_requested) { + async_response_event = *event; async_response_event.source_id = event->target_id; async_response_event.target_id = event->source_id; - async_response_event.id = event->id; - memcpy(&async_response_event.params, &event->params, - sizeof(async_response_event.params)); + async_response_event.is_delayed_response = false; status = process_event(event, &async_response_event); if (status != FWK_SUCCESS) @@ -90,9 +137,17 @@ static void process_next_event(void) async_response_event.is_response = true; async_response_event.response_requested = false; - async_response_event.is_notification = event->is_notification; if (!async_response_event.is_delayed_response) put_event(&async_response_event); + else { + allocated_event = duplicate_event(&async_response_event); + if (allocated_event != NULL) { + fwk_list_push_tail( + __fwk_thread_get_delayed_response_list( + async_response_event.source_id), + &allocated_event->slist_node); + } + } } else { status = process_event(event, &async_response_event); if (status != FWK_SUCCESS) diff --git a/framework/test/Makefile b/framework/test/Makefile index 12a0f2cc0..404b6ac5f 100644 --- a/framework/test/Makefile +++ b/framework/test/Makefile @@ -93,11 +93,12 @@ __fwk_notification_init TESTS += test_fwk_thread test_fwk_thread_SRC := test_fwk_thread.c fwk_thread.c fwk_test.c fwk_slist.c \ - fwk_id.c + fwk_id.c fwk_thread_delayed_resp.c test_fwk_thread_WRAP := fwk_mm_calloc fwk_module_is_valid_entity_id \ fwk_module_is_valid_event_id __fwk_slist_push_tail __fwk_module_get_ctx \ fwk_interrupt_global_enable fwk_interrupt_global_disable \ - fwk_interrupt_get_current fwk_module_is_valid_notification_id + fwk_interrupt_get_current fwk_module_is_valid_notification_id \ + __fwk_module_get_element_ctx TESTS += test_fwk_notification test_fwk_notification_SRC := test_fwk_notification.c fwk_notification.c \ diff --git a/framework/test/test_fwk_thread.c b/framework/test/test_fwk_thread.c index 349a9975e..cb82bc5e5 100644 --- a/framework/test/test_fwk_thread.c +++ b/framework/test/test_fwk_thread.c @@ -21,6 +21,7 @@ static jmp_buf test_context; static struct __fwk_thread_ctx *ctx; +static struct fwk_element_ctx fake_element_ctx; /* Mock functions */ static void * fwk_mm_calloc_val; @@ -72,6 +73,12 @@ bool __wrap_fwk_module_is_valid_notification_id(fwk_id_t id) return is_valid_notification_id_return_val; } +struct fwk_element_ctx *__wrap___fwk_module_get_element_ctx(fwk_id_t id) +{ + (void)id; + return &fake_element_ctx; +} + int __wrap_fwk_interrupt_global_enable(void) { return FWK_SUCCESS; -- GitLab