From bc09dda0f4dcafb9c3af0bf1f033edb2a5c13b19 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Mon, 1 Feb 2021 20:56:16 +1100 Subject: [PATCH] docs: Update SMP descriptions for taskENTER_CRITICAL/taskEXIT_CRITICAL Closes https://github.com/espressif/esp-idf/issues/6259 --- .../port/xtensa/include/freertos/portmacro.h | 2 +- docs/en/api-guides/freertos-smp.rst | 53 ++++++++++--------- 2 files changed, 28 insertions(+), 27 deletions(-) diff --git a/components/freertos/port/xtensa/include/freertos/portmacro.h b/components/freertos/port/xtensa/include/freertos/portmacro.h index a0db55850c..5efd1bc68c 100644 --- a/components/freertos/port/xtensa/include/freertos/portmacro.h +++ b/components/freertos/port/xtensa/include/freertos/portmacro.h @@ -134,7 +134,7 @@ do not disable the interrupts (because they already are). This all assumes that interrupts are either entirely disabled or enabled. Interrupt priority levels will break this scheme. -Remark: For the ESP32, portENTER_CRITICAL and portENTER_CRITICAL_ISR both alias vTaskEnterCritical, meaning +Remark: For the ESP32, portENTER_CRITICAL and portENTER_CRITICAL_ISR both alias vPortEnterCritical, meaning that either function can be called both from ISR as well as task context. This is not standard FreeRTOS behaviour; please keep this in mind if you need any compatibility with other FreeRTOS implementations. */ diff --git a/docs/en/api-guides/freertos-smp.rst b/docs/en/api-guides/freertos-smp.rst index cfd4c0e041..661f5c1be2 100644 --- a/docs/en/api-guides/freertos-smp.rst +++ b/docs/en/api-guides/freertos-smp.rst @@ -223,7 +223,7 @@ In vanilla FreeRTOS, suspending the scheduler via :cpp:func:`vTaskSuspendAll` wi prevent calls of ``vTaskSwitchContext`` from context switching until the scheduler has been resumed with :cpp:func:`xTaskResumeAll`. However servicing ISRs are still permitted. Therefore any changes in task states as a result from the -current running task or ISRSs will not be executed until the scheduler is +current running task or ISRs will not be executed until the scheduler is resumed. Scheduler suspension in vanilla FreeRTOS is a common protection method against simultaneous access of data shared between tasks, whilst still allowing ISRs to be serviced. @@ -279,15 +279,14 @@ to unblock multiple tasks at the same time. Critical Sections & Disabling Interrupts ---------------------------------------- -Vanilla FreeRTOS implements critical sections in ``vTaskEnterCritical`` which -disables the scheduler and calls ``portDISABLE_INTERRUPTS``. This prevents -context switches and servicing of ISRs during a critical section. Therefore, -critical sections are used as a valid protection method against simultaneous -access in vanilla FreeRTOS. +Vanilla FreeRTOS implements critical sections with ``taskENTER_CRITICAL()`` which +calls ``portDISABLE_INTERRUPTS()``. This prevents preemptive context switches and +servicing of ISRs during a critical section. Therefore, critical sections are +used as a valid protection method against simultaneous access in vanilla FreeRTOS. .. only:: not CONFIG_FREERTOS_UNICORE - On the other hand, the ESP32 has no hardware method for cores to disable each + On the other hand, {IDF_TARGET_NAME} has no hardware method for cores to disable each other’s interrupts. Calling ``portDISABLE_INTERRUPTS()`` will have no effect on the interrupts of the other core. Therefore, disabling interrupts is **NOT** a valid protection method against simultaneous access to shared data as it @@ -299,42 +298,44 @@ access in vanilla FreeRTOS. ESP-IDF contains some modifications to work with dual core concurrency, and the dual core API is used even on a single core only chip. -For this reason, ESP-IDF FreeRTOS implements critical sections using special mutexes, -referred by portMUX_Type objects on top of specific spinlock component -and calls to enter or exit a critical must provide a spinlock object that -is associated with a shared resource requiring access protection. -When entering a critical section in ESP-IDF FreeRTOS, the calling core will disable -its scheduler and interrupts similar to the vanilla FreeRTOS implementation. However, -the calling core will also take the locks whilst the other core is left unaffected during -the critical section. If the other core attempts to take the spinlock, it -will spin until the lock is released. Therefore, the ESP-IDF FreeRTOS -implementation of critical sections allows a core to have protected access to a -shared resource without disabling the other core. The other core will only be -affected if it tries to concurrently access the same resource. +For this reason, ESP-IDF FreeRTOS implements critical sections using special +mutexes, referred by ``portMUX_Type`` objects. These are implemented on top of a +specific spinlock component. Calls to ``taskENTER_CRITICAL`` or +``taskEXIT_CRITICAL`` each provide a spinlock object as an argument. The +spinlock is associated with a shared resource requiring access protection. When +entering a critical section in ESP-IDF FreeRTOS, the calling core will disable +interrupts similar to the vanilla FreeRTOS implementation, and will then take the +spinlock and enter the critical section. The other core is unaffected at this point, +unless it enters its own critical section and attempts to take the same spinlock. +In that case it will spin until the lock is released. Therefore, the ESP-IDF FreeRTOS +implementation of critical sections allows a core to have protected access to a shared +resource without disabling the other core. The other core will only be affected if it +tries to concurrently access the same resource. The ESP-IDF FreeRTOS critical section functions have been modified as follows… - ``taskENTER_CRITICAL(mux)``, ``taskENTER_CRITICAL_ISR(mux)``, ``portENTER_CRITICAL(mux)``, ``portENTER_CRITICAL_ISR(mux)`` are all macro - defined to call :cpp:func:`vTaskEnterCritical` + defined to call internal function :cpp:func:`vPortEnterCritical` - ``taskEXIT_CRITICAL(mux)``, ``taskEXIT_CRITICAL_ISR(mux)``, ``portEXIT_CRITICAL(mux)``, ``portEXIT_CRITICAL_ISR(mux)`` are all macro - defined to call :cpp:func:`vTaskExitCritical` + defined to call internal function :cpp:func:`vPortExitCritical` - ``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:`esp_hw_support/include/soc/spinlock.h` +For more details see :component_file:`esp_hw_support/include/soc/spinlock.h`, +:component_file:`freertos/include/freertos/task.h`, and :component_file:`freertos/tasks.c` It should be noted that when modifying vanilla FreeRTOS code to be ESP-IDF -FreeRTOS compatible, it is trivial to modify the type of critical section -called as they are all defined to call the same function. As long as the same -spinlock is provided upon entering and exiting, the type of call should not -matter. +FreeRTOS compatible, it is trivial to modify the type of critical section called +as they are all defined to call the same function. As long as the same spinlock +is provided upon entering and exiting, the exact macro or function used for the +call should not matter. .. only:: not CONFIG_FREERTOS_UNICORE