From 4e253754398869b32708004efa00789134bb05af Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Mon, 27 Nov 2023 14:32:52 +0100 Subject: [PATCH] fix(freertos): override select function without relying on -Wl,--wrap This commit changes the approach used to override select function in FreeRTOS simulator. The previous approach relied on '--wrap', which is a feature of GNU linker that performs symbol substitution at link time. Sadly this feature is not present in macOS linker. The alternative solution is to define 'select' wrapper as a regular (exported) symbol, preventing it from being loaded from system libraries. To call the "real" select implementation we use dlsym function and find the function pointer at run time. This solution works on both Linux and macOS. --- components/freertos/CMakeLists.txt | 7 +++---- .../freertos/esp_additions/FreeRTOSSimulator_wrappers.c | 9 ++++++--- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/components/freertos/CMakeLists.txt b/components/freertos/CMakeLists.txt index ed7efd5785..c32ef96323 100644 --- a/components/freertos/CMakeLists.txt +++ b/components/freertos/CMakeLists.txt @@ -100,11 +100,10 @@ list(APPEND srcs if(arch STREQUAL "linux") # Check if we need to address the FreeRTOS EINTR coexistence with linux system calls if we're building without - # lwIP, we need to use linux system select which will receive EINTR event on every FreeRTOS interrupt, we + # lwIP enabled, we need to use linux system select which will receive EINTR event on every FreeRTOS interrupt, we # workaround this problem by wrapping select() to bypass and silence the EINTR events set(BYPASS_EINTR_ISSUE 0) - idf_build_get_property(build_components BUILD_COMPONENTS) - if(NOT "lwip" IN_LIST build_components) + if(NOT CONFIG_LWIP_ENABLE) set(BYPASS_EINTR_ISSUE 1) list(APPEND srcs "esp_additions/FreeRTOSSimulator_wrappers.c") endif() @@ -183,7 +182,7 @@ if(arch STREQUAL "linux") target_compile_definitions(${COMPONENT_LIB} PUBLIC "projCOVERAGE_TEST=0") target_link_libraries(${COMPONENT_LIB} PUBLIC pthread) if(BYPASS_EINTR_ISSUE) - target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--wrap=select") + target_link_libraries(${COMPONENT_LIB} PRIVATE dl) endif() else() idf_component_get_property(COMPONENT_DIR freertos COMPONENT_DIR) diff --git a/components/freertos/esp_additions/FreeRTOSSimulator_wrappers.c b/components/freertos/esp_additions/FreeRTOSSimulator_wrappers.c index 7084eaf82c..0e5c211584 100644 --- a/components/freertos/esp_additions/FreeRTOSSimulator_wrappers.c +++ b/components/freertos/esp_additions/FreeRTOSSimulator_wrappers.c @@ -4,6 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ #include +#include +#include #include "esp_err.h" #include "errno.h" @@ -12,7 +14,7 @@ * EINTR event on every FreeRTOS interrupt; we workaround this problem by wrapping select() * to bypass and silence these events. */ -extern int __real_select (int fd, fd_set * rfds, fd_set * wfds, fd_set *efds, struct timeval *tval); +typedef int (*select_func_t) (int fd, fd_set * rfds, fd_set * wfds, fd_set *efds, struct timeval *tval); static inline int64_t get_us(void) { @@ -21,13 +23,14 @@ static inline int64_t get_us(void) return spec.tv_nsec / 1000 + spec.tv_sec * 1000000; } -int __wrap_select (int fd, fd_set * rfds, fd_set * wfds, fd_set *efds, struct timeval *tval) +int select (int fd, fd_set * rfds, fd_set * wfds, fd_set *efds, struct timeval *tval) { int ret; struct timeval *tv = tval; struct timeval timeval_local = {}; int64_t start = 0; int64_t timeout_us = 0; + select_func_t real_select = (select_func_t) dlsym(RTLD_NEXT, "select"); if (tv != NULL) { start = get_us(); timeout_us = tval->tv_sec * 1000000 + tval->tv_usec; @@ -35,7 +38,7 @@ int __wrap_select (int fd, fd_set * rfds, fd_set * wfds, fd_set *efds, struct ti timeval_local.tv_usec = tval->tv_usec; tv = &timeval_local; // this (tv != NULL) indicates that we should handle timeouts } - while ((ret = __real_select(fd, rfds, wfds, efds, tv)) < 0 && errno == EINTR) { + while ((ret = real_select(fd, rfds, wfds, efds, tv)) < 0 && errno == EINTR) { if (tv != NULL) { int64_t now = get_us(); timeout_us -= now - start;