.. _module-pw_sync_freertos: ================ pw_sync_freertos ================ This is a set of backends for pw_sync based on FreeRTOS. -------------------------------- Critical Section Lock Primitives -------------------------------- Mutex & TimedMutex ================== The FreeRTOS backend for the Mutex and TimedMutex use ``StaticSemaphore_t`` as the underlying type. It is created using ``xSemaphoreCreateMutexStatic`` as part of the constructors and cleaned up using ``vSemaphoreDelete`` in the destructors. .. Note:: Static allocation support is required in your FreeRTOS configuration, i.e. ``configSUPPORT_STATIC_ALLOCATION == 1``. InterruptSpinLock ================= The FreeRTOS backend for InterruptSpinLock is backed by ``UBaseType_t`` and a ``bool`` which permits these objects to stash the saved interrupt mask and to detect accidental recursive locking. This object uses ``taskENTER_CRITICAL_FROM_ISR`` and ``taskEXIT_CRITICAL_FROM_ISR`` from interrupt contexts and ``taskENTER_CRITICAL`` and ``taskEXIT_CRITICAL`` from other contexts. -------------------- Signaling Primitives -------------------- ThreadNotification & TimedThreadNotification ============================================ An optimized FreeRTOS backend for the ThreadNotification and TimedThreadNotification is provided using Task Notifications. It is backed by a ``TaskHandle_t`` and a ``bool`` which permits these objects to track the notification value outside of the task's TCB (AKA FreeRTOS Task Notification State and Value). .. Warning:: By default this backend uses the task notification at index 0, just like FreeRTOS Stream and Message Buffers. If you want to maintain the state of a task notification across blocking acquiring calls to ThreadNotifications, then you must do one of the following: 1. Adjust ``PW_SYNC_FREERTOS_CONFIG_THREAD_NOTIFICATION_INDEX`` to an index which does not collide with existing incompatible use. 2. Migrate your existing use of task notifications away from index 0. 3. Do not use this optimized backend and instead use the binary semaphore backends for ThreadNotifications (``pw_sync:binary_semaphore_thread_notification_backend``). You are using any of the following Task Notification APIs, it means you are using notification indices: - ``xTaskNotify`` / ``xTaskNotifyIndexed`` - ``xTaskNotifyFromISR`` / ``xTaskNotifyIndexedFromISR`` - ``xTaskNotifyGive`` / ``xTaskNotifyGiveIndexed`` - ``xTaskNotifyGiveFromISR`` / ``xTaskNotifyGiveIndexedFromISR`` - ``xTaskNotifyAndQuery`` / ``xTaskNotifyAndQueryIndexed`` - ``xTaskNotifyAndQueryFromISR`` / ``xTaskNotifyAndQueryIndexedFromISR`` - ``ulTaskNotifyTake`` / ``ulTaskNotifyTakeIndexed`` - ``xTaskNotifyWait`` / ``xTaskNotifyWaitIndexed`` - ``xTaskNotifyStateClear`` / ``xTaskNotifyStateClearIndexed`` - ``ulTaskNotifyValueClear`` / ``ulTaskNotifyValueClearIndexed`` APIs without ``Indexed`` in the name use index 0 implicitly. Prior to FreeRTOS V10.4.0 each task had a single "notification index", and all task notification API functions operated on that implicit index of 0. This backend is compatible with sharing the notification index with native FreeRTOS `Stream and Message Buffers `_ at index 0. Just like FreeRTOS Stream and Message Buffers, this backend uses the task notification index only within callsites where the task must block until a notification is received or a timeout occurs. The notification index's state is always cleaned up before returning. The notification index is never used when the acquiring task is not going to block. .. Note:: Task notification support is required in your FreeRTOS configuration, i.e. ``configUSE_TASK_NOTIFICATIONS == 1``. Design Notes ------------ You may ask, why are Task Notifications used at all given the risk associated with global notification index allocations? It turns out there's no other lightweight mechanism to unblock a task in FreeRTOS. Task suspension (i.e. ``vTaskSuspend``, ``vTaskResume``, & ``vTaskResumeFromISR``) seems like a good fit, however ``xTaskResumeAll`` does not participate in reference counting and will wake up all suspended tasks whether you want it to or not. Lastly, there's also ``xTaskAbortDelay`` but there is no interrupt safe equivalent of this API. Note that it uses ``vTaskSuspendAll`` internally for the critical section which is not interrupt safe. If in the future an interrupt safe version of this API is offerred, then this would be a great alternative! Lastly, we want to briefly explain how Task Notifications actually work in FreeRTOS to show why you cannot directly share notification indeces even if the bits used in the ``ulNotifiedValue`` are unique. This is a very common source of bugs when using FreeRTOS and partially why Pigweed does not recommend using the native Task Notification APIs directly. FreeRTOS Task Notifications use a task's TCB's ``ucNotifyState`` to capture the notification state even when the task is not blocked. This state transitions ``taskNOT_WAITING_NOTIFICATION`` to ``task_NOTIFICATION_RECEIVED`` if the task ever notified. This notification state is used to determine whether the next task notification wait call should block, irrespective of the notification value. In order to enable this optimized backend, native task notifications are only used when the task needs to block. If a timeout occurs the task unregisters for notifications and clears the notification state before returning. This exact mechanism is used by FreeRTOS internally for their Stream and Message Buffer implementations. BinarySemaphore =============== The FreeRTOS backend for the BinarySemaphore uses ``StaticSemaphore_t`` as the underlying type. It is created using ``xSemaphoreCreateBinaryStatic`` as part of the constructor and cleaned up using ``vSemaphoreDelete`` in the destructor. .. Note:: Static allocation support is required in your FreeRTOS configuration, i.e. ``configSUPPORT_STATIC_ALLOCATION == 1``. CountingSemaphore ================= The FreeRTOS backend for the CountingSemaphore uses ``StaticSemaphore_t`` as the underlying type. It is created using ``xSemaphoreCreateCountingStatic`` as part of the constructor and cleaned up using ``vSemaphoreDelete`` in the destructor. .. Note:: Counting semaphore support is required in your FreeRTOS configuration, i.e. ``configUSE_COUNTING_SEMAPHORES == 1``. .. Note:: Static allocation support is required in your FreeRTOS configuration, i.e. ``configSUPPORT_STATIC_ALLOCATION == 1``.