diff --git a/components/freertos/Kconfig b/components/freertos/Kconfig index 8063c266b..7eeec02b9 100644 --- a/components/freertos/Kconfig +++ b/components/freertos/Kconfig @@ -426,4 +426,11 @@ menu "FreeRTOS" If enabled, assert that when a mutex semaphore is given, the task giving the semaphore is the task which is currently holding the mutex. + config FREERTOS_CHECK_PORT_CRITICAL_COMPLIANCE + bool "Tests compliance with Vanilla FreeRTOS port*_CRITICAL calls" + default n + help + If enabled, context of port*_CRITICAL calls (ISR or Non-ISR) would be checked to be in compliance with Vanilla FreeRTOS. + e.g Calling port*_CRITICAL from ISR context would cause assert failure + endmenu diff --git a/components/freertos/include/freertos/portmacro.h b/components/freertos/include/freertos/portmacro.h index d0023fee9..88da1c0c0 100644 --- a/components/freertos/include/freertos/portmacro.h +++ b/components/freertos/include/freertos/portmacro.h @@ -216,8 +216,23 @@ void vPortCPUReleaseMutex(portMUX_TYPE *mux, const char *function, int line); void vTaskEnterCritical( portMUX_TYPE *mux, const char *function, int line ); void vTaskExitCritical( portMUX_TYPE *mux, const char *function, int line ); + +#ifdef CONFIG_FREERTOS_CHECK_PORT_CRITICAL_COMPLIANCE +/* Calling port*_CRITICAL from ISR context would cause an assert failure. + * If the parent function is called from both ISR and Non-ISR context then call port*_CRITICAL_SAFE + **/ +#define portENTER_CRITICAL(mux) do { \ + configASSERT(!xPortInIsrContext()); \ + vTaskEnterCritical(mux, __FUNCTION__, __LINE__); \ + } while(0) +#define portEXIT_CRITICAL(mux) do { \ + configASSERT(!xPortInIsrContext()); \ + vTaskExitCritical(mux, __FUNCTION__, __LINE__); \ + } while(0) +#else #define portENTER_CRITICAL(mux) vTaskEnterCritical(mux, __FUNCTION__, __LINE__) #define portEXIT_CRITICAL(mux) vTaskExitCritical(mux, __FUNCTION__, __LINE__) +#endif #define portENTER_CRITICAL_ISR(mux) vTaskEnterCritical(mux, __FUNCTION__, __LINE__) #define portEXIT_CRITICAL_ISR(mux) vTaskExitCritical(mux, __FUNCTION__, __LINE__) #else @@ -236,12 +251,43 @@ void vPortCPUAcquireMutex(portMUX_TYPE *mux); bool vPortCPUAcquireMutexTimeout(portMUX_TYPE *mux, int timeout_cycles); void vPortCPUReleaseMutex(portMUX_TYPE *mux); +#ifdef CONFIG_FREERTOS_CHECK_PORT_CRITICAL_COMPLIANCE +/* Calling port*_CRITICAL from ISR context would cause an assert failure. + * If the parent function is called from both ISR and Non-ISR context then call port*_CRITICAL_SAFE + **/ +#define portENTER_CRITICAL(mux) do { \ + configASSERT(!xPortInIsrContext()); \ + vTaskEnterCritical(mux); \ + } while(0) +#define portEXIT_CRITICAL(mux) do { \ + configASSERT(!xPortInIsrContext()); \ + vTaskExitCritical(mux); \ + } while(0) +#else #define portENTER_CRITICAL(mux) vTaskEnterCritical(mux) #define portEXIT_CRITICAL(mux) vTaskExitCritical(mux) +#endif #define portENTER_CRITICAL_ISR(mux) vTaskEnterCritical(mux) #define portEXIT_CRITICAL_ISR(mux) vTaskExitCritical(mux) #endif +#define portENTER_CRITICAL_SAFE(mux) do { \ + if (xPortInIsrContext()) { \ + portENTER_CRITICAL_ISR(mux); \ + } else { \ + portENTER_CRITICAL(mux); \ + } \ + } while(0) + +#define portEXIT_CRITICAL_SAFE(mux) do { \ + if (xPortInIsrContext()) { \ + portEXIT_CRITICAL_ISR(mux); \ + } else { \ + portEXIT_CRITICAL(mux); \ + } \ + } while(0) + + // Critical section management. NW-TODO: replace XTOS_SET_INTLEVEL with more efficient version, if any? // These cannot be nested. They should be used with a lot of care and cannot be called from interrupt level. // diff --git a/docs/en/api-guides/freertos-smp.rst b/docs/en/api-guides/freertos-smp.rst index 96738c45a..5e765a00a 100644 --- a/docs/en/api-guides/freertos-smp.rst +++ b/docs/en/api-guides/freertos-smp.rst @@ -377,6 +377,11 @@ The ESP-IDF FreeRTOS critical section functions have been modified as follows… ``portEXIT_CRITICAL(mux)``, ``portEXIT_CRITICAL_ISR(mux)`` are all macro defined to call :cpp:func:`vTaskExitCritical` + - ``portENTER_CRITICAL_SAFE(mux)``, ``portEXIT_CRITICAL_SAFE(mux)`` macro identifies + the context of execution, i.e ISR or Non-ISR, and calls appropriate critical + section functions (``port*_CRITICAL`` in Non-ISR and ``port*_CRITICAL_ISR`` in ISR) + in order to be in compliance with Vanilla FreeRTOS. + For more details see :component_file:`freertos/include/freertos/portmacro.h` and :component_file:`freertos/task.c`