From 4dac5482e3c9d0b793689de4ab82f48ac829f0ab Mon Sep 17 00:00:00 2001 From: Kapil Gupta Date: Wed, 9 Apr 2025 14:53:08 +0530 Subject: [PATCH] fix(esp_wifi): Add eloop blocking call API for public APIs --- components/wpa_supplicant/port/eloop.c | 125 +++++++++++++++++++- components/wpa_supplicant/src/utils/eloop.h | 16 +++ 2 files changed, 136 insertions(+), 5 deletions(-) diff --git a/components/wpa_supplicant/port/eloop.c b/components/wpa_supplicant/port/eloop.c index 758e78151c..b680c54f08 100644 --- a/components/wpa_supplicant/port/eloop.c +++ b/components/wpa_supplicant/port/eloop.c @@ -6,7 +6,7 @@ * See README for more details. */ /* - * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -19,6 +19,8 @@ #include "esp_wifi_driver.h" #include "rom/ets_sys.h" +bool current_task_is_wifi_task(void); + struct eloop_timeout { struct dl_list list; struct os_reltime time; @@ -29,12 +31,16 @@ struct eloop_timeout { char func_name[100]; int line; #endif + void *sync_semph; + int ret; + eloop_blocking_timeout_handler blocking_handler; }; struct eloop_data { struct dl_list timeout; ETSTimer eloop_timer; bool eloop_started; + void *eloop_semph; }; #define ELOOP_LOCK() os_mutex_lock(eloop_data_lock) @@ -164,6 +170,86 @@ overflow: return 0; } +#ifdef ELOOP_DEBUG +int eloop_register_timeout_blocking_debug(eloop_blocking_timeout_handler handler, void *eloop_data, + void *user_data, const char *func, int line) +#else +int eloop_register_timeout_blocking(eloop_blocking_timeout_handler handler, + void *eloop_data, void *user_data) +#endif +{ + struct eloop_timeout *timeout, *tmp; +#ifdef ELOOP_DEBUG + int count = 0; +#endif + int ret; + + if (current_task_is_wifi_task()) { + assert(false); + return -1; + } + timeout = os_zalloc(sizeof(*timeout)); + if (timeout == NULL) { + return -1; + } + if (os_get_reltime(&timeout->time) < 0) { + os_free(timeout); + return -1; + } + timeout->eloop_data = eloop_data; + timeout->user_data = user_data; + timeout->blocking_handler = handler; +#ifdef ELOOP_DEBUG + os_strlcpy(timeout->func_name, func, 100); + timeout->line = line; +#endif + + ELOOP_LOCK(); + if (!eloop.eloop_semph) { + eloop.eloop_semph = os_semphr_create(1, 0); + } + ELOOP_UNLOCK(); + + if (!eloop.eloop_semph) { + wpa_printf(MSG_INFO, "ELOOP: sync semphr not available"); + os_free(timeout); + return -1; + } + timeout->sync_semph = eloop.eloop_semph; + /* Maintain timeouts in order of increasing time */ + dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) { + if (os_reltime_before(&timeout->time, &tmp->time)) { + ELOOP_LOCK(); + dl_list_add(tmp->list.prev, &timeout->list); + ELOOP_UNLOCK(); + goto run; + } +#ifdef ELOOP_DEBUG + count++; +#endif + } + ELOOP_LOCK(); + dl_list_add_tail(&eloop.timeout, &timeout->list); + ELOOP_UNLOCK(); + +run: +#ifdef ELOOP_DEBUG + wpa_printf(MSG_DEBUG, "ELOOP: Added one blocking timer from %s:%d to call %p, current order=%d", + timeout->func_name, line, timeout->handler, count); +#endif + ELOOP_LOCK(); + os_timer_disarm(&eloop.eloop_timer); + os_timer_arm(&eloop.eloop_timer, 0, 0); + ELOOP_UNLOCK(); + + wpa_printf(MSG_DEBUG, "ELOOP: waiting for sync semphr"); + os_semphr_take(eloop.eloop_semph, OS_BLOCK); + + ret = timeout->ret; + os_free(timeout); + return ret; +} + static bool timeout_exists(struct eloop_timeout *old) { struct eloop_timeout *timeout, *prev; @@ -177,6 +263,18 @@ static bool timeout_exists(struct eloop_timeout *old) return false; } +static void eloop_remove_blocking_timeout(struct eloop_timeout *timeout) +{ + bool timeout_present = false; + ELOOP_LOCK(); + /* Make sure timeout still exists(Another context may have deleted this) */ + timeout_present = timeout_exists(timeout); + if (timeout_present) { + dl_list_del(&timeout->list); + } + ELOOP_UNLOCK(); +} + static void eloop_remove_timeout(struct eloop_timeout *timeout) { bool timeout_present = false; @@ -359,6 +457,7 @@ void eloop_run(void) if (!os_reltime_before(&now, &timeout->time)) { void *eloop_data = timeout->eloop_data; void *user_data = timeout->user_data; + void *sync_semaphr = timeout->sync_semph; eloop_timeout_handler handler = timeout->handler; #ifdef ELOOP_DEBUG @@ -366,12 +465,28 @@ void eloop_run(void) int line = timeout->line; os_strlcpy(fn_name, timeout->func_name, 100); #endif - eloop_remove_timeout(timeout); + /* will be freed in caller context in blocking call */ + if (!sync_semaphr) { + eloop_remove_timeout(timeout); #ifdef ELOOP_DEBUG - wpa_printf(MSG_DEBUG, "ELOOP: Running timer fn:%p scheduled by %s:%d ", - handler, fn_name, line); + wpa_printf(MSG_DEBUG, "ELOOP: Running timer fn:%p scheduled by %s:%d ", + handler, fn_name, line); #endif - handler(eloop_data, user_data); + handler(eloop_data, user_data); + } else { + eloop_remove_blocking_timeout(timeout); + eloop_blocking_timeout_handler handler2 = + timeout->blocking_handler; +#ifdef ELOOP_DEBUG + wpa_printf(MSG_DEBUG, "ELOOP: Running blocking timer fn:%p scheduled by %s:%d ", + handler2, fn_name, line); +#endif + timeout->ret = handler2(eloop_data, user_data); +#ifdef ELOOP_DEBUG + wpa_printf(MSG_DEBUG, "ELOOP: releasing sync semaphor"); +#endif + os_semphr_give(sync_semaphr); + } } } } diff --git a/components/wpa_supplicant/src/utils/eloop.h b/components/wpa_supplicant/src/utils/eloop.h index 0bc8b5d6b3..35f1740f61 100644 --- a/components/wpa_supplicant/src/utils/eloop.h +++ b/components/wpa_supplicant/src/utils/eloop.h @@ -56,6 +56,9 @@ typedef void (*eloop_event_handler)(void *eloop_ctx, void *user_ctx); */ typedef void (*eloop_timeout_handler)(void *eloop_ctx, void *user_ctx); + +typedef int (*eloop_blocking_timeout_handler)(void *eloop_ctx, void *user_ctx); + /** * eloop_signal_handler - eloop signal event callback type * @sig: Signal number @@ -190,6 +193,19 @@ int eloop_register_timeout(unsigned int secs, unsigned int usecs, void *eloop_data, void *user_data); #endif +#ifdef ELOOP_DEBUG +int eloop_register_timeout_blocking_debug(eloop_blocking_timeout_handler handler, void *eloop_data, + void *user_data, const char *func, int line); + +#define eloop_register_timeout_blocking(handler, eloop_data, user_data) \ + eloop_register_timeout_blocking_debug(handler, eloop_data, user_data, __func__, __LINE__) +#else +int eloop_register_timeout_blocking(eloop_blocking_timeout_handler handler, + void *eloop_data, void *user_data); +#endif + + + /** * eloop_cancel_timeout - Cancel timeouts * @handler: Matching callback function