blob: 86e1f0c3901e7818bbd0f64fe634bfc59ac37efc [file] [log] [blame]
Ewout van Bekkum58901932020-11-09 12:46:52 -08001.. _module-pw_sync:
2
Ewout van Bekkumf84638b2021-03-12 16:09:08 -08003=======
Ewout van Bekkum58901932020-11-09 12:46:52 -08004pw_sync
Ewout van Bekkumf84638b2021-03-12 16:09:08 -08005=======
6The ``pw_sync`` module contains utilities for synchronizing between threads
7and/or interrupts through signaling primitives and critical section lock
8primitives.
Ewout van Bekkum58901932020-11-09 12:46:52 -08009
Ewout van Bekkumf84638b2021-03-12 16:09:08 -080010.. contents::
11 :local:
12 :depth: 2
13
14.. Warning::
15 This module is still under construction, the API is not yet stable.
16
17.. Note::
18 The objects in this module do not have an Init() style public API which is
19 common in many RTOS C APIs. Instead, they rely on being able to invoke the
20 native initialization APIs for synchronization primitives during C++
21 construction.
22 In order to support global statically constructed synchronization without
23 constexpr constructors, the user and/or backend **MUST** ensure that any
24 initialization required in your environment is done prior to the creation
25 and/or initialization of the native synchronization primitives
26 (e.g. kernel initialization).
27
28--------------------------------
29Critical Section Lock Primitives
30--------------------------------
31The critical section lock primitives provided by this module comply with
32`BasicLockable <https://en.cppreference.com/w/cpp/named_req/BasicLockable>`_,
33`Lockable <https://en.cppreference.com/w/cpp/named_req/Lockable>`_, and where
34relevant
35`TimedLockable <https://en.cppreference.com/w/cpp/named_req/TimedLockable>`_ C++
36named requirements. This means that they are compatible with existing helpers in
37the STL's ``<mutex>`` thread support library. For example `std::lock_guard <https://en.cppreference.com/w/cpp/thread/lock_guard>`_
38and `std::unique_lock <https://en.cppreference.com/w/cpp/thread/unique_lock>`_ can be directly used.
39
40Mutex
41=====
42The Mutex is a synchronization primitive that can be used to protect shared data
43from being simultaneously accessed by multiple threads. It offers exclusive,
44non-recursive ownership semantics where priority inheritance is used to solve
45the classic priority-inversion problem.
46
47The Mutex's API is C++11 STL
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -070048`std::mutex <https://en.cppreference.com/w/cpp/thread/mutex>`_ like,
Ewout van Bekkumf84638b2021-03-12 16:09:08 -080049meaning it is a
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -070050`BasicLockable <https://en.cppreference.com/w/cpp/named_req/BasicLockable>`_
51and `Lockable <https://en.cppreference.com/w/cpp/named_req/Lockable>`_.
Ewout van Bekkum3b9eca42021-04-02 14:54:02 -070052
53.. list-table::
54
55 * - *Supported on*
56 - *Backend module*
57 * - FreeRTOS
58 - :ref:`module-pw_sync_freertos`
59 * - ThreadX
60 - :ref:`module-pw_sync_threadx`
61 * - embOS
62 - :ref:`module-pw_sync_embos`
63 * - STL
64 - :ref:`module-pw_sync_stl`
65 * - Baremetal
66 - Planned
67 * - Zephyr
68 - Planned
69 * - CMSIS-RTOS API v2 & RTX5
70 - Planned
Ewout van Bekkumf84638b2021-03-12 16:09:08 -080071
72C++
73---
74.. cpp:class:: pw::sync::Mutex
75
76 .. cpp:function:: void lock()
77
78 Locks the mutex, blocking indefinitely. Failures are fatal.
79
80 **Precondition:** The lock isn't already held by this thread. Recursive
81 locking is undefined behavior.
82
83 .. cpp:function:: bool try_lock()
84
85 Attempts to lock the mutex in a non-blocking manner.
86 Returns true if the mutex was successfully acquired.
87
88 **Precondition:** The lock isn't already held by this thread. Recursive
89 locking is undefined behavior.
90
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -070091 .. cpp:function:: void unlock()
92
93 Unlocks the mutex. Failures are fatal.
94
95 **Precondition:** The mutex is held by this thread.
96
97
98 .. list-table::
99
100 * - *Safe to use in context*
101 - *Thread*
102 - *Interrupt*
103 - *NMI*
104 * - ``Mutex::Mutex``
105 - ✔
106 -
107 -
108 * - ``Mutex::~Mutex``
109 - ✔
110 -
111 -
112 * - ``void Mutex::lock``
113 - ✔
114 -
115 -
116 * - ``bool Mutex::try_lock``
117 - ✔
118 -
119 -
120 * - ``void Mutex::unlock``
121 - ✔
122 -
123 -
124
125Examples in C++
126^^^^^^^^^^^^^^^
127.. code-block:: cpp
128
129 #include "pw_sync/mutex.h"
130
131 pw::sync::Mutex mutex;
132
133 void ThreadSafeCriticalSection() {
134 mutex.lock();
135 NotThreadSafeCriticalSection();
136 mutex.unlock();
137 }
138
139
140Alternatively you can use C++'s RAII helpers to ensure you always unlock.
141
142.. code-block:: cpp
143
144 #include <mutex>
145
146 #include "pw_sync/mutex.h"
147
148 pw::sync::Mutex mutex;
149
150 void ThreadSafeCriticalSection() {
151 std::lock_guard lock(mutex);
152 NotThreadSafeCriticalSection();
153 }
154
155
156C
157-
158The Mutex must be created in C++, however it can be passed into C using the
159``pw_sync_Mutex`` opaque struct alias.
160
161.. cpp:function:: void pw_sync_Mutex_Lock(pw_sync_Mutex* mutex)
162
163 Invokes the ``Mutex::lock`` member function on the given ``mutex``.
164
165.. cpp:function:: bool pw_sync_Mutex_TryLock(pw_sync_Mutex* mutex)
166
167 Invokes the ``Mutex::try_lock`` member function on the given ``mutex``.
168
169.. cpp:function:: void pw_sync_Mutex_Unlock(pw_sync_Mutex* mutex)
170
171 Invokes the ``Mutex::unlock`` member function on the given ``mutex``.
172
173.. list-table::
174
175 * - *Safe to use in context*
176 - *Thread*
177 - *Interrupt*
178 - *NMI*
179 * - ``void pw_sync_Mutex_Lock``
180 - ✔
181 -
182 -
183 * - ``bool pw_sync_Mutex_TryLock``
184 - ✔
185 -
186 -
187 * - ``void pw_sync_Mutex_Unlock``
188 - ✔
189 -
190 -
191
192Example in C
193^^^^^^^^^^^^
194.. code-block:: cpp
195
196 #include "pw_sync/mutex.h"
197
198 pw::sync::Mutex mutex;
199
200 extern pw_sync_Mutex mutex; // This can only be created in C++.
201
202 void ThreadSafeCriticalSection(void) {
203 pw_sync_Mutex_Lock(&mutex);
204 NotThreadSafeCriticalSection();
205 pw_sync_Mutex_Unlock(&mutex);
206 }
207
208TimedMutex
209==========
210The TimedMutex is an extension of the Mutex which offers timeout and deadline
211based semantics.
212
213The TimedMutex's API is C++11 STL
214`std::timed_mutex <https://en.cppreference.com/w/cpp/thread/timed_mutex>`_ like,
215meaning it is a
216`BasicLockable <https://en.cppreference.com/w/cpp/named_req/BasicLockable>`_,
217`Lockable <https://en.cppreference.com/w/cpp/named_req/Lockable>`_, and
218`TimedLockable <https://en.cppreference.com/w/cpp/named_req/TimedLockable>`_.
219
220Note that the ``TimedMutex`` is a derived ``Mutex`` class, meaning that
221a ``TimedMutex`` can be used by someone who needs the basic ``Mutex``. This is
222in stark contrast to the C++ STL's
223`std::timed_mutex <https://en.cppreference.com/w/cpp/thread/timed_mutex>`_.
224
225
226.. list-table::
227
228 * - *Supported on*
229 - *Backend module*
230 * - FreeRTOS
231 - :ref:`module-pw_sync_freertos`
232 * - ThreadX
233 - :ref:`module-pw_sync_threadx`
234 * - embOS
235 - :ref:`module-pw_sync_embos`
236 * - STL
237 - :ref:`module-pw_sync_stl`
238 * - Zephyr
239 - Planned
240 * - CMSIS-RTOS API v2 & RTX5
241 - Planned
242
243C++
244---
245.. cpp:class:: pw::sync::TimedMutex
246
247 .. cpp:function:: void lock()
248
249 Locks the mutex, blocking indefinitely. Failures are fatal.
250
251 **Precondition:** The lock isn't already held by this thread. Recursive
252 locking is undefined behavior.
253
254 .. cpp:function:: bool try_lock()
255
256 Attempts to lock the mutex in a non-blocking manner.
257 Returns true if the mutex was successfully acquired.
258
259 **Precondition:** The lock isn't already held by this thread. Recursive
260 locking is undefined behavior.
261
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800262 .. cpp:function:: bool try_lock_for(chrono::SystemClock::duration for_at_least)
263
264 Attempts to lock the mutex where, if needed, blocking for at least the
265 specified duration.
266 Returns true if the mutex was successfully acquired.
267
268 **Precondition:** The lock isn't already held by this thread. Recursive
269 locking is undefined behavior.
270
271 .. cpp:function:: bool try_lock_until(chrono::SystemClock::time_point until_at_least)
272
273 Attempts to lock the mutex where, if needed, blocking until at least the
274 specified time_point.
275 Returns true if the mutex was successfully acquired.
276
277 **Precondition:** The lock isn't already held by this thread. Recursive
278 locking is undefined behavior.
279
280 .. cpp:function:: void unlock()
281
282 Unlocks the mutex. Failures are fatal.
283
284 **Precondition:** The mutex is held by this thread.
285
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800286
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700287 .. list-table::
288
289 * - *Safe to use in context*
290 - *Thread*
291 - *Interrupt*
292 - *NMI*
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700293 * - ``TimedMutex::TimedMutex``
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700294 - ✔
295 -
296 -
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700297 * - ``TimedMutex::~TimedMutex``
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700298 - ✔
299 -
300 -
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700301 * - ``void TimedMutex::lock``
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700302 - ✔
303 -
304 -
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700305 * - ``bool TimedMutex::try_lock``
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700306 - ✔
307 -
308 -
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700309 * - ``bool TimedMutex::try_lock_for``
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700310 - ✔
311 -
312 -
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700313 * - ``bool TimedMutex::try_lock_until``
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700314 - ✔
315 -
316 -
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700317 * - ``void TimedMutex::unlock``
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700318 - ✔
319 -
320 -
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800321
322Examples in C++
323^^^^^^^^^^^^^^^
324.. code-block:: cpp
325
326 #include "pw_chrono/system_clock.h"
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700327 #include "pw_sync/timed_mutex.h"
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800328
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700329 pw::sync::TimedMutex mutex;
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800330
331 bool ThreadSafeCriticalSectionWithTimeout(
332 const SystemClock::duration timeout) {
333 if (!mutex.try_lock_for(timeout)) {
334 return false;
335 }
336 NotThreadSafeCriticalSection();
337 mutex.unlock();
338 return true;
339 }
340
341
342Alternatively you can use C++'s RAII helpers to ensure you always unlock.
343
344.. code-block:: cpp
345
346 #include <mutex>
347
348 #include "pw_chrono/system_clock.h"
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700349 #include "pw_sync/timed_mutex.h"
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800350
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700351 pw::sync::TimedMutex mutex;
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800352
353 bool ThreadSafeCriticalSectionWithTimeout(
354 const SystemClock::duration timeout) {
355 std::unique_lock lock(mutex, std::defer_lock);
356 if (!lock.try_lock_for(timeout)) {
357 return false;
358 }
359 NotThreadSafeCriticalSection();
360 return true;
361 }
362
363
364
365C
366-
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700367The TimedMutex must be created in C++, however it can be passed into C using the
368``pw_sync_TimedMutex`` opaque struct alias.
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800369
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700370.. cpp:function:: void pw_sync_TimedMutex_Lock(pw_sync_TimedMutex* mutex)
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800371
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700372 Invokes the ``TimedMutex::lock`` member function on the given ``mutex``.
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800373
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700374.. cpp:function:: bool pw_sync_TimedMutex_TryLock(pw_sync_TimedMutex* mutex)
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800375
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700376 Invokes the ``TimedMutex::try_lock`` member function on the given ``mutex``.
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800377
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700378.. cpp:function:: bool pw_sync_TimedMutex_TryLockFor(pw_sync_TimedMutex* mutex, pw_chrono_SystemClock_Duration for_at_least)
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800379
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700380 Invokes the ``TimedMutex::try_lock_for`` member function on the given ``mutex``.
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800381
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700382.. cpp:function:: bool pw_sync_TimedMutex_TryLockUntil(pw_sync_TimedMutex* mutex, pw_chrono_SystemClock_TimePoint until_at_least)
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800383
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700384 Invokes the ``TimedMutex::try_lock_until`` member function on the given ``mutex``.
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800385
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700386.. cpp:function:: void pw_sync_TimedMutex_Unlock(pw_sync_TimedMutex* mutex)
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800387
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700388 Invokes the ``TimedMutex::unlock`` member function on the given ``mutex``.
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800389
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700390.. list-table::
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800391
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700392 * - *Safe to use in context*
393 - *Thread*
394 - *Interrupt*
395 - *NMI*
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700396 * - ``void pw_sync_TimedMutex_Lock``
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700397 - ✔
398 -
399 -
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700400 * - ``bool pw_sync_TimedMutex_TryLock``
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700401 - ✔
402 -
403 -
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700404 * - ``bool pw_sync_TimedMutex_TryLockFor``
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700405 - ✔
406 -
407 -
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700408 * - ``bool pw_sync_TimedMutex_TryLockUntil``
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700409 - ✔
410 -
411 -
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700412 * - ``void pw_sync_TimedMutex_Unlock``
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700413 - ✔
414 -
415 -
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800416
417Example in C
418^^^^^^^^^^^^
419.. code-block:: cpp
420
421 #include "pw_chrono/system_clock.h"
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700422 #include "pw_sync/timed_mutex.h"
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800423
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700424 pw::sync::TimedMutex mutex;
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800425
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700426 extern pw_sync_TimedMutex mutex; // This can only be created in C++.
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800427
428 bool ThreadSafeCriticalSectionWithTimeout(
429 const pw_chrono_SystemClock_Duration timeout) {
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700430 if (!pw_sync_TimedMutex_TryLockFor(&mutex, timeout)) {
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800431 return false;
432 }
433 NotThreadSafeCriticalSection();
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700434 pw_sync_TimedMutex_Unlock(&mutex);
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800435 return true;
436 }
437
438
439InterruptSpinLock
440=================
441The InterruptSpinLock is a synchronization primitive that can be used to protect
442shared data from being simultaneously accessed by multiple threads and/or
443interrupts as a targeted global lock, with the exception of Non-Maskable
444Interrupts (NMIs). It offers exclusive, non-recursive ownership semantics where
445IRQs up to a backend defined level of "NMIs" will be masked to solve
446priority-inversion.
447
448This InterruptSpinLock relies on built-in local interrupt masking to make it
449interrupt safe without requiring the caller to separately mask and unmask
450interrupts when using this primitive.
451
452Unlike global interrupt locks, this also works safely and efficiently on SMP
453systems. On systems which are not SMP, spinning is not required but some state
454may still be used to detect recursion.
455
456The InterruptSpinLock is a
457`BasicLockable <https://en.cppreference.com/w/cpp/named_req/BasicLockable>`_
458and
459`Lockable <https://en.cppreference.com/w/cpp/named_req/Lockable>`_.
460
Ewout van Bekkum3b9eca42021-04-02 14:54:02 -0700461.. list-table::
462
463 * - *Supported on*
464 - *Backend module*
465 * - FreeRTOS
466 - :ref:`module-pw_sync_freertos`
467 * - ThreadX
468 - :ref:`module-pw_sync_threadx`
469 * - embOS
470 - :ref:`module-pw_sync_embos`
471 * - STL
472 - :ref:`module-pw_sync_stl`
473 * - Baremetal
474 - Planned, not ready for use
475 * - Zephyr
476 - Planned
477 * - CMSIS-RTOS API v2 & RTX5
478 - Planned
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800479
480C++
481---
482.. cpp:class:: pw::sync::InterruptSpinLock
483
484 .. cpp:function:: void lock()
485
486 Locks the spinlock, blocking indefinitely. Failures are fatal.
487
488 **Precondition:** Recursive locking is undefined behavior.
489
490 .. cpp:function:: bool try_lock()
491
492 Attempts to lock the spinlock in a non-blocking manner.
493 Returns true if the spinlock was successfully acquired.
494
495 **Precondition:** Recursive locking is undefined behavior.
496
497 .. cpp:function:: void unlock()
498
499 Unlocks the mutex. Failures are fatal.
500
501 **Precondition:** The spinlock is held by the caller.
502
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700503 .. list-table::
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800504
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700505 * - *Safe to use in context*
506 - *Thread*
507 - *Interrupt*
508 - *NMI*
509 * - ``InterruptSpinLock::InterruptSpinLock``
510 - ✔
511 - ✔
512 -
513 * - ``InterruptSpinLock::~InterruptSpinLock``
514 - ✔
515 - ✔
516 -
517 * - ``void InterruptSpinLock::lock``
518 - ✔
519 - ✔
520 -
521 * - ``bool InterruptSpinLock::try_lock``
522 - ✔
523 - ✔
524 -
525 * - ``void InterruptSpinLock::unlock``
526 - ✔
527 - ✔
528 -
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800529
530Examples in C++
531^^^^^^^^^^^^^^^
532.. code-block:: cpp
533
534 #include "pw_sync/interrupt_spin_lock.h"
535
536 pw::sync::InterruptSpinLock interrupt_spin_lock;
537
538 void InterruptSafeCriticalSection() {
539 interrupt_spin_lock.lock();
540 NotThreadSafeCriticalSection();
541 interrupt_spin_lock.unlock();
542 }
543
544
545Alternatively you can use C++'s RAII helpers to ensure you always unlock.
546
547.. code-block:: cpp
548
549 #include <mutex>
550
551 #include "pw_sync/interrupt_spin_lock.h"
552
553 pw::sync::InterruptSpinLock interrupt_spin_lock;
554
555 void InterruptSafeCriticalSection() {
556 std::lock_guard lock(interrupt_spin_lock);
557 NotThreadSafeCriticalSection();
558 }
559
560
561C
562-
563The InterruptSpinLock must be created in C++, however it can be passed into C using the
564``pw_sync_InterruptSpinLock`` opaque struct alias.
565
566.. cpp:function:: void pw_sync_InterruptSpinLock_Lock(pw_sync_InterruptSpinLock* interrupt_spin_lock)
567
568 Invokes the ``InterruptSpinLock::lock`` member function on the given ``interrupt_spin_lock``.
569
570.. cpp:function:: bool pw_sync_InterruptSpinLock_TryLock(pw_sync_InterruptSpinLock* interrupt_spin_lock)
571
572 Invokes the ``InterruptSpinLock::try_lock`` member function on the given ``interrupt_spin_lock``.
573
574.. cpp:function:: void pw_sync_InterruptSpinLock_Unlock(pw_sync_InterruptSpinLock* interrupt_spin_lock)
575
576 Invokes the ``InterruptSpinLock::unlock`` member function on the given ``interrupt_spin_lock``.
577
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700578.. list-table::
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800579
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700580 * - *Safe to use in context*
581 - *Thread*
582 - *Interrupt*
583 - *NMI*
584 * - ``void pw_sync_InterruptSpinLock_Lock``
585 - ✔
586 - ✔
587 -
588 * - ``bool pw_sync_InterruptSpinLock_TryLock``
589 - ✔
590 - ✔
591 -
592 * - ``void pw_sync_InterruptSpinLock_Unlock``
593 - ✔
594 - ✔
595 -
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800596
597Example in C
598^^^^^^^^^^^^
599.. code-block:: cpp
600
601 #include "pw_chrono/system_clock.h"
602 #include "pw_sync/interrupt_spin_lock.h"
603
604 pw::sync::InterruptSpinLock interrupt_spin_lock;
605
606 extern pw_sync_InterruptSpinLock interrupt_spin_lock; // This can only be created in C++.
607
608 void InterruptSafeCriticalSection(void) {
609 pw_sync_InterruptSpinLock_Lock(&interrupt_spin_lock);
610 NotThreadSafeCriticalSection();
611 pw_sync_InterruptSpinLock_Unlock(&interrupt_spin_lock);
612 }
613
Ewout van Bekkumcc9ef832021-04-08 08:51:16 -0700614Thread Safety Lock Annotations
615==============================
616Pigweed's critical section lock primitives support Clang's thread safety
617analysis extension for C++. The analysis is completely static at compile-time.
618This is only supported when building with Clang. The annotations are no-ops when
619using different compilers.
620
621Pigweed provides the ``pw_sync/lock_annotations.h`` header file with macro
622definitions to allow developers to document the locking policies of
623multi-threaded code. The annotations can also help program analysis tools to
624identify potential thread safety issues.
625
626More information on Clang's thread safety analysis system can be found
627`here <https://clang.llvm.org/docs/ThreadSafetyAnalysis.html>`_.
628
629Enabling Clang's Analysis
630-------------------------
631In order to enable the analysis, Clang requires that the ``-Wthread-safety``
632compilation flag be used. In addition, if any STL components like
633``std::lock_guard`` are used, the STL's built in annotations have to be manually
634enabled, typically by setting the ``_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS``
635macro.
636
637If using GN, the ``pw_build:clang_thread_safety_warnings`` config is provided
638to do this for you, when added to your clang toolchain definition's default
639configs.
640
641Why use lock annotations?
642-------------------------
643Lock annotations can help warn you about potential race conditions in your code
644when using locks: you have to remember to grab lock(s) before entering a
645critical section, yuou have to remember to unlock it when you leave, and you
646have to avoid deadlocks.
647
648Clang's lock annotations let you inform the compiler and anyone reading your
649code which variables are guarded by which locks, which locks should or cannot be
650held when calling which function, which order locks should be acquired in, etc.
651
652Using Lock Annotations
653----------------------
654When referring to locks in the arguments of the attributes, you should
655use variable names or more complex expressions (e.g. ``my_object->lock_``)
656that evaluate to a concrete lock object whenever possible. If the lock
657you want to refer to is not in scope, you may use a member pointer
658(e.g. ``&MyClass::lock_``) to refer to a lock in some (unknown) object.
659
660Annotating Lock Usage
661^^^^^^^^^^^^^^^^^^^^^
662.. cpp:function:: PW_GUARDED_BY(x)
663
664 Documents if a shared field or global variable needs to be protected by a
665 lock. ``PW_GUARDED_BY()`` allows the user to specify a particular lock that
666 should be held when accessing the annotated variable.
667
668 Although this annotation (and ``PW_PT_GUARDED_BY``, below) cannot be applied
669 to local variables, a local variable and its associated lock can often be
670 combined into a small class or struct, thereby allowing the annotation.
671
672 Example:
673
674 .. code-block:: cpp
675
676 class Foo {
677 Mutex mu_;
678 int p1_ PW_GUARDED_BY(mu_);
679 ...
680 };
681
682.. cpp:function:: PW_PT_GUARDED_BY(x)
683
684 Documents if the memory location pointed to by a pointer should be guarded
685 by a lock when dereferencing the pointer.
686
687 Example:
688
689 .. code-block:: cpp
690
691 class Foo {
692 Mutex mu_;
693 int *p1_ PW_PT_GUARDED_BY(mu_);
694 ...
695 };
696
697 Note that a pointer variable to a shared memory location could itself be a
698 shared variable.
699
700 Example:
701
702 .. code-block:: cpp
703
704 // `q_`, guarded by `mu1_`, points to a shared memory location that is
705 // guarded by `mu2_`:
706 int *q_ PW_GUARDED_BY(mu1_) PW_PT_GUARDED_BY(mu2_);
707
708.. cpp:function:: PW_ACQUIRED_AFTER(...)
709.. cpp:function:: PW_ACQUIRED_BEFORE(...)
710
711 Documents the acquisition order between locks that can be held
712 simultaneously by a thread. For any two locks that need to be annotated
713 to establish an acquisition order, only one of them needs the annotation.
714 (i.e. You don't have to annotate both locks with both ``PW_ACQUIRED_AFTER``
715 and ``PW_ACQUIRED_BEFORE``.)
716
717 As with ``PW_GUARDED_BY``, this is only applicable to locks that are shared
718 fields or global variables.
719
720 Example:
721
722 .. code-block:: cpp
723
724 Mutex m1_;
725 Mutex m2_ PW_ACQUIRED_AFTER(m1_);
726
727.. cpp:function:: PW_EXCLUSIVE_LOCKS_REQUIRED(...)
728.. cpp:function:: PW_SHARED_LOCKS_REQUIRED(...)
729
730 Documents a function that expects a lock to be held prior to entry.
731 The lock is expected to be held both on entry to, and exit from, the
732 function.
733
734 An exclusive lock allows read-write access to the guarded data member(s), and
735 only one thread can acquire a lock exclusively at any one time. A shared lock
736 allows read-only access, and any number of threads can acquire a shared lock
737 concurrently.
738
739 Generally, non-const methods should be annotated with
740 ``PW_EXCLUSIVE_LOCKS_REQUIRED``, while const methods should be annotated with
741 ``PW_SHARED_LOCKS_REQUIRED``.
742
743 Example:
744
745 .. code-block:: cpp
746
747 Mutex mu1, mu2;
748 int a PW_GUARDED_BY(mu1);
749 int b PW_GUARDED_BY(mu2);
750
751 void foo() PW_EXCLUSIVE_LOCKS_REQUIRED(mu1, mu2) { ... }
752 void bar() const PW_SHARED_LOCKS_REQUIRED(mu1, mu2) { ... }
753
754.. cpp:function:: PW_LOCKS_EXCLUDED(...)
755
756 Documents the locks acquired in the body of the function. These locks
757 cannot be held when calling this function (as Pigweed's default locks are
758 non-reentrant).
759
760 Example:
761
762 .. code-block:: cpp
763
764 Mutex mu;
765 int a PW_GUARDED_BY(mu);
766
767 void foo() PW_LOCKS_EXCLUDED(mu) {
768 mu.lock();
769 ...
770 mu.unlock();
771 }
772
773.. cpp:function:: PW_LOCK_RETURNED(...)
774
775 Documents a function that returns a lock without acquiring it. For example,
776 a public getter method that returns a pointer to a private lock should
777 be annotated with ``PW_LOCK_RETURNED``.
778
779 Example:
780
781 .. code-block:: cpp
782
783 class Foo {
784 public:
785 Mutex* mu() PW_LOCK_RETURNED(mu) { return &mu; }
786
787 private:
788 Mutex mu;
789 };
790
791.. cpp:function:: PW_NO_LOCK_SAFETY_ANALYSIS()
792
793 Turns off thread safety checking within the body of a particular function.
794 This annotation is used to mark functions that are known to be correct, but
795 the locking behavior is more complicated than the analyzer can handle.
796
797Annotating Lock Objects
798^^^^^^^^^^^^^^^^^^^^^^^
799In order of lock usage annotation to work, the lock objects themselves need to
800be annotated as well. In case you are providing your own lock or psuedo-lock
801object, you can use the macros in this section to annotate it.
802
803As an example we've annotated a Lock and a RAII ScopedLocker object for you, see
804the macro documentation after for more details:
805
806.. code-block:: cpp
807
808 class PW_LOCKABLE("Lock") Lock {
809 public:
810 void Lock() PW_EXCLUSIVE_LOCK_FUNCTION();
811
812 void ReaderLock() PW_SHARED_LOCK_FUNCTION();
813
814 void Unlock() PW_UNLOCK_FUNCTION();
815
816 void ReaderUnlock() PW_SHARED_TRYLOCK_FUNCTION();
817
818 bool TryLock() PW_EXCLUSIVE_TRYLOCK_FUNCTION(true);
819
820 bool ReaderTryLock() PW_SHARED_TRYLOCK_FUNCTION(true);
821
822 void AssertHeld() PW_ASSERT_EXCLUSIVE_LOCK();
823
824 void AssertReaderHeld() PW_ASSERT_SHARED_LOCK();
825 };
826
827
828 // Tag types for selecting a constructor.
829 struct adopt_lock_t {} inline constexpr adopt_lock = {};
830 struct defer_lock_t {} inline constexpr defer_lock = {};
831 struct shared_lock_t {} inline constexpr shared_lock = {};
832
833 class PW_SCOPED_LOCKABLE ScopedLocker {
834 // Acquire lock, implicitly acquire *this and associate it with lock.
835 ScopedLocker(Lock *lock) PW_EXCLUSIVE_LOCK_FUNCTION(lock)
836 : lock_(lock), locked(true) {
837 lock->Lock();
838 }
839
840 // Assume lock is held, implicitly acquire *this and associate it with lock.
841 ScopedLocker(Lock *lock, adopt_lock_t) PW_EXCLUSIVE_LOCKS_REQUIRED(lock)
842 : lock_(lock), locked(true) {}
843
844 // Acquire lock in shared mode, implicitly acquire *this and associate it
845 // with lock.
846 ScopedLocker(Lock *lock, shared_lock_t) PW_SHARED_LOCK_FUNCTION(lock)
847 : lock_(lock), locked(true) {
848 lock->ReaderLock();
849 }
850
851 // Assume lock is held in shared mode, implicitly acquire *this and associate
852 // it with lock.
853 ScopedLocker(Lock *lock, adopt_lock_t, shared_lock_t)
854 PW_SHARED_LOCKS_REQUIRED(lock) : lock_(lock), locked(true) {}
855
856 // Assume lock is not held, implicitly acquire *this and associate it with
857 // lock.
858 ScopedLocker(Lock *lock, defer_lock_t) PW_LOCKS_EXCLUDED(lock)
859 : lock_(lock), locked(false) {}
860
861 // Release *this and all associated locks, if they are still held.
862 // There is no warning if the scope was already unlocked before.
863 ~ScopedLocker() PW_UNLOCK_FUNCTION() {
864 if (locked)
865 lock_->GenericUnlock();
866 }
867
868 // Acquire all associated locks exclusively.
869 void Lock() PW_EXCLUSIVE_LOCK_FUNCTION() {
870 lock_->Lock();
871 locked = true;
872 }
873
874 // Try to acquire all associated locks exclusively.
875 bool TryLock() PW_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
876 return locked = lock_->TryLock();
877 }
878
879 // Acquire all associated locks in shared mode.
880 void ReaderLock() PW_SHARED_LOCK_FUNCTION() {
881 lock_->ReaderLock();
882 locked = true;
883 }
884
885 // Try to acquire all associated locks in shared mode.
886 bool ReaderTryLock() PW_SHARED_TRYLOCK_FUNCTION(true) {
887 return locked = lock_->ReaderTryLock();
888 }
889
890 // Release all associated locks. Warn on double unlock.
891 void Unlock() PW_UNLOCK_FUNCTION() {
892 lock_->Unlock();
893 locked = false;
894 }
895
896 // Release all associated locks. Warn on double unlock.
897 void ReaderUnlock() PW_UNLOCK_FUNCTION() {
898 lock_->ReaderUnlock();
899 locked = false;
900 }
901
902 private:
903 Lock* lock_;
904 bool locked_;
905 };
906
907.. cpp:function:: PW_LOCKABLE(name)
908
909 Documents if a class/type is a lockable type (such as the ``pw::sync::Mutex``
910 class). The name is used in the warning messages. This can also be useful on
911 classes which have locking like semantics but aren't actually locks.
912
913.. cpp:function:: PW_SCOPED_LOCKABLE()
914
915 Documents if a class does RAII locking. The name is used in the warning
916 messages.
917
918 The constructor should use ``LOCK_FUNCTION()`` to specify the lock that is
919 acquired, and the destructor should use ``UNLOCK_FUNCTION()`` with no
920 arguments; the analysis will assume that the destructor unlocks whatever the
921 constructor locked.
922
923.. cpp:function:: PW_EXCLUSIVE_LOCK_FUNCTION()
924
925 Documents functions that acquire a lock in the body of a function, and do
926 not release it.
927
928.. cpp:function:: PW_SHARED_LOCK_FUNCTION()
929
930 Documents functions that acquire a shared (reader) lock in the body of a
931 function, and do not release it.
932
933.. cpp:function:: PW_UNLOCK_FUNCTION()
934
935 Documents functions that expect a lock to be held on entry to the function,
936 and release it in the body of the function.
937
938.. cpp:function:: PW_EXCLUSIVE_TRYLOCK_FUNCTION(try_success)
939.. cpp:function:: PW_SHARED_TRYLOCK_FUNCTION(try_success)
940
941 Documents functions that try to acquire a lock, and return success or failure
942 (or a non-boolean value that can be interpreted as a boolean).
943 The first argument should be ``true`` for functions that return ``true`` on
944 success, or ``false`` for functions that return `false` on success. The second
945 argument specifies the lock that is locked on success. If unspecified, this
946 lock is assumed to be ``this``.
947
948.. cpp:function:: PW_ASSERT_EXCLUSIVE_LOCK()
949.. cpp:function:: PW_ASSERT_SHARED_LOCK()
950
951 Documents functions that dynamically check to see if a lock is held, and fail
952 if it is not held.
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800953
954--------------------
955Signaling Primitives
956--------------------
957
Ewout van Bekkum3b9eca42021-04-02 14:54:02 -0700958Native signaling primitives tend to vary more compared to critial section locks
959across different platforms. For example, although common signaling primtives
960like semaphores are in most if not all RTOSes and even POSIX, it was not in the
961STL before C++20. Likewise many C++ developers are surprised that conditional
962variables tend to not be natively supported on RTOSes. Although you can usually
963build any signaling primitive based on other native signaling primitives, this
964may come with non-trivial added overhead in ROM, RAM, and execution efficiency.
965
Ewout van Bekkumf0106062021-05-06 14:08:33 -0700966For this reason, Pigweed intends to provide some simpler signaling primitives
Ewout van Bekkum3b9eca42021-04-02 14:54:02 -0700967which exist to solve a narrow programming need but can be implemented as
968efficiently as possible for the platform that it is used on.
969
970This simpler but highly portable class of signaling primitives is intended to
971ensure that a portability efficiency tradeoff does not have to be made up front.
Ewout van Bekkumf0106062021-05-06 14:08:33 -0700972Today this is class of simpler signaling primitives is limited to the
973``pw::sync::ThreadNotification`` and ``pw::sync::TimedThreadNotification``.
974
975ThreadNotification
976==================
977The ThreadNotification is a synchronization primitive that can be used to
978permit a SINGLE thread to block and consume a latching, saturating
979notification from multiple notifiers.
980
981.. Warning::
982 This is a single consumer/waiter, multiple producer/notifier API!
983 The acquire APIs must only be invoked by a single consuming thread. As a
984 result, having multiple threads receiving notifications via the acquire API
985 is unsupported.
986
987This is effectively a subset of the ``pw::sync::BinarySemaphore`` API, except
988that only a single thread can be notified and block at a time.
989
990The single consumer aspect of the API permits the use of a smaller and/or
991faster native APIs such as direct thread signaling. This should be
Ewout van Bekkum3b9eca42021-04-02 14:54:02 -0700992backed by the most efficient native primitive for a target, regardless of
993whether that is a semaphore, event flag group, condition variable, or something
994else.
995
Ewout van Bekkumf0106062021-05-06 14:08:33 -0700996Generic BinarySemaphore-based Backend
997-------------------------------------
998This module provides a generic backend for ``pw::sync::ThreadNotification`` via
999``pw_sync:binary_semaphore_thread_notification`` which uses a
1000``pw::sync::BinarySemaphore`` as the backing primitive. See
1001:ref:`BinarySemaphore <module-pw_sync-binary-semaphore>` for backend
1002availability.
1003
1004Optimized Backend
1005-----------------
1006.. list-table::
1007
1008 * - *Supported on*
1009 - *Optimized backend module*
1010 * - FreeRTOS
1011 - Planned
1012 * - ThreadX
1013 - Planned
1014 * - embOS
1015 - Planned
1016 * - STL
1017 - Not planned, use ``pw_sync:binary_semaphore_thread_notification``
1018 * - Baremetal
1019 - Planned
1020 * - Zephyr
1021 - Planned
1022 * - CMSIS-RTOS API v2 & RTX5
1023 - Planned
1024
1025C++
1026---
1027.. cpp:class:: pw::sync::ThreadNotification
1028
1029 .. cpp:function:: void acquire()
1030
1031 Blocks indefinitely until the thread is notified, i.e. until the
1032 notification latch can be cleared because it was set.
1033
1034 Clears the notification latch.
1035
1036 **IMPORTANT:** This should only be used by a single consumer thread.
1037
1038 .. cpp:function:: bool try_acquire()
1039
1040 Returns whether the thread has been notified, i.e. whether the notificion
1041 latch was set and resets the latch regardless.
1042
1043 Clears the notification latch.
1044
1045 Returns true if the thread was notified, meaning the the internal latch was
1046 reset successfully.
1047
1048 **IMPORTANT:** This should only be used by a single consumer thread.
1049
1050 .. cpp:function:: void release()
1051
1052 Notifies the thread in a saturating manner, setting the notification latch.
1053
1054 Raising the notification multiple time without it being acquired by the
1055 consuming thread is equivalent to raising the notification once to the
1056 thread. The notification is latched in case the thread was not waiting at
1057 the time.
1058
1059 This is IRQ and thread safe.
1060
1061 .. list-table::
1062
1063 * - *Safe to use in context*
1064 - *Thread*
1065 - *Interrupt*
1066 - *NMI*
1067 * - ``ThreadNotification::ThreadNotification``
1068 - ✔
1069 -
1070 -
1071 * - ``ThreadNotification::~ThreadNotification``
1072 - ✔
1073 -
1074 -
1075 * - ``void ThreadNotification::acquire``
1076 - ✔
1077 -
1078 -
1079 * - ``bool ThreadNotification::try_acquire``
1080 - ✔
1081 -
1082 -
1083 * - ``void ThreadNotification::release``
1084 - ✔
1085 - ✔
1086 -
1087
1088Examples in C++
1089^^^^^^^^^^^^^^^
1090.. code-block:: cpp
1091
1092 #include "pw_sync/thread_notification.h"
1093 #include "pw_thread/thread_core.h"
1094
1095 class FooHandler() : public pw::thread::ThreadCore {
1096 // Public API invoked by other threads and/or interrupts.
1097 void NewFooAvailable() {
1098 new_foo_notification_.release();
1099 }
1100
1101 private:
1102 pw::sync::ThreadNotification new_foo_notification_;
1103
1104 // Thread function.
1105 void Run() override {
1106 while (true) {
1107 new_foo_notification_.acquire();
1108 HandleFoo();
1109 }
1110 }
1111
1112 void HandleFoo();
1113 }
1114
1115TimedThreadNotification
1116=======================
1117The TimedThreadNotification is an extension of the ThreadNotification which
1118offers timeout and deadline based semantics.
1119
1120.. Warning::
1121 This is a single consumer/waiter, multiple producer/notifier API!
1122 The acquire APIs must only be invoked by a single consuming thread. As a
1123 result, having multiple threads receiving notifications via the acquire API
1124 is unsupported.
1125
1126Generic BinarySemaphore-based Backend
1127-------------------------------------
1128This module provides a generic backend for ``pw::sync::TimedThreadNotification``
1129via ``pw_sync:binary_semaphore_timed_thread_notification`` which uses a
1130``pw::sync::BinarySemaphore`` as the backing primitive. See
1131:ref:`BinarySemaphore <module-pw_sync-binary-semaphore>` for backend
1132availability.
1133
1134Optimized Backend
1135-----------------
1136.. list-table::
1137
1138 * - *Supported on*
1139 - *Backend module*
1140 * - FreeRTOS
1141 - Planned
1142 * - ThreadX
1143 - Planned
1144 * - embOS
1145 - Planned
1146 * - STL
1147 - Not planned, use ``pw_sync:binary_semaphore_thread_notification``
1148 * - Zephyr
1149 - Planned
1150 * - CMSIS-RTOS API v2 & RTX5
1151 - Planned
1152
1153C++
1154---
1155.. cpp:class:: pw::sync::TimedThreadNotification
1156
1157 .. cpp:function:: void acquire()
1158
1159 Blocks indefinitely until the thread is notified, i.e. until the
1160 notification latch can be cleared because it was set.
1161
1162 Clears the notification latch.
1163
1164 **IMPORTANT:** This should only be used by a single consumer thread.
1165
1166 .. cpp:function:: bool try_acquire()
1167
1168 Returns whether the thread has been notified, i.e. whether the notificion
1169 latch was set and resets the latch regardless.
1170
1171 Clears the notification latch.
1172
1173 Returns true if the thread was notified, meaning the the internal latch was
1174 reset successfully.
1175
1176 **IMPORTANT:** This should only be used by a single consumer thread.
1177
1178 .. cpp:function:: void release()
1179
1180 Notifies the thread in a saturating manner, setting the notification latch.
1181
1182 Raising the notification multiple time without it being acquired by the
1183 consuming thread is equivalent to raising the notification once to the
1184 thread. The notification is latched in case the thread was not waiting at
1185 the time.
1186
1187 This is IRQ and thread safe.
1188
1189 .. cpp:function:: bool try_acquire_for(chrono::SystemClock::duration timeout)
1190
1191 Blocks until the specified timeout duration has elapsed or the thread
1192 has been notified (i.e. notification latch can be cleared because it was
1193 set), whichever comes first.
1194
1195 Clears the notification latch.
1196
1197 Returns true if the thread was notified, meaning the the internal latch was
1198 reset successfully.
1199
1200 **IMPORTANT:** This should only be used by a single consumer thread.
1201
1202 .. cpp:function:: bool try_acquire_until(chrono::SystemClock::time_point deadline)
1203
1204 Blocks until the specified deadline time has been reached the thread has
1205 been notified (i.e. notification latch can be cleared because it was set),
1206 whichever comes first.
1207
1208 Clears the notification latch.
1209
1210 Returns true if the thread was notified, meaning the the internal latch was
1211 reset successfully.
1212
1213 **IMPORTANT:** This should only be used by a single consumer thread.
1214
1215 .. list-table::
1216
1217 * - *Safe to use in context*
1218 - *Thread*
1219 - *Interrupt*
1220 - *NMI*
1221 * - ``ThreadNotification::ThreadNotification``
1222 - ✔
1223 -
1224 -
1225 * - ``ThreadNotification::~ThreadNotification``
1226 - ✔
1227 -
1228 -
1229 * - ``void ThreadNotification::acquire``
1230 - ✔
1231 -
1232 -
1233 * - ``bool ThreadNotification::try_acquire``
1234 - ✔
1235 -
1236 -
1237 * - ``bool ThreadNotification::try_acquire_for``
1238 - ✔
1239 -
1240 -
1241 * - ``bool ThreadNotification::try_acquire_until``
1242 - ✔
1243 -
1244 -
1245 * - ``void ThreadNotification::release``
1246 - ✔
1247 - ✔
1248 -
1249
1250Examples in C++
1251^^^^^^^^^^^^^^^
1252.. code-block:: cpp
1253
1254 #include "pw_sync/timed_thread_notification.h"
1255 #include "pw_thread/thread_core.h"
1256
1257 class FooHandler() : public pw::thread::ThreadCore {
1258 // Public API invoked by other threads and/or interrupts.
1259 void NewFooAvailable() {
1260 new_foo_notification_.release();
1261 }
1262
1263 private:
1264 pw::sync::TimedThreadNotification new_foo_notification_;
1265
1266 // Thread function.
1267 void Run() override {
1268 while (true) {
1269 if (new_foo_notification_.try_acquire_for(kNotificationTimeout)) {
1270 HandleFoo();
1271 }
1272 DoOtherStuff();
1273 }
1274 }
1275
1276 void HandleFoo();
1277 void DoOtherStuff();
1278 }
1279
Ewout van Bekkumf84638b2021-03-12 16:09:08 -08001280CountingSemaphore
1281=================
1282The CountingSemaphore is a synchronization primitive that can be used for
1283counting events and/or resource management where receiver(s) can block on
1284acquire until notifier(s) signal by invoking release.
1285
1286Note that unlike Mutexes, priority inheritance is not used by semaphores meaning
1287semaphores are subject to unbounded priority inversions. Due to this, Pigweed
1288does not recommend semaphores for mutual exclusion.
1289
1290The CountingSemaphore is initialized to being empty or having no tokens.
1291
1292The entire API is thread safe, but only a subset is interrupt safe. None of it
1293is NMI safe.
1294
1295.. Warning::
1296 Releasing multiple tokens is often not natively supported, meaning you may
1297 end up invoking the native kernel API many times, i.e. once per token you
1298 are releasing!
1299
Ewout van Bekkum3b9eca42021-04-02 14:54:02 -07001300.. list-table::
1301
1302 * - *Supported on*
1303 - *Backend module*
1304 * - FreeRTOS
1305 - :ref:`module-pw_sync_freertos`
1306 * - ThreadX
1307 - :ref:`module-pw_sync_threadx`
1308 * - embOS
1309 - :ref:`module-pw_sync_embos`
1310 * - STL
1311 - :ref:`module-pw_sync_stl`
1312 * - Zephyr
1313 - Planned
1314 * - CMSIS-RTOS API v2 & RTX5
1315 - Planned
1316
Ewout van Bekkumf0106062021-05-06 14:08:33 -07001317.. _module-pw_sync-binary-semaphore:
1318
Ewout van Bekkumf84638b2021-03-12 16:09:08 -08001319BinarySemaphore
1320===============
1321BinarySemaphore is a specialization of CountingSemaphore with an arbitrary token
1322limit of 1. Note that that ``max()`` is >= 1, meaning it may be released up to
1323``max()`` times but only acquired once for those N releases.
1324
1325Implementations of BinarySemaphore are typically more efficient than the
1326default implementation of CountingSemaphore.
1327
1328The BinarySemaphore is initialized to being empty or having no tokens.
1329
1330The entire API is thread safe, but only a subset is interrupt safe. None of it
1331is NMI safe.
Ewout van Bekkum3b9eca42021-04-02 14:54:02 -07001332
1333.. list-table::
1334
1335 * - *Supported on*
1336 - *Backend module*
1337 * - FreeRTOS
1338 - :ref:`module-pw_sync_freertos`
1339 * - ThreadX
1340 - :ref:`module-pw_sync_threadx`
1341 * - embOS
1342 - :ref:`module-pw_sync_embos`
1343 * - STL
1344 - :ref:`module-pw_sync_stl`
1345 * - Zephyr
1346 - Planned
1347 * - CMSIS-RTOS API v2 & RTX5
1348 - Planned
1349
Ewout van Bekkumcc756c82021-05-12 07:57:43 -07001350Conditional Variables
1351=====================
1352We've decided for now to skip on conditional variables. These are constructs,
1353which are typically not natively available on RTOSes. CVs would have to be
1354backed by a multiple hidden semaphore(s) in addition to the explicit public
1355mutex. In other words a CV typically ends up as a a composition of
1356synchronization primitives on RTOSes. That being said, one could implement them
1357using our semaphore and mutex layers and we may consider providing this in the
1358future. However for most of our resource constrained customers they will mostly
1359likely be using semaphores more often than CVs.