diff --git a/components/esp_common/include/esp_macro.h b/components/esp_common/include/esp_macro.h new file mode 100644 index 0000000000..b7b7fafaeb --- /dev/null +++ b/components/esp_common/include/esp_macro.h @@ -0,0 +1,46 @@ +/* + * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +/* +This header contains various general purpose helper macros used across ESP-IDF +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Macro to select different versions of other macros based on whether VA_ARGS has an argument or no argument + * + * Some macros (such as in FreeRTOS) have two versions (one that accepts arguments and another that does not). The + * following "CHOOSE_MACRO_VA_ARG" selector allows automatic selection between two different versions of a macro. + * + * "CHOOSE_MACRO_VA_ARG" make use of the fact that "##__VA_ARGS__," will eliminate the trailing comma if there are no + * arguments, thus allows subsequent arguments in "CHOOSE_MACRO_VA_ARG" to be left shifted in the parameter list. + * Therefore, if we call "CHOOSE_MACRO_VA_ARG(_0, ##__VA_ARGS__, MACRO1, MACRO2)(__VA_ARGS__)", the result will be: + * + * - MACRO1(__VA_ARGS__) if __VA_ARGS__ was not empty + * - MACRO2() if __VA_ARGS__ was empty + * + * @note In the future, we want to switch to C++20. We also want to become compatible with clang. Hence, we provide two + * versions of the following macros which are using variadic arguments. The first one is using the GNU extension + * ##__VA_ARGS__. The second one is using the C++20 feature __VA_OPT__(,). This allows users to compile their code with + * standard C++20 enabled instead of the GNU extension. Below C++20, we haven't found any good alternative to using + * ##__VA_ARGS__. + */ +#if defined(__cplusplus) && (__cplusplus > 201703L) +#define CHOOSE_MACRO_VA_ARG(_0 __VA_OPT__(,) __VA_ARGS__, MACRO, ...) MACRO +#else +#define CHOOSE_MACRO_VA_ARG(_0, _1, MACRO, ...) MACRO +#endif +_Static_assert(CHOOSE_MACRO_VA_ARG(_0, x, 0, 1) == 0, "CHOOSE_MACRO_VA_ARG() result does not match for 0 arguments"); +_Static_assert(CHOOSE_MACRO_VA_ARG(_0, 0, 1) == 1, "CHOOSE_MACRO_VA_ARG() result does not match for 1 argument"); + +#ifdef __cplusplus +} +#endif diff --git a/components/freertos/FreeRTOS-Kernel/portable/riscv/include/freertos/portmacro.h b/components/freertos/FreeRTOS-Kernel/portable/riscv/include/freertos/portmacro.h index 36f1da5134..b80f794f4a 100644 --- a/components/freertos/FreeRTOS-Kernel/portable/riscv/include/freertos/portmacro.h +++ b/components/freertos/FreeRTOS-Kernel/portable/riscv/include/freertos/portmacro.h @@ -44,6 +44,7 @@ #include #include "soc/spinlock.h" #include "soc/interrupt_core0_reg.h" +#include "esp_macro.h" #include "esp_attr.h" #include "esp_rom_sys.h" #include "esp_timer.h" /* required for FreeRTOS run time stats */ @@ -58,8 +59,6 @@ extern "C" { #endif - - /* --------------------------------------------------- Port Types ------------------------------------------------------ * - Port specific types. * - The settings in this file configure FreeRTOS correctly for the given hardware and compiler. @@ -383,7 +382,24 @@ static inline BaseType_t IRAM_ATTR xPortGetCoreID(void) // ---------------------- Yielding ------------------------- #define portYIELD() vPortYield() -#define portYIELD_FROM_ISR() vPortYieldFromISR() +#define portYIELD_FROM_ISR_NO_ARG() vPortYieldFromISR() +#define portYIELD_FROM_ISR_ARG(xHigherPriorityTaskWoken) ({ \ + if (xHigherPriorityTaskWoken == pdTRUE) { \ + vPortYieldFromISR(); \ + } \ +}) +/** + * @note The macro below could be used when passing a single argument, or without any argument, + * it was developed to support both usages of portYIELD inside of an ISR. Any other usage form + * might result in undesired behavior + */ +#if defined(__cplusplus) && (__cplusplus > 201703L) +#define portYIELD_FROM_ISR(...) CHOOSE_MACRO_VA_ARG(_0 __VA_OPT__(,) ##__VA_ARGS__, portYIELD_FROM_ISR_ARG, portYIELD_FROM_ISR_NO_ARG)(__VA_ARGS__) +#else +#define portYIELD_FROM_ISR(...) CHOOSE_MACRO_VA_ARG(_0, ##__VA_ARGS__, portYIELD_FROM_ISR_ARG, portYIELD_FROM_ISR_NO_ARG)(__VA_ARGS__) +#endif + + #define portEND_SWITCHING_ISR(xSwitchRequired) if(xSwitchRequired) vPortYield() /* Yielding within an API call (when interrupts are off), means the yield should be delayed until interrupts are re-enabled. diff --git a/components/freertos/FreeRTOS-Kernel/portable/xtensa/include/freertos/portmacro.h b/components/freertos/FreeRTOS-Kernel/portable/xtensa/include/freertos/portmacro.h index cc7dd588fe..b60b90ce9e 100644 --- a/components/freertos/FreeRTOS-Kernel/portable/xtensa/include/freertos/portmacro.h +++ b/components/freertos/FreeRTOS-Kernel/portable/xtensa/include/freertos/portmacro.h @@ -74,6 +74,7 @@ #include "soc/spinlock.h" #include "hal/cpu_hal.h" #include "esp_private/crosscore_int.h" +#include "esp_macro.h" #include "esp_attr.h" #include "esp_timer.h" /* required for esp_timer_get_time. [refactor-todo] make this common between archs */ #include "esp_newlib.h" /* required for esp_reent_init() in tasks.c */ @@ -92,7 +93,6 @@ extern "C" { #endif - /* --------------------------------------------------- Port Types ------------------------------------------------------ * - Port specific types. * - The settings in this file configure FreeRTOS correctly for the given hardware and compiler. @@ -339,15 +339,6 @@ static inline void __attribute__((always_inline)) vPortExitCriticalSafe(portMUX_ */ void vPortYield( void ); -/** - * @brief - * - * @note [refactor-todo] Refactor this to avoid va_args - * @param argc - * @param ... Variable arguments to allow for IDF prototype without arguments, and vanilla version WITH argument - */ -void vPortEvaluateYieldFromISR(int argc, ...); - /** * @brief Yields the other core * @@ -517,17 +508,28 @@ static inline void __attribute__((always_inline)) uxPortCompareSetExtram(volatil #define portYIELD() vPortYield() +extern void _frxt_setup_switch( void ); //Defined in portasm.S + +#define portYIELD_FROM_ISR_NO_ARG() ({ \ + traceISR_EXIT_TO_SCHEDULER(); \ + _frxt_setup_switch(); \ +}) +#define portYIELD_FROM_ISR_ARG(xHigherPriorityTaskWoken) ({ \ + if (xHigherPriorityTaskWoken == pdTRUE) { \ + traceISR_EXIT_TO_SCHEDULER(); \ + _frxt_setup_switch(); \ + } \ +}) + /** * @note The macro below could be used when passing a single argument, or without any argument, * it was developed to support both usages of portYIELD inside of an ISR. Any other usage form * might result in undesired behavior - * - * @note [refactor-todo] Refactor this to avoid va_args */ #if defined(__cplusplus) && (__cplusplus > 201703L) -#define portYIELD_FROM_ISR(...) vPortEvaluateYieldFromISR(portGET_ARGUMENT_COUNT(__VA_ARGS__) __VA_OPT__(,) __VA_ARGS__) +#define portYIELD_FROM_ISR(...) CHOOSE_MACRO_VA_ARG(_0 __VA_OPT__(,) ##__VA_ARGS__, portYIELD_FROM_ISR_ARG, portYIELD_FROM_ISR_NO_ARG)(__VA_ARGS__) #else -#define portYIELD_FROM_ISR(...) vPortEvaluateYieldFromISR(portGET_ARGUMENT_COUNT(__VA_ARGS__), ##__VA_ARGS__) +#define portYIELD_FROM_ISR(...) CHOOSE_MACRO_VA_ARG(_0, ##__VA_ARGS__, portYIELD_FROM_ISR_ARG, portYIELD_FROM_ISR_NO_ARG)(__VA_ARGS__) #endif /* Yielding within an API call (when interrupts are off), means the yield should be delayed @@ -723,28 +725,6 @@ void vPortStoreTaskMPUSettings( xMPU_SETTINGS *xMPUSettings, const struct xMEMOR void vPortReleaseTaskMPUSettings( xMPU_SETTINGS *xMPUSettings ); #endif -// -------------------- VA_ARGS Yield ---------------------- - -/** - * Macro to count number of arguments of a __VA_ARGS__ used to support portYIELD_FROM_ISR with, - * or without arguments. The macro counts only 0 or 1 arguments. - * - * In the future, we want to switch to C++20. We also want to become compatible with clang. - * Hence, we provide two versions of the following macros which are using variadic arguments. - * The first one is using the GNU extension ##__VA_ARGS__. The second one is using the C++20 feature __VA_OPT__(,). - * This allows users to compile their code with standard C++20 enabled instead of the GNU extension. - * Below C++20, we haven't found any good alternative to using ##__VA_ARGS__. - */ -#if defined(__cplusplus) && (__cplusplus > 201703L) -#define portGET_ARGUMENT_COUNT(...) portGET_ARGUMENT_COUNT_INNER(0 __VA_OPT__(,) __VA_ARGS__,1,0) -#else -#define portGET_ARGUMENT_COUNT(...) portGET_ARGUMENT_COUNT_INNER(0, ##__VA_ARGS__,1,0) -#endif -#define portGET_ARGUMENT_COUNT_INNER(zero, one, count, ...) count - -_Static_assert(portGET_ARGUMENT_COUNT() == 0, "portGET_ARGUMENT_COUNT() result does not match for 0 arguments"); -_Static_assert(portGET_ARGUMENT_COUNT(1) == 1, "portGET_ARGUMENT_COUNT() result does not match for 1 argument"); - // -------------------- Heap Related ----------------------- /** diff --git a/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c b/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c index fee570466f..ea021da27c 100644 --- a/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c +++ b/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c @@ -1,3 +1,11 @@ +/* + * SPDX-FileCopyrightText: 2017 Amazon.com, Inc. or its affiliates + * SPDX-FileCopyrightText: 2015-2019 Cadence Design Systems, Inc. + * + * SPDX-License-Identifier: MIT + * + * SPDX-FileContributor: 2016-2022 Espressif Systems (Shanghai) CO LTD + */ /* * FreeRTOS Kernel V10.4.3 * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. @@ -53,7 +61,6 @@ #include #include #include -#include #include #include #include "soc/soc_caps.h" @@ -354,32 +361,6 @@ void vPortYieldOtherCore( BaseType_t coreid ) esp_crosscore_int_send_yield( coreid ); } -extern void _frxt_setup_switch( void ); //Defined in portasm.S - -void IRAM_ATTR vPortEvaluateYieldFromISR(int argc, ...) -{ - BaseType_t xYield; - va_list ap; - va_start(ap, argc); - - if (argc) { - xYield = (BaseType_t)va_arg(ap, int); - va_end(ap); - } else { - //it is a empty parameter vPortYieldFromISR macro call: - va_end(ap); - traceISR_EXIT_TO_SCHEDULER(); - _frxt_setup_switch(); - return; - } - - //Yield exists, so need evaluate it first then switch: - if (xYield == pdTRUE) { - traceISR_EXIT_TO_SCHEDULER(); - _frxt_setup_switch(); - } -} - // ------------------- Hook Functions ---------------------- void __attribute__((weak)) vApplicationStackOverflowHook( TaskHandle_t xTask, char *pcTaskName ) diff --git a/components/log/include/esp_log.h b/components/log/include/esp_log.h index 84ec2866dc..86bdfb30d3 100644 --- a/components/log/include/esp_log.h +++ b/components/log/include/esp_log.h @@ -298,7 +298,6 @@ void esp_log_writev(esp_log_level_t level, const char* tag, const char* format, /// macro to output logs in startup code, before heap allocator and syscalls have been initialized. /// Log at ``ESP_LOG_ERROR`` level. @see ``printf``,``ESP_LOGE``,``ESP_DRAM_LOGE`` -#define portGET_ARGUMENT_COUNT_INNER(zero, one, count, ...) count /** * In the future, we want to switch to C++20. We also want to become compatible with clang.