blob: a4fd5917e723ba3874f1b81ec640c4fccd6c4bfe [file] [log] [blame]
Ewout van Bekkum660ebba2020-11-11 13:40:10 -08001.. _module-pw_sync_freertos:
2
Ewout van Bekkum258171a2021-11-01 12:46:03 -07003================
Ewout van Bekkum660ebba2020-11-11 13:40:10 -08004pw_sync_freertos
Ewout van Bekkum258171a2021-11-01 12:46:03 -07005================
6This is a set of backends for pw_sync based on FreeRTOS.
7
8--------------------------------
9Critical Section Lock Primitives
10--------------------------------
11
12Mutex & TimedMutex
13==================
14The FreeRTOS backend for the Mutex and TimedMutex use ``StaticSemaphore_t`` as
15the underlying type. It is created using ``xSemaphoreCreateMutexStatic`` as part
16of the constructors and cleaned up using ``vSemaphoreDelete`` in the
17destructors.
18
19.. Note::
20 Static allocation support is required in your FreeRTOS configuration, i.e.
21 ``configSUPPORT_STATIC_ALLOCATION == 1``.
22
23InterruptSpinLock
24=================
25The FreeRTOS backend for InterruptSpinLock is backed by ``UBaseType_t`` and a
26``bool`` which permits these objects to stash the saved interrupt mask and to
27detect accidental recursive locking.
28
29This object uses ``taskENTER_CRITICAL_FROM_ISR`` and
30``taskEXIT_CRITICAL_FROM_ISR`` from interrupt contexts and
31``taskENTER_CRITICAL`` and ``taskEXIT_CRITICAL`` from other contexts.
32
33--------------------
34Signaling Primitives
35--------------------
36
37ThreadNotification & TimedThreadNotification
38============================================
39An optimized FreeRTOS backend for the ThreadNotification and
40TimedThreadNotification is provided using Task Notifications. It is backed by a
41``TaskHandle_t`` and a ``bool`` which permits these objects to track the
42notification value outside of the task's TCB (AKA FreeRTOS Task Notification
43State and Value).
44
45.. Warning::
46 By default this backend uses the task notification at index 0, just like
47 FreeRTOS Stream and Message Buffers. If you want to maintain the state of a
48 task notification across blocking acquiring calls to ThreadNotifications, then
49 you must do one of the following:
50
51 1. Adjust ``PW_SYNC_FREERTOS_CONFIG_THREAD_NOTIFICATION_INDEX`` to an index
52 which does not collide with existing incompatible use.
53 2. Migrate your existing use of task notifications away from index 0.
54 3. Do not use this optimized backend and instead use the binary semaphore
55 backends for ThreadNotifications
56 (``pw_sync:binary_semaphore_thread_notification_backend``).
57
58 You are using any of the following Task Notification APIs, it means you are
59 using notification indices:
60
61 - ``xTaskNotify`` / ``xTaskNotifyIndexed``
62 - ``xTaskNotifyFromISR`` / ``xTaskNotifyIndexedFromISR``
63 - ``xTaskNotifyGive`` / ``xTaskNotifyGiveIndexed``
64 - ``xTaskNotifyGiveFromISR`` / ``xTaskNotifyGiveIndexedFromISR``
65 - ``xTaskNotifyAndQuery`` / ``xTaskNotifyAndQueryIndexed``
66 - ``xTaskNotifyAndQueryFromISR`` / ``xTaskNotifyAndQueryIndexedFromISR``
67 - ``ulTaskNotifyTake`` / ``ulTaskNotifyTakeIndexed``
68 - ``xTaskNotifyWait`` / ``xTaskNotifyWaitIndexed``
69 - ``xTaskNotifyStateClear`` / ``xTaskNotifyStateClearIndexed``
70 - ``ulTaskNotifyValueClear`` / ``ulTaskNotifyValueClearIndexed``
71
72 APIs without ``Indexed`` in the name use index 0 implicitly.
73
74 Prior to FreeRTOS V10.4.0 each task had a single "notification index", and all
75 task notification API functions operated on that implicit index of 0.
76
77This backend is compatible with sharing the notification index
78with native FreeRTOS
79`Stream and Message Buffers <https://www.freertos.org/RTOS-task-notifications.html>`_
80at index 0.
81
82Just like FreeRTOS Stream and Message Buffers, this backend uses the task
83notification index only within callsites where the task must block until a
84notification is received or a timeout occurs. The notification index's state is
85always cleaned up before returning. The notification index is never used when
86the acquiring task is not going to block.
87
88.. Note::
89 Task notification support is required in your FreeRTOS configuration, i.e.
90 ``configUSE_TASK_NOTIFICATIONS == 1``.
91
92Design Notes
93------------
94You may ask, why are Task Notifications used at all given the risk associated
95with global notification index allocations? It turns out there's no other
96lightweight mechanism to unblock a task in FreeRTOS.
97
98Task suspension (i.e. ``vTaskSuspend``, ``vTaskResume``, &
99``vTaskResumeFromISR``) seems like a good fit, however ``xTaskResumeAll`` does
100not participate in reference counting and will wake up all suspended tasks
101whether you want it to or not.
102
103Lastly, there's also ``xTaskAbortDelay`` but there is no interrupt safe
104equivalent of this API. Note that it uses ``vTaskSuspendAll`` internally for
105the critical section which is not interrupt safe. If in the future an interrupt
106safe version of this API is offerred, then this would be a great alternative!
107
108Lastly, we want to briefly explain how Task Notifications actually work in
109FreeRTOS to show why you cannot directly share notification indeces even if the
110bits used in the ``ulNotifiedValue`` are unique. This is a very common source of
111bugs when using FreeRTOS and partially why Pigweed does not recommend using the
112native Task Notification APIs directly.
113
114FreeRTOS Task Notifications use a task's TCB's ``ucNotifyState`` to capture the
115notification state even when the task is not blocked. This state transitions
116``taskNOT_WAITING_NOTIFICATION`` to ``task_NOTIFICATION_RECEIVED`` if the task
117ever notified. This notification state is used to determine whether the next
118task notification wait call should block, irrespective of the notification
119value.
120
121In order to enable this optimized backend, native task notifications are only
122used when the task needs to block. If a timeout occurs the task unregisters for
123notifications and clears the notification state before returning. This exact
124mechanism is used by FreeRTOS internally for their Stream and Message Buffer
125implementations.
126
127BinarySemaphore
128===============
129The FreeRTOS backend for the BinarySemaphore uses ``StaticSemaphore_t`` as the
130underlying type. It is created using ``xSemaphoreCreateBinaryStatic`` as part
131of the constructor and cleaned up using ``vSemaphoreDelete`` in the destructor.
132
133.. Note::
134 Static allocation support is required in your FreeRTOS configuration, i.e.
135 ``configSUPPORT_STATIC_ALLOCATION == 1``.
136
137CountingSemaphore
138=================
139The FreeRTOS backend for the CountingSemaphore uses ``StaticSemaphore_t`` as the
140underlying type. It is created using ``xSemaphoreCreateCountingStatic`` as part
141of the constructor and cleaned up using ``vSemaphoreDelete`` in the destructor.
142
143.. Note::
144 Counting semaphore support is required in your FreeRTOS configuration, i.e.
145 ``configUSE_COUNTING_SEMAPHORES == 1``.
146.. Note::
147 Static allocation support is required in your FreeRTOS configuration, i.e.
148 ``configSUPPORT_STATIC_ALLOCATION == 1``.
149
Ewout van Bekkum660ebba2020-11-11 13:40:10 -0800150