1 // Copyright 2020 The Pigweed Authors
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
7 // https://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
19 #include "pw_chrono/system_clock.h"
20 #include "pw_preprocessor/util.h"
24 #include "pw_sync_backend/counting_semaphore_native.h"
28 // The CountingSemaphore is a synchronization primitive that can be used for
29 // counting events and/or resource management where receiver(s) can block on
30 // acquire until notifier(s) signal by invoking release.
31 // Note that unlike Mutexes, priority inheritance is not used by semaphores
32 // meaning semaphores are subject to unbounded priority inversions.
33 // Pigweed does not recommend semaphores for mutual exclusion. The entire API is
34 // thread safe but only a subset is IRQ safe.
36 // WARNING: In order to support global statically constructed
37 // CountingSemaphores, the backend MUST ensure that any initialization required
38 // in your environment prior to the creation and/or initialization of the native
39 // semaphore (e.g. kernel initialization), is done before or during the
40 // invocation of the global static C++ constructors.
41 class CountingSemaphore {
43 using native_handle_type = backend::NativeCountingSemaphoreHandle;
47 CountingSemaphore(const CountingSemaphore&) = delete;
48 CountingSemaphore(CountingSemaphore&&) = delete;
49 CountingSemaphore& operator=(const CountingSemaphore&) = delete;
50 CountingSemaphore& operator=(CountingSemaphore&&) = delete;
52 // Atomically increments the internal counter by the value of update.
53 // Any thread(s) waiting for the counter to be greater than 0, i.e.
54 // blocked in acquire, will subsequently be unblocked.
59 // update <= max() - counter
60 void release(ptrdiff_t update = 1);
62 // Decrements the internal counter by 1 or blocks indefinitely until it can.
63 // This is thread safe.
66 // Attempts to decrement by the internal counter by 1 without blocking.
67 // Returns true if the internal counter was decremented successfully.
69 bool try_acquire() noexcept;
71 // Attempts to decrement the internal counter by 1 where, if needed, blocking
72 // for at least the specified duration.
73 // Returns true if the internal counter was decremented successfully.
74 // This is thread safe.
75 bool try_acquire_for(chrono::SystemClock::duration for_at_least);
77 // Attempts to decrement the internal counter by 1 where, if needed, blocking
78 // until at least the specified time point.
79 // Returns true if the internal counter was decremented successfully.
80 // This is thread safe.
81 bool try_acquire_until(chrono::SystemClock::time_point until_at_least);
83 static constexpr ptrdiff_t max() noexcept {
84 return backend::kCountingSemaphoreMaxValue;
87 native_handle_type native_handle();
90 // This may be a wrapper around a native type with additional members.
91 backend::NativeCountingSemaphore native_type_;
94 } // namespace pw::sync
96 #include "pw_sync_backend/counting_semaphore_inline.h"
98 using pw_sync_CountingSemaphore = pw::sync::CountingSemaphore;
100 #else // !defined(__cplusplus)
102 typedef struct pw_sync_CountingSemaphore pw_sync_CountingSemaphore;
104 #endif // __cplusplus
108 void pw_sync_CountingSemaphore_Release(pw_sync_CountingSemaphore* semaphore);
109 void pw_sync_CountingSemaphore_ReleaseNum(pw_sync_CountingSemaphore* semaphore,
111 void pw_sync_CountingSemaphore_Acquire(pw_sync_CountingSemaphore* semaphore);
112 bool pw_sync_CountingSemaphore_TryAcquire(pw_sync_CountingSemaphore* semaphore);
113 bool pw_sync_CountingSemaphore_TryAcquireFor(
114 pw_sync_CountingSemaphore* semaphore,
115 pw_chrono_SystemClock_Duration for_at_least);
116 bool pw_sync_CountingSemaphore_TryAcquireUntil(
117 pw_sync_CountingSemaphore* semaphore,
118 pw_chrono_SystemClock_TimePoint until_at_least);
119 ptrdiff_t pw_sync_CountingSemaphore_Max(void);