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. blocked 53 // in acquire, will subsequently be unblocked. 54 // This is IRQ safe. 55 // 56 // Precondition: update >= 0 57 // Precondition: update <= max() - counter 58 void release(ptrdiff_t update = 1); 59 60 // Decrements the internal counter by 1 or blocks indefinitely until it can. 61 // This is thread safe, but not IRQ safe. 62 void acquire(); 63 64 // Tries to decrement by the internal counter by 1 without blocking. 65 // Returns true if the internal counter was decremented successfully. 66 // This is IRQ safe. 67 bool try_acquire() noexcept; 68 69 // Tries to decrement the internal counter by 1. Blocks until the specified 70 // timeout has elapsed or the counter was decremented by 1, whichever comes 71 // first. 72 // Returns true if the internal counter was decremented successfully. 73 // This is thread safe, but not IRQ safe. 74 bool try_acquire_for(chrono::SystemClock::duration timeout); 75 76 // Tries to decrement the internal counter by 1. Blocks until the specified 77 // deadline has been reached or the counter was decremented by 1, whichever 78 // comes first. 79 // Returns true if the internal counter was decremented successfully. 80 // This is thread safe, but not IRQ safe. 81 bool try_acquire_until(chrono::SystemClock::time_point deadline); 82 max()83 static constexpr ptrdiff_t max() noexcept { 84 return backend::kCountingSemaphoreMaxValue; 85 } 86 87 native_handle_type native_handle(); 88 89 private: 90 // This may be a wrapper around a native type with additional members. 91 backend::NativeCountingSemaphore native_type_; 92 }; 93 94 } // namespace pw::sync 95 96 #include "pw_sync_backend/counting_semaphore_inline.h" 97 98 using pw_sync_CountingSemaphore = pw::sync::CountingSemaphore; 99 100 #else // !defined(__cplusplus) 101 102 typedef struct pw_sync_CountingSemaphore pw_sync_CountingSemaphore; 103 104 #endif // __cplusplus 105 106 PW_EXTERN_C_START 107 108 void pw_sync_CountingSemaphore_Release(pw_sync_CountingSemaphore* semaphore); 109 void pw_sync_CountingSemaphore_ReleaseNum(pw_sync_CountingSemaphore* semaphore, 110 ptrdiff_t update); 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 timeout); 116 bool pw_sync_CountingSemaphore_TryAcquireUntil( 117 pw_sync_CountingSemaphore* semaphore, 118 pw_chrono_SystemClock_TimePoint deadline); 119 ptrdiff_t pw_sync_CountingSemaphore_Max(void); 120 121 PW_EXTERN_C_END 122