diff --git a/components/freertos/Kconfig b/components/freertos/Kconfig index 8ec085e14..7eeec02b9 100644 --- a/components/freertos/Kconfig +++ b/components/freertos/Kconfig @@ -419,4 +419,18 @@ menu "FreeRTOS" abort the application. This option is also required for GDB backtraces and C++ exceptions to work correctly inside top-level task functions. + config FREERTOS_CHECK_MUTEX_GIVEN_BY_OWNER + bool "Check that mutex semaphore is given by owner task" + default y + help + 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 adeb3bb00..4072b65b4 100644 --- a/components/freertos/include/freertos/portmacro.h +++ b/components/freertos/include/freertos/portmacro.h @@ -209,8 +209,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 @@ -229,12 +244,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`