1 // Copyright 2020 The Pigweed Authors 2 // 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 5 // the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 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 13 // the License. 14 #pragma once 15 16 #include <stdbool.h> 17 #include <stddef.h> 18 19 #include "pw_chrono/system_clock.h" 20 #include "pw_preprocessor/util.h" 21 22 #ifdef __cplusplus 23 24 #include "pw_sync_backend/counting_semaphore_native.h" 25 26 namespace pw::sync { 27 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. 35 // 36 // WARNING: In order to support global statically constructed CountingSemaphores 37 // the user and/or backend MUST ensure that any initialization required in your 38 // environment is done prior to the creation and/or initialization of the native 39 // synchronization primitives (e.g. kernel initialization). 40 class CountingSemaphore { 41 public: 42 using native_handle_type = backend::NativeCountingSemaphoreHandle; 43 44 CountingSemaphore(); 45 ~CountingSemaphore(); 46 CountingSemaphore(const CountingSemaphore&) = delete; 47 CountingSemaphore(CountingSemaphore&&) = delete; 48 CountingSemaphore& operator=(const CountingSemaphore&) = delete; 49 CountingSemaphore& operator=(CountingSemaphore&&) = delete; 50 51 // Atomically increments the internal counter by the value of update. 52 // Any thread(s) waiting for the counter to be greater than 0, i.e. 53 // blocked in acquire, will subsequently be unblocked. 54 // This is IRQ safe. 55 // 56 // PRECONDITIONS: 57 // update >= 0 58 // update <= max() - counter 59 void release(ptrdiff_t update = 1); 60 61 // Decrements the internal counter by 1 or blocks indefinitely until it can. 62 // This is thread safe. 63 void acquire(); 64 65 // Attempts to decrement by the internal counter by 1 without blocking. 66 // Returns true if the internal counter was decremented successfully. 67 // This is IRQ safe. 68 bool try_acquire() noexcept; 69 70 // Attempts to decrement the internal counter by 1 where, if needed, blocking 71 // for at least the specified duration. 72 // Returns true if the internal counter was decremented successfully. 73 // This is thread safe. 74 bool try_acquire_for(chrono::SystemClock::duration for_at_least); 75 76 // Attempts to decrement the internal counter by 1 where, if needed, blocking 77 // until at least the specified time point. 78 // Returns true if the internal counter was decremented successfully. 79 // This is thread safe. 80 bool try_acquire_until(chrono::SystemClock::time_point until_at_least); 81 max()82 static constexpr ptrdiff_t max() noexcept { 83 return backend::kCountingSemaphoreMaxValue; 84 } 85 86 native_handle_type native_handle(); 87 88 private: 89 // This may be a wrapper around a native type with additional members. 90 backend::NativeCountingSemaphore native_type_; 91 }; 92 93 } // namespace pw::sync 94 95 #include "pw_sync_backend/counting_semaphore_inline.h" 96 97 using pw_sync_CountingSemaphore = pw::sync::CountingSemaphore; 98 99 #else // !defined(__cplusplus) 100 101 typedef struct pw_sync_CountingSemaphore pw_sync_CountingSemaphore; 102 103 #endif // __cplusplus 104 105 PW_EXTERN_C_START 106 107 void pw_sync_CountingSemaphore_Release(pw_sync_CountingSemaphore* semaphore); 108 void pw_sync_CountingSemaphore_ReleaseNum(pw_sync_CountingSemaphore* semaphore, 109 ptrdiff_t update); 110 void pw_sync_CountingSemaphore_Acquire(pw_sync_CountingSemaphore* semaphore); 111 bool pw_sync_CountingSemaphore_TryAcquire(pw_sync_CountingSemaphore* semaphore); 112 bool pw_sync_CountingSemaphore_TryAcquireFor( 113 pw_sync_CountingSemaphore* semaphore, 114 pw_chrono_SystemClock_Duration for_at_least); 115 bool pw_sync_CountingSemaphore_TryAcquireUntil( 116 pw_sync_CountingSemaphore* semaphore, 117 pw_chrono_SystemClock_TimePoint until_at_least); 118 ptrdiff_t pw_sync_CountingSemaphore_Max(void); 119 120 PW_EXTERN_C_END 121