blob: de5a125aaf33aa3937b29f6221ee56a56e0fafc2 [file] [log] [blame]
Ewout van Bekkum58901932020-11-09 12:46:52 -08001.. _module-pw_sync:
2
Ewout van Bekkumf84638b2021-03-12 16:09:08 -08003=======
Ewout van Bekkum58901932020-11-09 12:46:52 -08004pw_sync
Ewout van Bekkumf84638b2021-03-12 16:09:08 -08005=======
6The ``pw_sync`` module contains utilities for synchronizing between threads
7and/or interrupts through signaling primitives and critical section lock
8primitives.
Ewout van Bekkum58901932020-11-09 12:46:52 -08009
Ewout van Bekkumf84638b2021-03-12 16:09:08 -080010.. contents::
11 :local:
12 :depth: 2
13
14.. Warning::
15 This module is still under construction, the API is not yet stable.
16
17.. Note::
18 The objects in this module do not have an Init() style public API which is
19 common in many RTOS C APIs. Instead, they rely on being able to invoke the
20 native initialization APIs for synchronization primitives during C++
21 construction.
22 In order to support global statically constructed synchronization without
23 constexpr constructors, the user and/or backend **MUST** ensure that any
24 initialization required in your environment is done prior to the creation
25 and/or initialization of the native synchronization primitives
26 (e.g. kernel initialization).
27
28--------------------------------
29Critical Section Lock Primitives
30--------------------------------
31The critical section lock primitives provided by this module comply with
32`BasicLockable <https://en.cppreference.com/w/cpp/named_req/BasicLockable>`_,
33`Lockable <https://en.cppreference.com/w/cpp/named_req/Lockable>`_, and where
34relevant
35`TimedLockable <https://en.cppreference.com/w/cpp/named_req/TimedLockable>`_ C++
36named requirements. This means that they are compatible with existing helpers in
37the STL's ``<mutex>`` thread support library. For example `std::lock_guard <https://en.cppreference.com/w/cpp/thread/lock_guard>`_
38and `std::unique_lock <https://en.cppreference.com/w/cpp/thread/unique_lock>`_ can be directly used.
39
40Mutex
41=====
42The Mutex is a synchronization primitive that can be used to protect shared data
43from being simultaneously accessed by multiple threads. It offers exclusive,
44non-recursive ownership semantics where priority inheritance is used to solve
45the classic priority-inversion problem.
46
47The Mutex's API is C++11 STL
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -070048`std::mutex <https://en.cppreference.com/w/cpp/thread/mutex>`_ like,
Ewout van Bekkumf84638b2021-03-12 16:09:08 -080049meaning it is a
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -070050`BasicLockable <https://en.cppreference.com/w/cpp/named_req/BasicLockable>`_
51and `Lockable <https://en.cppreference.com/w/cpp/named_req/Lockable>`_.
Ewout van Bekkum3b9eca42021-04-02 14:54:02 -070052
53.. list-table::
54
55 * - *Supported on*
56 - *Backend module*
57 * - FreeRTOS
58 - :ref:`module-pw_sync_freertos`
59 * - ThreadX
60 - :ref:`module-pw_sync_threadx`
61 * - embOS
62 - :ref:`module-pw_sync_embos`
63 * - STL
64 - :ref:`module-pw_sync_stl`
65 * - Baremetal
66 - Planned
67 * - Zephyr
68 - Planned
69 * - CMSIS-RTOS API v2 & RTX5
70 - Planned
Ewout van Bekkumf84638b2021-03-12 16:09:08 -080071
72C++
73---
74.. cpp:class:: pw::sync::Mutex
75
76 .. cpp:function:: void lock()
77
78 Locks the mutex, blocking indefinitely. Failures are fatal.
79
80 **Precondition:** The lock isn't already held by this thread. Recursive
81 locking is undefined behavior.
82
83 .. cpp:function:: bool try_lock()
84
85 Attempts to lock the mutex in a non-blocking manner.
86 Returns true if the mutex was successfully acquired.
87
88 **Precondition:** The lock isn't already held by this thread. Recursive
89 locking is undefined behavior.
90
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -070091 .. cpp:function:: void unlock()
92
93 Unlocks the mutex. Failures are fatal.
94
95 **Precondition:** The mutex is held by this thread.
96
97
98 .. list-table::
99
100 * - *Safe to use in context*
101 - *Thread*
102 - *Interrupt*
103 - *NMI*
104 * - ``Mutex::Mutex``
105 - ✔
106 -
107 -
108 * - ``Mutex::~Mutex``
109 - ✔
110 -
111 -
112 * - ``void Mutex::lock``
113 - ✔
114 -
115 -
116 * - ``bool Mutex::try_lock``
117 - ✔
118 -
119 -
120 * - ``void Mutex::unlock``
121 - ✔
122 -
123 -
124
125Examples in C++
126^^^^^^^^^^^^^^^
127.. code-block:: cpp
128
129 #include "pw_sync/mutex.h"
130
131 pw::sync::Mutex mutex;
132
133 void ThreadSafeCriticalSection() {
134 mutex.lock();
135 NotThreadSafeCriticalSection();
136 mutex.unlock();
137 }
138
139
140Alternatively you can use C++'s RAII helpers to ensure you always unlock.
141
142.. code-block:: cpp
143
144 #include <mutex>
145
146 #include "pw_sync/mutex.h"
147
148 pw::sync::Mutex mutex;
149
150 void ThreadSafeCriticalSection() {
151 std::lock_guard lock(mutex);
152 NotThreadSafeCriticalSection();
153 }
154
155
156C
157-
158The Mutex must be created in C++, however it can be passed into C using the
159``pw_sync_Mutex`` opaque struct alias.
160
161.. cpp:function:: void pw_sync_Mutex_Lock(pw_sync_Mutex* mutex)
162
163 Invokes the ``Mutex::lock`` member function on the given ``mutex``.
164
165.. cpp:function:: bool pw_sync_Mutex_TryLock(pw_sync_Mutex* mutex)
166
167 Invokes the ``Mutex::try_lock`` member function on the given ``mutex``.
168
169.. cpp:function:: void pw_sync_Mutex_Unlock(pw_sync_Mutex* mutex)
170
171 Invokes the ``Mutex::unlock`` member function on the given ``mutex``.
172
173.. list-table::
174
175 * - *Safe to use in context*
176 - *Thread*
177 - *Interrupt*
178 - *NMI*
179 * - ``void pw_sync_Mutex_Lock``
180 - ✔
181 -
182 -
183 * - ``bool pw_sync_Mutex_TryLock``
184 - ✔
185 -
186 -
187 * - ``void pw_sync_Mutex_Unlock``
188 - ✔
189 -
190 -
191
192Example in C
193^^^^^^^^^^^^
194.. code-block:: cpp
195
196 #include "pw_sync/mutex.h"
197
198 pw::sync::Mutex mutex;
199
200 extern pw_sync_Mutex mutex; // This can only be created in C++.
201
202 void ThreadSafeCriticalSection(void) {
203 pw_sync_Mutex_Lock(&mutex);
204 NotThreadSafeCriticalSection();
205 pw_sync_Mutex_Unlock(&mutex);
206 }
207
208TimedMutex
209==========
210The TimedMutex is an extension of the Mutex which offers timeout and deadline
211based semantics.
212
213The TimedMutex's API is C++11 STL
214`std::timed_mutex <https://en.cppreference.com/w/cpp/thread/timed_mutex>`_ like,
215meaning it is a
216`BasicLockable <https://en.cppreference.com/w/cpp/named_req/BasicLockable>`_,
217`Lockable <https://en.cppreference.com/w/cpp/named_req/Lockable>`_, and
218`TimedLockable <https://en.cppreference.com/w/cpp/named_req/TimedLockable>`_.
219
220Note that the ``TimedMutex`` is a derived ``Mutex`` class, meaning that
221a ``TimedMutex`` can be used by someone who needs the basic ``Mutex``. This is
222in stark contrast to the C++ STL's
223`std::timed_mutex <https://en.cppreference.com/w/cpp/thread/timed_mutex>`_.
224
225
226.. list-table::
227
228 * - *Supported on*
229 - *Backend module*
230 * - FreeRTOS
231 - :ref:`module-pw_sync_freertos`
232 * - ThreadX
233 - :ref:`module-pw_sync_threadx`
234 * - embOS
235 - :ref:`module-pw_sync_embos`
236 * - STL
237 - :ref:`module-pw_sync_stl`
238 * - Zephyr
239 - Planned
240 * - CMSIS-RTOS API v2 & RTX5
241 - Planned
242
243C++
244---
245.. cpp:class:: pw::sync::TimedMutex
246
247 .. cpp:function:: void lock()
248
249 Locks the mutex, blocking indefinitely. Failures are fatal.
250
251 **Precondition:** The lock isn't already held by this thread. Recursive
252 locking is undefined behavior.
253
254 .. cpp:function:: bool try_lock()
255
256 Attempts to lock the mutex in a non-blocking manner.
257 Returns true if the mutex was successfully acquired.
258
259 **Precondition:** The lock isn't already held by this thread. Recursive
260 locking is undefined behavior.
261
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800262 .. cpp:function:: bool try_lock_for(chrono::SystemClock::duration for_at_least)
263
264 Attempts to lock the mutex where, if needed, blocking for at least the
265 specified duration.
266 Returns true if the mutex was successfully acquired.
267
268 **Precondition:** The lock isn't already held by this thread. Recursive
269 locking is undefined behavior.
270
271 .. cpp:function:: bool try_lock_until(chrono::SystemClock::time_point until_at_least)
272
273 Attempts to lock the mutex where, if needed, blocking until at least the
274 specified time_point.
275 Returns true if the mutex was successfully acquired.
276
277 **Precondition:** The lock isn't already held by this thread. Recursive
278 locking is undefined behavior.
279
280 .. cpp:function:: void unlock()
281
282 Unlocks the mutex. Failures are fatal.
283
284 **Precondition:** The mutex is held by this thread.
285
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800286
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700287 .. list-table::
288
289 * - *Safe to use in context*
290 - *Thread*
291 - *Interrupt*
292 - *NMI*
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700293 * - ``TimedMutex::TimedMutex``
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700294 - ✔
295 -
296 -
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700297 * - ``TimedMutex::~TimedMutex``
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700298 - ✔
299 -
300 -
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700301 * - ``void TimedMutex::lock``
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700302 - ✔
303 -
304 -
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700305 * - ``bool TimedMutex::try_lock``
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700306 - ✔
307 -
308 -
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700309 * - ``bool TimedMutex::try_lock_for``
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700310 - ✔
311 -
312 -
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700313 * - ``bool TimedMutex::try_lock_until``
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700314 - ✔
315 -
316 -
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700317 * - ``void TimedMutex::unlock``
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700318 - ✔
319 -
320 -
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800321
322Examples in C++
323^^^^^^^^^^^^^^^
324.. code-block:: cpp
325
326 #include "pw_chrono/system_clock.h"
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700327 #include "pw_sync/timed_mutex.h"
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800328
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700329 pw::sync::TimedMutex mutex;
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800330
331 bool ThreadSafeCriticalSectionWithTimeout(
332 const SystemClock::duration timeout) {
333 if (!mutex.try_lock_for(timeout)) {
334 return false;
335 }
336 NotThreadSafeCriticalSection();
337 mutex.unlock();
338 return true;
339 }
340
341
342Alternatively you can use C++'s RAII helpers to ensure you always unlock.
343
344.. code-block:: cpp
345
346 #include <mutex>
347
348 #include "pw_chrono/system_clock.h"
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700349 #include "pw_sync/timed_mutex.h"
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800350
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700351 pw::sync::TimedMutex mutex;
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800352
353 bool ThreadSafeCriticalSectionWithTimeout(
354 const SystemClock::duration timeout) {
355 std::unique_lock lock(mutex, std::defer_lock);
356 if (!lock.try_lock_for(timeout)) {
357 return false;
358 }
359 NotThreadSafeCriticalSection();
360 return true;
361 }
362
363
364
365C
366-
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700367The TimedMutex must be created in C++, however it can be passed into C using the
368``pw_sync_TimedMutex`` opaque struct alias.
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800369
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700370.. cpp:function:: void pw_sync_TimedMutex_Lock(pw_sync_TimedMutex* mutex)
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800371
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700372 Invokes the ``TimedMutex::lock`` member function on the given ``mutex``.
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800373
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700374.. cpp:function:: bool pw_sync_TimedMutex_TryLock(pw_sync_TimedMutex* mutex)
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800375
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700376 Invokes the ``TimedMutex::try_lock`` member function on the given ``mutex``.
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800377
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700378.. cpp:function:: bool pw_sync_TimedMutex_TryLockFor(pw_sync_TimedMutex* mutex, pw_chrono_SystemClock_Duration for_at_least)
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800379
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700380 Invokes the ``TimedMutex::try_lock_for`` member function on the given ``mutex``.
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800381
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700382.. cpp:function:: bool pw_sync_TimedMutex_TryLockUntil(pw_sync_TimedMutex* mutex, pw_chrono_SystemClock_TimePoint until_at_least)
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800383
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700384 Invokes the ``TimedMutex::try_lock_until`` member function on the given ``mutex``.
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800385
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700386.. cpp:function:: void pw_sync_TimedMutex_Unlock(pw_sync_TimedMutex* mutex)
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800387
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700388 Invokes the ``TimedMutex::unlock`` member function on the given ``mutex``.
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800389
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700390.. list-table::
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800391
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700392 * - *Safe to use in context*
393 - *Thread*
394 - *Interrupt*
395 - *NMI*
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700396 * - ``void pw_sync_TimedMutex_Lock``
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700397 - ✔
398 -
399 -
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700400 * - ``bool pw_sync_TimedMutex_TryLock``
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700401 - ✔
402 -
403 -
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700404 * - ``bool pw_sync_TimedMutex_TryLockFor``
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700405 - ✔
406 -
407 -
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700408 * - ``bool pw_sync_TimedMutex_TryLockUntil``
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700409 - ✔
410 -
411 -
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700412 * - ``void pw_sync_TimedMutex_Unlock``
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700413 - ✔
414 -
415 -
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800416
417Example in C
418^^^^^^^^^^^^
419.. code-block:: cpp
420
421 #include "pw_chrono/system_clock.h"
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700422 #include "pw_sync/timed_mutex.h"
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800423
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700424 pw::sync::TimedMutex mutex;
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800425
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700426 extern pw_sync_TimedMutex mutex; // This can only be created in C++.
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800427
428 bool ThreadSafeCriticalSectionWithTimeout(
429 const pw_chrono_SystemClock_Duration timeout) {
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700430 if (!pw_sync_TimedMutex_TryLockFor(&mutex, timeout)) {
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800431 return false;
432 }
433 NotThreadSafeCriticalSection();
Ewout van Bekkum6f5b8fb2021-04-06 16:15:22 -0700434 pw_sync_TimedMutex_Unlock(&mutex);
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800435 return true;
436 }
437
438
439InterruptSpinLock
440=================
441The InterruptSpinLock is a synchronization primitive that can be used to protect
442shared data from being simultaneously accessed by multiple threads and/or
443interrupts as a targeted global lock, with the exception of Non-Maskable
444Interrupts (NMIs). It offers exclusive, non-recursive ownership semantics where
445IRQs up to a backend defined level of "NMIs" will be masked to solve
446priority-inversion.
447
448This InterruptSpinLock relies on built-in local interrupt masking to make it
449interrupt safe without requiring the caller to separately mask and unmask
450interrupts when using this primitive.
451
452Unlike global interrupt locks, this also works safely and efficiently on SMP
453systems. On systems which are not SMP, spinning is not required but some state
454may still be used to detect recursion.
455
456The InterruptSpinLock is a
457`BasicLockable <https://en.cppreference.com/w/cpp/named_req/BasicLockable>`_
458and
459`Lockable <https://en.cppreference.com/w/cpp/named_req/Lockable>`_.
460
Ewout van Bekkum3b9eca42021-04-02 14:54:02 -0700461.. list-table::
462
463 * - *Supported on*
464 - *Backend module*
465 * - FreeRTOS
466 - :ref:`module-pw_sync_freertos`
467 * - ThreadX
468 - :ref:`module-pw_sync_threadx`
469 * - embOS
470 - :ref:`module-pw_sync_embos`
471 * - STL
472 - :ref:`module-pw_sync_stl`
473 * - Baremetal
474 - Planned, not ready for use
475 * - Zephyr
476 - Planned
477 * - CMSIS-RTOS API v2 & RTX5
478 - Planned
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800479
480C++
481---
482.. cpp:class:: pw::sync::InterruptSpinLock
483
484 .. cpp:function:: void lock()
485
486 Locks the spinlock, blocking indefinitely. Failures are fatal.
487
488 **Precondition:** Recursive locking is undefined behavior.
489
490 .. cpp:function:: bool try_lock()
491
492 Attempts to lock the spinlock in a non-blocking manner.
493 Returns true if the spinlock was successfully acquired.
494
495 **Precondition:** Recursive locking is undefined behavior.
496
497 .. cpp:function:: void unlock()
498
499 Unlocks the mutex. Failures are fatal.
500
501 **Precondition:** The spinlock is held by the caller.
502
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700503 .. list-table::
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800504
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700505 * - *Safe to use in context*
506 - *Thread*
507 - *Interrupt*
508 - *NMI*
509 * - ``InterruptSpinLock::InterruptSpinLock``
510 - ✔
511 - ✔
512 -
513 * - ``InterruptSpinLock::~InterruptSpinLock``
514 - ✔
515 - ✔
516 -
517 * - ``void InterruptSpinLock::lock``
518 - ✔
519 - ✔
520 -
521 * - ``bool InterruptSpinLock::try_lock``
522 - ✔
523 - ✔
524 -
525 * - ``void InterruptSpinLock::unlock``
526 - ✔
527 - ✔
528 -
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800529
530Examples in C++
531^^^^^^^^^^^^^^^
532.. code-block:: cpp
533
534 #include "pw_sync/interrupt_spin_lock.h"
535
536 pw::sync::InterruptSpinLock interrupt_spin_lock;
537
538 void InterruptSafeCriticalSection() {
539 interrupt_spin_lock.lock();
540 NotThreadSafeCriticalSection();
541 interrupt_spin_lock.unlock();
542 }
543
544
545Alternatively you can use C++'s RAII helpers to ensure you always unlock.
546
547.. code-block:: cpp
548
549 #include <mutex>
550
551 #include "pw_sync/interrupt_spin_lock.h"
552
553 pw::sync::InterruptSpinLock interrupt_spin_lock;
554
555 void InterruptSafeCriticalSection() {
556 std::lock_guard lock(interrupt_spin_lock);
557 NotThreadSafeCriticalSection();
558 }
559
560
561C
562-
563The InterruptSpinLock must be created in C++, however it can be passed into C using the
564``pw_sync_InterruptSpinLock`` opaque struct alias.
565
566.. cpp:function:: void pw_sync_InterruptSpinLock_Lock(pw_sync_InterruptSpinLock* interrupt_spin_lock)
567
568 Invokes the ``InterruptSpinLock::lock`` member function on the given ``interrupt_spin_lock``.
569
570.. cpp:function:: bool pw_sync_InterruptSpinLock_TryLock(pw_sync_InterruptSpinLock* interrupt_spin_lock)
571
572 Invokes the ``InterruptSpinLock::try_lock`` member function on the given ``interrupt_spin_lock``.
573
574.. cpp:function:: void pw_sync_InterruptSpinLock_Unlock(pw_sync_InterruptSpinLock* interrupt_spin_lock)
575
576 Invokes the ``InterruptSpinLock::unlock`` member function on the given ``interrupt_spin_lock``.
577
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700578.. list-table::
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800579
Ewout van Bekkumfe700662021-04-02 16:48:50 -0700580 * - *Safe to use in context*
581 - *Thread*
582 - *Interrupt*
583 - *NMI*
584 * - ``void pw_sync_InterruptSpinLock_Lock``
585 - ✔
586 - ✔
587 -
588 * - ``bool pw_sync_InterruptSpinLock_TryLock``
589 - ✔
590 - ✔
591 -
592 * - ``void pw_sync_InterruptSpinLock_Unlock``
593 - ✔
594 - ✔
595 -
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800596
597Example in C
598^^^^^^^^^^^^
599.. code-block:: cpp
600
601 #include "pw_chrono/system_clock.h"
602 #include "pw_sync/interrupt_spin_lock.h"
603
604 pw::sync::InterruptSpinLock interrupt_spin_lock;
605
606 extern pw_sync_InterruptSpinLock interrupt_spin_lock; // This can only be created in C++.
607
608 void InterruptSafeCriticalSection(void) {
609 pw_sync_InterruptSpinLock_Lock(&interrupt_spin_lock);
610 NotThreadSafeCriticalSection();
611 pw_sync_InterruptSpinLock_Unlock(&interrupt_spin_lock);
612 }
613
614
615--------------------
616Signaling Primitives
617--------------------
618
Ewout van Bekkum3b9eca42021-04-02 14:54:02 -0700619Native signaling primitives tend to vary more compared to critial section locks
620across different platforms. For example, although common signaling primtives
621like semaphores are in most if not all RTOSes and even POSIX, it was not in the
622STL before C++20. Likewise many C++ developers are surprised that conditional
623variables tend to not be natively supported on RTOSes. Although you can usually
624build any signaling primitive based on other native signaling primitives, this
625may come with non-trivial added overhead in ROM, RAM, and execution efficiency.
626
627For this reason, Pigweed intends to provide some "simpler" signaling primitives
628which exist to solve a narrow programming need but can be implemented as
629efficiently as possible for the platform that it is used on.
630
631This simpler but highly portable class of signaling primitives is intended to
632ensure that a portability efficiency tradeoff does not have to be made up front.
633For example we intend to provide a ``pw::sync::Notification`` facade which
634permits a singler consumer to block until an event occurs. This should be
635backed by the most efficient native primitive for a target, regardless of
636whether that is a semaphore, event flag group, condition variable, or something
637else.
638
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800639CountingSemaphore
640=================
641The CountingSemaphore is a synchronization primitive that can be used for
642counting events and/or resource management where receiver(s) can block on
643acquire until notifier(s) signal by invoking release.
644
645Note that unlike Mutexes, priority inheritance is not used by semaphores meaning
646semaphores are subject to unbounded priority inversions. Due to this, Pigweed
647does not recommend semaphores for mutual exclusion.
648
649The CountingSemaphore is initialized to being empty or having no tokens.
650
651The entire API is thread safe, but only a subset is interrupt safe. None of it
652is NMI safe.
653
654.. Warning::
655 Releasing multiple tokens is often not natively supported, meaning you may
656 end up invoking the native kernel API many times, i.e. once per token you
657 are releasing!
658
Ewout van Bekkum3b9eca42021-04-02 14:54:02 -0700659.. list-table::
660
661 * - *Supported on*
662 - *Backend module*
663 * - FreeRTOS
664 - :ref:`module-pw_sync_freertos`
665 * - ThreadX
666 - :ref:`module-pw_sync_threadx`
667 * - embOS
668 - :ref:`module-pw_sync_embos`
669 * - STL
670 - :ref:`module-pw_sync_stl`
671 * - Zephyr
672 - Planned
673 * - CMSIS-RTOS API v2 & RTX5
674 - Planned
675
Ewout van Bekkumf84638b2021-03-12 16:09:08 -0800676BinarySemaphore
677===============
678BinarySemaphore is a specialization of CountingSemaphore with an arbitrary token
679limit of 1. Note that that ``max()`` is >= 1, meaning it may be released up to
680``max()`` times but only acquired once for those N releases.
681
682Implementations of BinarySemaphore are typically more efficient than the
683default implementation of CountingSemaphore.
684
685The BinarySemaphore is initialized to being empty or having no tokens.
686
687The entire API is thread safe, but only a subset is interrupt safe. None of it
688is NMI safe.
Ewout van Bekkum3b9eca42021-04-02 14:54:02 -0700689
690.. list-table::
691
692 * - *Supported on*
693 - *Backend module*
694 * - FreeRTOS
695 - :ref:`module-pw_sync_freertos`
696 * - ThreadX
697 - :ref:`module-pw_sync_threadx`
698 * - embOS
699 - :ref:`module-pw_sync_embos`
700 * - STL
701 - :ref:`module-pw_sync_stl`
702 * - Zephyr
703 - Planned
704 * - CMSIS-RTOS API v2 & RTX5
705 - Planned
706
707Coming Soon
708===========
709We are intending to provide facades for:
710
711* ``pw::sync::Notification``: A portable abstraction to allow threads to receive
712 notification of a single occurrence of a single event.
713
714* ``pw::sync::EventGroup`` A facade for a common primitive on RTOSes like
715 FreeRTOS, RTX5, ThreadX, and embOS which permit threads and interrupts to
716 signal up to 32 events. This permits others threads to be notified when either
717 any or some combination of these events have been signaled. This is frequently
718 used as an alternative to a set of binary semaphore(s). This is not supported
719 natively on Zephyr.