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.
pull/13090/head
Ivan Grokhotkov 2023-11-27 14:32:52 +01:00
rodzic 66431a62d1
commit f5cd3b7ff4
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 1E050E141B280628
2 zmienionych plików z 9 dodań i 7 usunięć

Wyświetl plik

@ -99,11 +99,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()
@ -182,7 +181,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()
# Disable strict prototype warnings in upstream code

Wyświetl plik

@ -4,6 +4,8 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include <pthread.h>
#include <dlfcn.h>
#include <sys/types.h>
#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;