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/binary_semaphore_native.h" 25 26 namespace pw::sync { 27 28 // BinarySemaphore is a specialization of CountingSemaphore with an arbitrary 29 // token limit of 1. Note that that max() is >= 1, meaning it may be 30 // released up to max() times but only acquired once for those N releases. 31 // Implementations of BinarySemaphore are typically more efficient than the 32 // default implementation of CountingSemaphore. The entire API is thread safe 33 // but only a subset is IRQ safe. 34 // 35 // WARNING: In order to support global statically constructed BinarySemaphores, 36 // the user and/or backend MUST ensure that any initialization required in your 37 // environment is done prior to the creation and/or initialization of the native 38 // synchronization primitives (e.g. kernel initialization). 39 class BinarySemaphore { 40 public: 41 using native_handle_type = backend::NativeBinarySemaphoreHandle; 42 43 BinarySemaphore(); 44 ~BinarySemaphore(); 45 BinarySemaphore(const BinarySemaphore&) = delete; 46 BinarySemaphore(BinarySemaphore&&) = delete; 47 BinarySemaphore& operator=(const BinarySemaphore&) = delete; 48 BinarySemaphore& operator=(BinarySemaphore&&) = delete; 49 50 // Atomically increments the internal counter by 1. 51 // Any thread(s) waiting for the counter to be greater than 0, i.e. 52 // blocked in acquire, will subsequently be unblocked. 53 // This is thread and IRQ safe. 54 // 55 // There exists an overflow risk if one releases more than max() times 56 // between acquires because many RTOS implementations internally 57 // increment the counter past one where it is only cleared when acquired. 58 // 59 // Precondition: 1 <= max() - counter 60 void release(); 61 62 // Decrements the internal counter to 0 or blocks indefinitely until it can. 63 // This is thread safe, but not IRQ safe. 64 void acquire(); 65 66 // Tries to decrement by the internal counter to 0 without blocking. 67 // Returns true if the internal counter was reset successfully. 68 // This is thread and IRQ safe. 69 bool try_acquire() noexcept; 70 71 // Tries to decrement the internal counter to 0. Blocks until the specified 72 // timeout has elapsed or the counter was decremented to 0, whichever comes 73 // first. 74 // Returns true if the internal counter was decremented successfully. 75 // This is thread safe, but not IRQ safe. 76 bool try_acquire_for(chrono::SystemClock::duration timeout); 77 78 // Tries to decrement the internal counter to 0. Blocks until the specified 79 // deadline has been reached or the counter was decremented to 0, whichever 80 // comes first. 81 // Returns true if the internal counter was decremented successfully. 82 // This is thread safe, but not IRQ safe. 83 bool try_acquire_until(chrono::SystemClock::time_point deadline); 84 max()85 static constexpr ptrdiff_t max() noexcept { 86 return backend::kBinarySemaphoreMaxValue; 87 } 88 89 native_handle_type native_handle(); 90 91 private: 92 // This may be a wrapper around a native type with additional members. 93 backend::NativeBinarySemaphore native_type_; 94 }; 95 96 } // namespace pw::sync 97 98 #include "pw_sync_backend/binary_semaphore_inline.h" 99 100 using pw_sync_BinarySemaphore = pw::sync::BinarySemaphore; 101 102 #else // !defined(__cplusplus) 103 104 typedef struct pw_sync_BinarySemaphore pw_sync_BinarySemaphore; 105 106 #endif // __cplusplus 107 108 PW_EXTERN_C_START 109 110 void pw_sync_BinarySemaphore_Release(pw_sync_BinarySemaphore* semaphore); 111 void pw_sync_BinarySemaphore_Acquire(pw_sync_BinarySemaphore* semaphore); 112 bool pw_sync_BinarySemaphore_TryAcquire(pw_sync_BinarySemaphore* semaphore); 113 bool pw_sync_BinarySemaphore_TryAcquireFor( 114 pw_sync_BinarySemaphore* semaphore, pw_chrono_SystemClock_Duration timeout); 115 bool pw_sync_BinarySemaphore_TryAcquireUntil( 116 pw_sync_BinarySemaphore* semaphore, 117 pw_chrono_SystemClock_TimePoint deadline); 118 ptrdiff_t pw_sync_BinarySemaphore_Max(void); 119 120 PW_EXTERN_C_END 121