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