blob: 1308f00214ad088b9b3ed49a6a3d6bf51dcabf45 [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
Ewout van Bekkum5ff8cc52021-09-07 15:46:36 -070081 Tries to lock the mutex in a non-blocking manner.
Ewout van Bekkumf84638b2021-03-12 16:09:08 -080082 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
Ewout van Bekkum5ff8cc52021-09-07 15:46:36 -0700252 Tries to lock the mutex in a non-blocking manner.
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700253 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
Ewout van Bekkum5ff8cc52021-09-07 15:46:36 -0700259 .. cpp:function:: bool try_lock_for(const chrono::SystemClock::duration& timeout)
260
261 Tries to lock the mutex. Blocks until specified the timeout has elapsed or
262 the lock is acquired, whichever comes first.
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800263 Returns true if the mutex was successfully acquired.
264
265 **Precondition:** The lock isn't already held by this thread. Recursive
266 locking is undefined behavior.
267
Ewout van Bekkum5ff8cc52021-09-07 15:46:36 -0700268 .. cpp:function:: bool try_lock_until(const chrono::SystemClock::time_point& deadline)
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800269
Ewout van Bekkum5ff8cc52021-09-07 15:46:36 -0700270 Tries to lock the mutex. Blocks until specified deadline has been reached
271 or the lock is acquired, whichever comes first.
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800272 Returns true if the mutex was successfully acquired.
273
274 **Precondition:** The lock isn't already held by this thread. Recursive
275 locking is undefined behavior.
276
277 .. cpp:function:: void unlock()
278
279 Unlocks the mutex. Failures are fatal.
280
281 **Precondition:** The mutex is held by this thread.
282
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800283
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700284 .. list-table::
285
286 * - *Safe to use in context*
287 - *Thread*
288 - *Interrupt*
289 - *NMI*
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700290 * - ``TimedMutex::TimedMutex``
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700291 - ✔
292 -
293 -
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700294 * - ``TimedMutex::~TimedMutex``
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700295 - ✔
296 -
297 -
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700298 * - ``void TimedMutex::lock``
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700299 - ✔
300 -
301 -
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700302 * - ``bool TimedMutex::try_lock``
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700303 - ✔
304 -
305 -
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700306 * - ``bool TimedMutex::try_lock_for``
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700307 - ✔
308 -
309 -
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700310 * - ``bool TimedMutex::try_lock_until``
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700311 - ✔
312 -
313 -
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700314 * - ``void TimedMutex::unlock``
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700315 - ✔
316 -
317 -
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800318
319Examples in C++
320^^^^^^^^^^^^^^^
321.. code-block:: cpp
322
323 #include "pw_chrono/system_clock.h"
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700324 #include "pw_sync/timed_mutex.h"
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800325
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700326 pw::sync::TimedMutex mutex;
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800327
328 bool ThreadSafeCriticalSectionWithTimeout(
329 const SystemClock::duration timeout) {
330 if (!mutex.try_lock_for(timeout)) {
331 return false;
332 }
333 NotThreadSafeCriticalSection();
334 mutex.unlock();
335 return true;
336 }
337
338
339Alternatively you can use C++'s RAII helpers to ensure you always unlock.
340
341.. code-block:: cpp
342
343 #include <mutex>
344
345 #include "pw_chrono/system_clock.h"
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700346 #include "pw_sync/timed_mutex.h"
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800347
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700348 pw::sync::TimedMutex mutex;
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800349
350 bool ThreadSafeCriticalSectionWithTimeout(
351 const SystemClock::duration timeout) {
352 std::unique_lock lock(mutex, std::defer_lock);
353 if (!lock.try_lock_for(timeout)) {
354 return false;
355 }
356 NotThreadSafeCriticalSection();
357 return true;
358 }
359
360
361
362C
363-
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700364The TimedMutex must be created in C++, however it can be passed into C using the
365``pw_sync_TimedMutex`` opaque struct alias.
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800366
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700367.. cpp:function:: void pw_sync_TimedMutex_Lock(pw_sync_TimedMutex* mutex)
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800368
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700369 Invokes the ``TimedMutex::lock`` member function on the given ``mutex``.
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800370
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700371.. cpp:function:: bool pw_sync_TimedMutex_TryLock(pw_sync_TimedMutex* mutex)
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800372
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700373 Invokes the ``TimedMutex::try_lock`` member function on the given ``mutex``.
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800374
Ewout van Bekkum5ff8cc52021-09-07 15:46:36 -0700375.. cpp:function:: bool pw_sync_TimedMutex_TryLockFor(pw_sync_TimedMutex* mutex, pw_chrono_SystemClock_Duration timeout)
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800376
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700377 Invokes the ``TimedMutex::try_lock_for`` member function on the given ``mutex``.
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800378
Ewout van Bekkum5ff8cc52021-09-07 15:46:36 -0700379.. cpp:function:: bool pw_sync_TimedMutex_TryLockUntil(pw_sync_TimedMutex* mutex, pw_chrono_SystemClock_TimePoint deadline)
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800380
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700381 Invokes the ``TimedMutex::try_lock_until`` member function on the given ``mutex``.
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800382
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700383.. cpp:function:: void pw_sync_TimedMutex_Unlock(pw_sync_TimedMutex* mutex)
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800384
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700385 Invokes the ``TimedMutex::unlock`` member function on the given ``mutex``.
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800386
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700387.. list-table::
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800388
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700389 * - *Safe to use in context*
390 - *Thread*
391 - *Interrupt*
392 - *NMI*
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700393 * - ``void pw_sync_TimedMutex_Lock``
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700394 - ✔
395 -
396 -
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700397 * - ``bool pw_sync_TimedMutex_TryLock``
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700398 - ✔
399 -
400 -
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700401 * - ``bool pw_sync_TimedMutex_TryLockFor``
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700402 - ✔
403 -
404 -
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700405 * - ``bool pw_sync_TimedMutex_TryLockUntil``
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700406 - ✔
407 -
408 -
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700409 * - ``void pw_sync_TimedMutex_Unlock``
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700410 - ✔
411 -
412 -
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800413
414Example in C
415^^^^^^^^^^^^
416.. code-block:: cpp
417
418 #include "pw_chrono/system_clock.h"
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700419 #include "pw_sync/timed_mutex.h"
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800420
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700421 pw::sync::TimedMutex mutex;
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800422
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700423 extern pw_sync_TimedMutex mutex; // This can only be created in C++.
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800424
425 bool ThreadSafeCriticalSectionWithTimeout(
426 const pw_chrono_SystemClock_Duration timeout) {
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700427 if (!pw_sync_TimedMutex_TryLockFor(&mutex, timeout)) {
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800428 return false;
429 }
430 NotThreadSafeCriticalSection();
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700431 pw_sync_TimedMutex_Unlock(&mutex);
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800432 return true;
433 }
434
435
436InterruptSpinLock
437=================
438The InterruptSpinLock is a synchronization primitive that can be used to protect
439shared data from being simultaneously accessed by multiple threads and/or
440interrupts as a targeted global lock, with the exception of Non-Maskable
441Interrupts (NMIs). It offers exclusive, non-recursive ownership semantics where
442IRQs up to a backend defined level of "NMIs" will be masked to solve
443priority-inversion.
444
445This InterruptSpinLock relies on built-in local interrupt masking to make it
446interrupt safe without requiring the caller to separately mask and unmask
447interrupts when using this primitive.
448
449Unlike global interrupt locks, this also works safely and efficiently on SMP
450systems. On systems which are not SMP, spinning is not required but some state
451may still be used to detect recursion.
452
453The InterruptSpinLock is a
454`BasicLockable <https://en.cppreference.com/w/cpp/named_req/BasicLockable>`_
455and
456`Lockable <https://en.cppreference.com/w/cpp/named_req/Lockable>`_.
457
Ewout van Bekkum3b9eca42021-04-02 14:54:02 -0700458.. list-table::
459
460 * - *Supported on*
461 - *Backend module*
462 * - FreeRTOS
463 - :ref:`module-pw_sync_freertos`
464 * - ThreadX
465 - :ref:`module-pw_sync_threadx`
466 * - embOS
467 - :ref:`module-pw_sync_embos`
468 * - STL
469 - :ref:`module-pw_sync_stl`
470 * - Baremetal
471 - Planned, not ready for use
472 * - Zephyr
473 - Planned
474 * - CMSIS-RTOS API v2 & RTX5
475 - Planned
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800476
477C++
478---
479.. cpp:class:: pw::sync::InterruptSpinLock
480
481 .. cpp:function:: void lock()
482
483 Locks the spinlock, blocking indefinitely. Failures are fatal.
484
485 **Precondition:** Recursive locking is undefined behavior.
486
487 .. cpp:function:: bool try_lock()
488
Ewout van Bekkum5ff8cc52021-09-07 15:46:36 -0700489 Tries to lock the spinlock in a non-blocking manner.
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800490 Returns true if the spinlock was successfully acquired.
491
492 **Precondition:** Recursive locking is undefined behavior.
493
494 .. cpp:function:: void unlock()
495
496 Unlocks the mutex. Failures are fatal.
497
498 **Precondition:** The spinlock is held by the caller.
499
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700500 .. list-table::
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800501
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700502 * - *Safe to use in context*
503 - *Thread*
504 - *Interrupt*
505 - *NMI*
506 * - ``InterruptSpinLock::InterruptSpinLock``
507 - ✔
508 - ✔
509 -
510 * - ``InterruptSpinLock::~InterruptSpinLock``
511 - ✔
512 - ✔
513 -
514 * - ``void InterruptSpinLock::lock``
515 - ✔
516 - ✔
517 -
518 * - ``bool InterruptSpinLock::try_lock``
519 - ✔
520 - ✔
521 -
522 * - ``void InterruptSpinLock::unlock``
523 - ✔
524 - ✔
525 -
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800526
527Examples in C++
528^^^^^^^^^^^^^^^
529.. code-block:: cpp
530
531 #include "pw_sync/interrupt_spin_lock.h"
532
533 pw::sync::InterruptSpinLock interrupt_spin_lock;
534
535 void InterruptSafeCriticalSection() {
536 interrupt_spin_lock.lock();
537 NotThreadSafeCriticalSection();
538 interrupt_spin_lock.unlock();
539 }
540
541
542Alternatively you can use C++'s RAII helpers to ensure you always unlock.
543
544.. code-block:: cpp
545
546 #include <mutex>
547
548 #include "pw_sync/interrupt_spin_lock.h"
549
550 pw::sync::InterruptSpinLock interrupt_spin_lock;
551
552 void InterruptSafeCriticalSection() {
553 std::lock_guard lock(interrupt_spin_lock);
554 NotThreadSafeCriticalSection();
555 }
556
557
558C
559-
560The InterruptSpinLock must be created in C++, however it can be passed into C using the
561``pw_sync_InterruptSpinLock`` opaque struct alias.
562
563.. cpp:function:: void pw_sync_InterruptSpinLock_Lock(pw_sync_InterruptSpinLock* interrupt_spin_lock)
564
565 Invokes the ``InterruptSpinLock::lock`` member function on the given ``interrupt_spin_lock``.
566
567.. cpp:function:: bool pw_sync_InterruptSpinLock_TryLock(pw_sync_InterruptSpinLock* interrupt_spin_lock)
568
569 Invokes the ``InterruptSpinLock::try_lock`` member function on the given ``interrupt_spin_lock``.
570
571.. cpp:function:: void pw_sync_InterruptSpinLock_Unlock(pw_sync_InterruptSpinLock* interrupt_spin_lock)
572
573 Invokes the ``InterruptSpinLock::unlock`` member function on the given ``interrupt_spin_lock``.
574
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700575.. list-table::
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800576
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700577 * - *Safe to use in context*
578 - *Thread*
579 - *Interrupt*
580 - *NMI*
581 * - ``void pw_sync_InterruptSpinLock_Lock``
582 - ✔
583 - ✔
584 -
585 * - ``bool pw_sync_InterruptSpinLock_TryLock``
586 - ✔
587 - ✔
588 -
589 * - ``void pw_sync_InterruptSpinLock_Unlock``
590 - ✔
591 - ✔
592 -
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800593
594Example in C
595^^^^^^^^^^^^
596.. code-block:: cpp
597
598 #include "pw_chrono/system_clock.h"
599 #include "pw_sync/interrupt_spin_lock.h"
600
601 pw::sync::InterruptSpinLock interrupt_spin_lock;
602
603 extern pw_sync_InterruptSpinLock interrupt_spin_lock; // This can only be created in C++.
604
605 void InterruptSafeCriticalSection(void) {
606 pw_sync_InterruptSpinLock_Lock(&interrupt_spin_lock);
607 NotThreadSafeCriticalSection();
608 pw_sync_InterruptSpinLock_Unlock(&interrupt_spin_lock);
609 }
610
Ewout van Bekkumcc9ef832021-04-08 08:51:16 -0700611Thread Safety Lock Annotations
612==============================
613Pigweed's critical section lock primitives support Clang's thread safety
614analysis extension for C++. The analysis is completely static at compile-time.
615This is only supported when building with Clang. The annotations are no-ops when
616using different compilers.
617
618Pigweed provides the ``pw_sync/lock_annotations.h`` header file with macro
619definitions to allow developers to document the locking policies of
620multi-threaded code. The annotations can also help program analysis tools to
621identify potential thread safety issues.
622
623More information on Clang's thread safety analysis system can be found
624`here <https://clang.llvm.org/docs/ThreadSafetyAnalysis.html>`_.
625
626Enabling Clang's Analysis
627-------------------------
628In order to enable the analysis, Clang requires that the ``-Wthread-safety``
629compilation flag be used. In addition, if any STL components like
630``std::lock_guard`` are used, the STL's built in annotations have to be manually
631enabled, typically by setting the ``_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS``
632macro.
633
634If using GN, the ``pw_build:clang_thread_safety_warnings`` config is provided
635to do this for you, when added to your clang toolchain definition's default
636configs.
637
638Why use lock annotations?
639-------------------------
640Lock annotations can help warn you about potential race conditions in your code
641when using locks: you have to remember to grab lock(s) before entering a
642critical section, yuou have to remember to unlock it when you leave, and you
643have to avoid deadlocks.
644
645Clang's lock annotations let you inform the compiler and anyone reading your
646code which variables are guarded by which locks, which locks should or cannot be
647held when calling which function, which order locks should be acquired in, etc.
648
649Using Lock Annotations
650----------------------
651When referring to locks in the arguments of the attributes, you should
652use variable names or more complex expressions (e.g. ``my_object->lock_``)
653that evaluate to a concrete lock object whenever possible. If the lock
654you want to refer to is not in scope, you may use a member pointer
655(e.g. ``&MyClass::lock_``) to refer to a lock in some (unknown) object.
656
657Annotating Lock Usage
658^^^^^^^^^^^^^^^^^^^^^
659.. cpp:function:: PW_GUARDED_BY(x)
660
661 Documents if a shared field or global variable needs to be protected by a
662 lock. ``PW_GUARDED_BY()`` allows the user to specify a particular lock that
663 should be held when accessing the annotated variable.
664
665 Although this annotation (and ``PW_PT_GUARDED_BY``, below) cannot be applied
666 to local variables, a local variable and its associated lock can often be
667 combined into a small class or struct, thereby allowing the annotation.
668
669 Example:
670
671 .. code-block:: cpp
672
673 class Foo {
674 Mutex mu_;
675 int p1_ PW_GUARDED_BY(mu_);
676 ...
677 };
678
679.. cpp:function:: PW_PT_GUARDED_BY(x)
680
681 Documents if the memory location pointed to by a pointer should be guarded
682 by a lock when dereferencing the pointer.
683
684 Example:
685
686 .. code-block:: cpp
687
688 class Foo {
689 Mutex mu_;
690 int *p1_ PW_PT_GUARDED_BY(mu_);
691 ...
692 };
693
694 Note that a pointer variable to a shared memory location could itself be a
695 shared variable.
696
697 Example:
698
699 .. code-block:: cpp
700
701 // `q_`, guarded by `mu1_`, points to a shared memory location that is
702 // guarded by `mu2_`:
703 int *q_ PW_GUARDED_BY(mu1_) PW_PT_GUARDED_BY(mu2_);
704
705.. cpp:function:: PW_ACQUIRED_AFTER(...)
706.. cpp:function:: PW_ACQUIRED_BEFORE(...)
707
708 Documents the acquisition order between locks that can be held
709 simultaneously by a thread. For any two locks that need to be annotated
710 to establish an acquisition order, only one of them needs the annotation.
711 (i.e. You don't have to annotate both locks with both ``PW_ACQUIRED_AFTER``
712 and ``PW_ACQUIRED_BEFORE``.)
713
714 As with ``PW_GUARDED_BY``, this is only applicable to locks that are shared
715 fields or global variables.
716
717 Example:
718
719 .. code-block:: cpp
720
721 Mutex m1_;
722 Mutex m2_ PW_ACQUIRED_AFTER(m1_);
723
724.. cpp:function:: PW_EXCLUSIVE_LOCKS_REQUIRED(...)
725.. cpp:function:: PW_SHARED_LOCKS_REQUIRED(...)
726
727 Documents a function that expects a lock to be held prior to entry.
728 The lock is expected to be held both on entry to, and exit from, the
729 function.
730
731 An exclusive lock allows read-write access to the guarded data member(s), and
732 only one thread can acquire a lock exclusively at any one time. A shared lock
733 allows read-only access, and any number of threads can acquire a shared lock
734 concurrently.
735
736 Generally, non-const methods should be annotated with
737 ``PW_EXCLUSIVE_LOCKS_REQUIRED``, while const methods should be annotated with
738 ``PW_SHARED_LOCKS_REQUIRED``.
739
740 Example:
741
742 .. code-block:: cpp
743
744 Mutex mu1, mu2;
745 int a PW_GUARDED_BY(mu1);
746 int b PW_GUARDED_BY(mu2);
747
748 void foo() PW_EXCLUSIVE_LOCKS_REQUIRED(mu1, mu2) { ... }
749 void bar() const PW_SHARED_LOCKS_REQUIRED(mu1, mu2) { ... }
750
751.. cpp:function:: PW_LOCKS_EXCLUDED(...)
752
753 Documents the locks acquired in the body of the function. These locks
754 cannot be held when calling this function (as Pigweed's default locks are
755 non-reentrant).
756
757 Example:
758
759 .. code-block:: cpp
760
761 Mutex mu;
762 int a PW_GUARDED_BY(mu);
763
764 void foo() PW_LOCKS_EXCLUDED(mu) {
765 mu.lock();
766 ...
767 mu.unlock();
768 }
769
770.. cpp:function:: PW_LOCK_RETURNED(...)
771
772 Documents a function that returns a lock without acquiring it. For example,
773 a public getter method that returns a pointer to a private lock should
774 be annotated with ``PW_LOCK_RETURNED``.
775
776 Example:
777
778 .. code-block:: cpp
779
780 class Foo {
781 public:
782 Mutex* mu() PW_LOCK_RETURNED(mu) { return &mu; }
783
784 private:
785 Mutex mu;
786 };
787
788.. cpp:function:: PW_NO_LOCK_SAFETY_ANALYSIS()
789
790 Turns off thread safety checking within the body of a particular function.
791 This annotation is used to mark functions that are known to be correct, but
792 the locking behavior is more complicated than the analyzer can handle.
793
794Annotating Lock Objects
795^^^^^^^^^^^^^^^^^^^^^^^
796In order of lock usage annotation to work, the lock objects themselves need to
797be annotated as well. In case you are providing your own lock or psuedo-lock
798object, you can use the macros in this section to annotate it.
799
800As an example we've annotated a Lock and a RAII ScopedLocker object for you, see
801the macro documentation after for more details:
802
803.. code-block:: cpp
804
805 class PW_LOCKABLE("Lock") Lock {
806 public:
807 void Lock() PW_EXCLUSIVE_LOCK_FUNCTION();
808
809 void ReaderLock() PW_SHARED_LOCK_FUNCTION();
810
811 void Unlock() PW_UNLOCK_FUNCTION();
812
813 void ReaderUnlock() PW_SHARED_TRYLOCK_FUNCTION();
814
815 bool TryLock() PW_EXCLUSIVE_TRYLOCK_FUNCTION(true);
816
817 bool ReaderTryLock() PW_SHARED_TRYLOCK_FUNCTION(true);
818
819 void AssertHeld() PW_ASSERT_EXCLUSIVE_LOCK();
820
821 void AssertReaderHeld() PW_ASSERT_SHARED_LOCK();
822 };
823
824
825 // Tag types for selecting a constructor.
826 struct adopt_lock_t {} inline constexpr adopt_lock = {};
827 struct defer_lock_t {} inline constexpr defer_lock = {};
828 struct shared_lock_t {} inline constexpr shared_lock = {};
829
830 class PW_SCOPED_LOCKABLE ScopedLocker {
831 // Acquire lock, implicitly acquire *this and associate it with lock.
832 ScopedLocker(Lock *lock) PW_EXCLUSIVE_LOCK_FUNCTION(lock)
833 : lock_(lock), locked(true) {
834 lock->Lock();
835 }
836
837 // Assume lock is held, implicitly acquire *this and associate it with lock.
838 ScopedLocker(Lock *lock, adopt_lock_t) PW_EXCLUSIVE_LOCKS_REQUIRED(lock)
839 : lock_(lock), locked(true) {}
840
841 // Acquire lock in shared mode, implicitly acquire *this and associate it
842 // with lock.
843 ScopedLocker(Lock *lock, shared_lock_t) PW_SHARED_LOCK_FUNCTION(lock)
844 : lock_(lock), locked(true) {
845 lock->ReaderLock();
846 }
847
848 // Assume lock is held in shared mode, implicitly acquire *this and associate
849 // it with lock.
850 ScopedLocker(Lock *lock, adopt_lock_t, shared_lock_t)
851 PW_SHARED_LOCKS_REQUIRED(lock) : lock_(lock), locked(true) {}
852
853 // Assume lock is not held, implicitly acquire *this and associate it with
854 // lock.
855 ScopedLocker(Lock *lock, defer_lock_t) PW_LOCKS_EXCLUDED(lock)
856 : lock_(lock), locked(false) {}
857
858 // Release *this and all associated locks, if they are still held.
859 // There is no warning if the scope was already unlocked before.
860 ~ScopedLocker() PW_UNLOCK_FUNCTION() {
861 if (locked)
862 lock_->GenericUnlock();
863 }
864
865 // Acquire all associated locks exclusively.
866 void Lock() PW_EXCLUSIVE_LOCK_FUNCTION() {
867 lock_->Lock();
868 locked = true;
869 }
870
871 // Try to acquire all associated locks exclusively.
872 bool TryLock() PW_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
873 return locked = lock_->TryLock();
874 }
875
876 // Acquire all associated locks in shared mode.
877 void ReaderLock() PW_SHARED_LOCK_FUNCTION() {
878 lock_->ReaderLock();
879 locked = true;
880 }
881
882 // Try to acquire all associated locks in shared mode.
883 bool ReaderTryLock() PW_SHARED_TRYLOCK_FUNCTION(true) {
884 return locked = lock_->ReaderTryLock();
885 }
886
887 // Release all associated locks. Warn on double unlock.
888 void Unlock() PW_UNLOCK_FUNCTION() {
889 lock_->Unlock();
890 locked = false;
891 }
892
893 // Release all associated locks. Warn on double unlock.
894 void ReaderUnlock() PW_UNLOCK_FUNCTION() {
895 lock_->ReaderUnlock();
896 locked = false;
897 }
898
899 private:
900 Lock* lock_;
901 bool locked_;
902 };
903
904.. cpp:function:: PW_LOCKABLE(name)
905
906 Documents if a class/type is a lockable type (such as the ``pw::sync::Mutex``
907 class). The name is used in the warning messages. This can also be useful on
908 classes which have locking like semantics but aren't actually locks.
909
910.. cpp:function:: PW_SCOPED_LOCKABLE()
911
912 Documents if a class does RAII locking. The name is used in the warning
913 messages.
914
915 The constructor should use ``LOCK_FUNCTION()`` to specify the lock that is
916 acquired, and the destructor should use ``UNLOCK_FUNCTION()`` with no
917 arguments; the analysis will assume that the destructor unlocks whatever the
918 constructor locked.
919
920.. cpp:function:: PW_EXCLUSIVE_LOCK_FUNCTION()
921
922 Documents functions that acquire a lock in the body of a function, and do
923 not release it.
924
925.. cpp:function:: PW_SHARED_LOCK_FUNCTION()
926
927 Documents functions that acquire a shared (reader) lock in the body of a
928 function, and do not release it.
929
930.. cpp:function:: PW_UNLOCK_FUNCTION()
931
932 Documents functions that expect a lock to be held on entry to the function,
933 and release it in the body of the function.
934
935.. cpp:function:: PW_EXCLUSIVE_TRYLOCK_FUNCTION(try_success)
936.. cpp:function:: PW_SHARED_TRYLOCK_FUNCTION(try_success)
937
938 Documents functions that try to acquire a lock, and return success or failure
939 (or a non-boolean value that can be interpreted as a boolean).
940 The first argument should be ``true`` for functions that return ``true`` on
941 success, or ``false`` for functions that return `false` on success. The second
942 argument specifies the lock that is locked on success. If unspecified, this
943 lock is assumed to be ``this``.
944
945.. cpp:function:: PW_ASSERT_EXCLUSIVE_LOCK()
946.. cpp:function:: PW_ASSERT_SHARED_LOCK()
947
948 Documents functions that dynamically check to see if a lock is held, and fail
949 if it is not held.
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800950
951--------------------
952Signaling Primitives
953--------------------
954
Ewout van Bekkum3b9eca42021-04-02 14:54:02 -0700955Native signaling primitives tend to vary more compared to critial section locks
956across different platforms. For example, although common signaling primtives
957like semaphores are in most if not all RTOSes and even POSIX, it was not in the
958STL before C++20. Likewise many C++ developers are surprised that conditional
959variables tend to not be natively supported on RTOSes. Although you can usually
960build any signaling primitive based on other native signaling primitives, this
961may come with non-trivial added overhead in ROM, RAM, and execution efficiency.
962
Ewout van Bekkumf0106062021-05-06 14:08:33 -0700963For this reason, Pigweed intends to provide some simpler signaling primitives
Ewout van Bekkum3b9eca42021-04-02 14:54:02 -0700964which exist to solve a narrow programming need but can be implemented as
965efficiently as possible for the platform that it is used on.
966
967This simpler but highly portable class of signaling primitives is intended to
968ensure that a portability efficiency tradeoff does not have to be made up front.
Ewout van Bekkumf0106062021-05-06 14:08:33 -0700969Today this is class of simpler signaling primitives is limited to the
970``pw::sync::ThreadNotification`` and ``pw::sync::TimedThreadNotification``.
971
972ThreadNotification
973==================
974The ThreadNotification is a synchronization primitive that can be used to
975permit a SINGLE thread to block and consume a latching, saturating
976notification from multiple notifiers.
977
Ewout van Bekkum0bf96252021-08-24 09:44:06 -0700978.. Note::
979 Although only a single thread can block on a ThreadNotification at a time,
980 many instances may be used by a single thread just like binary semaphores.
981 This is in contrast to some native RTOS APIs, such as direct task
982 notifications, which re-use the same state within a thread's context.
983
Ewout van Bekkumf0106062021-05-06 14:08:33 -0700984.. Warning::
985 This is a single consumer/waiter, multiple producer/notifier API!
986 The acquire APIs must only be invoked by a single consuming thread. As a
987 result, having multiple threads receiving notifications via the acquire API
988 is unsupported.
989
990This is effectively a subset of the ``pw::sync::BinarySemaphore`` API, except
991that only a single thread can be notified and block at a time.
992
993The single consumer aspect of the API permits the use of a smaller and/or
994faster native APIs such as direct thread signaling. This should be
Ewout van Bekkum3b9eca42021-04-02 14:54:02 -0700995backed by the most efficient native primitive for a target, regardless of
996whether that is a semaphore, event flag group, condition variable, or something
997else.
998
Ewout van Bekkumf0106062021-05-06 14:08:33 -0700999Generic BinarySemaphore-based Backend
1000-------------------------------------
1001This module provides a generic backend for ``pw::sync::ThreadNotification`` via
1002``pw_sync:binary_semaphore_thread_notification`` which uses a
1003``pw::sync::BinarySemaphore`` as the backing primitive. See
1004:ref:`BinarySemaphore <module-pw_sync-binary-semaphore>` for backend
1005availability.
1006
1007Optimized Backend
1008-----------------
1009.. list-table::
1010
1011 * - *Supported on*
1012 - *Optimized backend module*
1013 * - FreeRTOS
1014 - Planned
1015 * - ThreadX
1016 - Planned
1017 * - embOS
1018 - Planned
1019 * - STL
1020 - Not planned, use ``pw_sync:binary_semaphore_thread_notification``
1021 * - Baremetal
1022 - Planned
1023 * - Zephyr
1024 - Planned
1025 * - CMSIS-RTOS API v2 & RTX5
1026 - Planned
1027
1028C++
1029---
1030.. cpp:class:: pw::sync::ThreadNotification
1031
1032 .. cpp:function:: void acquire()
1033
1034 Blocks indefinitely until the thread is notified, i.e. until the
1035 notification latch can be cleared because it was set.
1036
1037 Clears the notification latch.
1038
1039 **IMPORTANT:** This should only be used by a single consumer thread.
1040
1041 .. cpp:function:: bool try_acquire()
1042
1043 Returns whether the thread has been notified, i.e. whether the notificion
1044 latch was set and resets the latch regardless.
1045
1046 Clears the notification latch.
1047
1048 Returns true if the thread was notified, meaning the the internal latch was
1049 reset successfully.
1050
1051 **IMPORTANT:** This should only be used by a single consumer thread.
1052
1053 .. cpp:function:: void release()
1054
1055 Notifies the thread in a saturating manner, setting the notification latch.
1056
1057 Raising the notification multiple time without it being acquired by the
1058 consuming thread is equivalent to raising the notification once to the
1059 thread. The notification is latched in case the thread was not waiting at
1060 the time.
1061
1062 This is IRQ and thread safe.
1063
1064 .. list-table::
1065
1066 * - *Safe to use in context*
1067 - *Thread*
1068 - *Interrupt*
1069 - *NMI*
1070 * - ``ThreadNotification::ThreadNotification``
1071 - ✔
1072 -
1073 -
1074 * - ``ThreadNotification::~ThreadNotification``
1075 - ✔
1076 -
1077 -
1078 * - ``void ThreadNotification::acquire``
1079 - ✔
1080 -
1081 -
1082 * - ``bool ThreadNotification::try_acquire``
1083 - ✔
1084 -
1085 -
1086 * - ``void ThreadNotification::release``
1087 - ✔
1088 - ✔
1089 -
1090
1091Examples in C++
1092^^^^^^^^^^^^^^^
1093.. code-block:: cpp
1094
1095 #include "pw_sync/thread_notification.h"
1096 #include "pw_thread/thread_core.h"
1097
1098 class FooHandler() : public pw::thread::ThreadCore {
1099 // Public API invoked by other threads and/or interrupts.
1100 void NewFooAvailable() {
1101 new_foo_notification_.release();
1102 }
1103
1104 private:
1105 pw::sync::ThreadNotification new_foo_notification_;
1106
1107 // Thread function.
1108 void Run() override {
1109 while (true) {
1110 new_foo_notification_.acquire();
1111 HandleFoo();
1112 }
1113 }
1114
1115 void HandleFoo();
1116 }
1117
1118TimedThreadNotification
1119=======================
1120The TimedThreadNotification is an extension of the ThreadNotification which
1121offers timeout and deadline based semantics.
1122
1123.. Warning::
1124 This is a single consumer/waiter, multiple producer/notifier API!
1125 The acquire APIs must only be invoked by a single consuming thread. As a
1126 result, having multiple threads receiving notifications via the acquire API
1127 is unsupported.
1128
1129Generic BinarySemaphore-based Backend
1130-------------------------------------
1131This module provides a generic backend for ``pw::sync::TimedThreadNotification``
1132via ``pw_sync:binary_semaphore_timed_thread_notification`` which uses a
1133``pw::sync::BinarySemaphore`` as the backing primitive. See
1134:ref:`BinarySemaphore <module-pw_sync-binary-semaphore>` for backend
1135availability.
1136
1137Optimized Backend
1138-----------------
1139.. list-table::
1140
1141 * - *Supported on*
1142 - *Backend module*
1143 * - FreeRTOS
1144 - Planned
1145 * - ThreadX
1146 - Planned
1147 * - embOS
1148 - Planned
1149 * - STL
1150 - Not planned, use ``pw_sync:binary_semaphore_thread_notification``
1151 * - Zephyr
1152 - Planned
1153 * - CMSIS-RTOS API v2 & RTX5
1154 - Planned
1155
1156C++
1157---
1158.. cpp:class:: pw::sync::TimedThreadNotification
1159
1160 .. cpp:function:: void acquire()
1161
1162 Blocks indefinitely until the thread is notified, i.e. until the
1163 notification latch can be cleared because it was set.
1164
1165 Clears the notification latch.
1166
1167 **IMPORTANT:** This should only be used by a single consumer thread.
1168
1169 .. cpp:function:: bool try_acquire()
1170
1171 Returns whether the thread has been notified, i.e. whether the notificion
1172 latch was set and resets the latch regardless.
1173
1174 Clears the notification latch.
1175
1176 Returns true if the thread was notified, meaning the the internal latch was
1177 reset successfully.
1178
1179 **IMPORTANT:** This should only be used by a single consumer thread.
1180
1181 .. cpp:function:: void release()
1182
1183 Notifies the thread in a saturating manner, setting the notification latch.
1184
1185 Raising the notification multiple time without it being acquired by the
1186 consuming thread is equivalent to raising the notification once to the
1187 thread. The notification is latched in case the thread was not waiting at
1188 the time.
1189
1190 This is IRQ and thread safe.
1191
1192 .. cpp:function:: bool try_acquire_for(chrono::SystemClock::duration timeout)
1193
1194 Blocks until the specified timeout duration has elapsed or the thread
1195 has been notified (i.e. notification latch can be cleared because it was
1196 set), whichever comes first.
1197
1198 Clears the notification latch.
1199
1200 Returns true if the thread was notified, meaning the the internal latch was
1201 reset successfully.
1202
1203 **IMPORTANT:** This should only be used by a single consumer thread.
1204
1205 .. cpp:function:: bool try_acquire_until(chrono::SystemClock::time_point deadline)
1206
1207 Blocks until the specified deadline time has been reached the thread has
1208 been notified (i.e. notification latch can be cleared because it was set),
1209 whichever comes first.
1210
1211 Clears the notification latch.
1212
1213 Returns true if the thread was notified, meaning the the internal latch was
1214 reset successfully.
1215
1216 **IMPORTANT:** This should only be used by a single consumer thread.
1217
1218 .. list-table::
1219
1220 * - *Safe to use in context*
1221 - *Thread*
1222 - *Interrupt*
1223 - *NMI*
1224 * - ``ThreadNotification::ThreadNotification``
1225 - ✔
1226 -
1227 -
1228 * - ``ThreadNotification::~ThreadNotification``
1229 - ✔
1230 -
1231 -
1232 * - ``void ThreadNotification::acquire``
1233 - ✔
1234 -
1235 -
1236 * - ``bool ThreadNotification::try_acquire``
1237 - ✔
1238 -
1239 -
1240 * - ``bool ThreadNotification::try_acquire_for``
1241 - ✔
1242 -
1243 -
1244 * - ``bool ThreadNotification::try_acquire_until``
1245 - ✔
1246 -
1247 -
1248 * - ``void ThreadNotification::release``
1249 - ✔
1250 - ✔
1251 -
1252
1253Examples in C++
1254^^^^^^^^^^^^^^^
1255.. code-block:: cpp
1256
1257 #include "pw_sync/timed_thread_notification.h"
1258 #include "pw_thread/thread_core.h"
1259
1260 class FooHandler() : public pw::thread::ThreadCore {
1261 // Public API invoked by other threads and/or interrupts.
1262 void NewFooAvailable() {
1263 new_foo_notification_.release();
1264 }
1265
1266 private:
1267 pw::sync::TimedThreadNotification new_foo_notification_;
1268
1269 // Thread function.
1270 void Run() override {
1271 while (true) {
1272 if (new_foo_notification_.try_acquire_for(kNotificationTimeout)) {
1273 HandleFoo();
1274 }
1275 DoOtherStuff();
1276 }
1277 }
1278
1279 void HandleFoo();
1280 void DoOtherStuff();
1281 }
1282
Ewout van Bekkumf84638b2021-03-12 16:09:08 -08001283CountingSemaphore
1284=================
1285The CountingSemaphore is a synchronization primitive that can be used for
1286counting events and/or resource management where receiver(s) can block on
1287acquire until notifier(s) signal by invoking release.
1288
1289Note that unlike Mutexes, priority inheritance is not used by semaphores meaning
1290semaphores are subject to unbounded priority inversions. Due to this, Pigweed
1291does not recommend semaphores for mutual exclusion.
1292
1293The CountingSemaphore is initialized to being empty or having no tokens.
1294
1295The entire API is thread safe, but only a subset is interrupt safe. None of it
1296is NMI safe.
1297
1298.. Warning::
1299 Releasing multiple tokens is often not natively supported, meaning you may
1300 end up invoking the native kernel API many times, i.e. once per token you
1301 are releasing!
1302
Ewout van Bekkum3b9eca42021-04-02 14:54:02 -07001303.. list-table::
1304
1305 * - *Supported on*
1306 - *Backend module*
1307 * - FreeRTOS
1308 - :ref:`module-pw_sync_freertos`
1309 * - ThreadX
1310 - :ref:`module-pw_sync_threadx`
1311 * - embOS
1312 - :ref:`module-pw_sync_embos`
1313 * - STL
1314 - :ref:`module-pw_sync_stl`
1315 * - Zephyr
1316 - Planned
1317 * - CMSIS-RTOS API v2 & RTX5
1318 - Planned
1319
Ewout van Bekkumf0106062021-05-06 14:08:33 -07001320.. _module-pw_sync-binary-semaphore:
1321
Ewout van Bekkumf84638b2021-03-12 16:09:08 -08001322BinarySemaphore
1323===============
1324BinarySemaphore is a specialization of CountingSemaphore with an arbitrary token
1325limit of 1. Note that that ``max()`` is >= 1, meaning it may be released up to
1326``max()`` times but only acquired once for those N releases.
1327
1328Implementations of BinarySemaphore are typically more efficient than the
1329default implementation of CountingSemaphore.
1330
1331The BinarySemaphore is initialized to being empty or having no tokens.
1332
1333The entire API is thread safe, but only a subset is interrupt safe. None of it
1334is NMI safe.
Ewout van Bekkum3b9eca42021-04-02 14:54:02 -07001335
1336.. list-table::
1337
1338 * - *Supported on*
1339 - *Backend module*
1340 * - FreeRTOS
1341 - :ref:`module-pw_sync_freertos`
1342 * - ThreadX
1343 - :ref:`module-pw_sync_threadx`
1344 * - embOS
1345 - :ref:`module-pw_sync_embos`
1346 * - STL
1347 - :ref:`module-pw_sync_stl`
1348 * - Zephyr
1349 - Planned
1350 * - CMSIS-RTOS API v2 & RTX5
1351 - Planned
1352
Ewout van Bekkumcc756c82021-05-12 07:57:43 -07001353Conditional Variables
1354=====================
1355We've decided for now to skip on conditional variables. These are constructs,
1356which are typically not natively available on RTOSes. CVs would have to be
1357backed by a multiple hidden semaphore(s) in addition to the explicit public
1358mutex. In other words a CV typically ends up as a a composition of
1359synchronization primitives on RTOSes. That being said, one could implement them
1360using our semaphore and mutex layers and we may consider providing this in the
1361future. However for most of our resource constrained customers they will mostly
1362likely be using semaphores more often than CVs.