Merge branch 'refactor/freertos_macro_selection' into 'master'

freertos: Add CHOOSE_MACRO_VA_ARG selector

See merge request espressif/esp-idf!16904
This commit is contained in:
Darian 2022-02-08 06:48:14 +00:00
commit a00117cb7f
5 changed files with 89 additions and 67 deletions

View File

@ -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

View File

@ -44,6 +44,7 @@
#include <stdio.h>
#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.

View File

@ -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 -----------------------
/**

View File

@ -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 <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <xtensa/config/core.h>
#include <xtensa/xtensa_context.h>
#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 )

View File

@ -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.