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 29 /// arbitrary 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 38 /// native synchronization primitives (e.g. kernel initialization). 39 /// 40 /// The `BinarySemaphore` is initialized to being empty or having no tokens. 41 class BinarySemaphore { 42 public: 43 using native_handle_type = backend::NativeBinarySemaphoreHandle; 44 45 BinarySemaphore(); 46 ~BinarySemaphore(); 47 BinarySemaphore(const BinarySemaphore&) = delete; 48 BinarySemaphore(BinarySemaphore&&) = delete; 49 BinarySemaphore& operator=(const BinarySemaphore&) = delete; 50 BinarySemaphore& operator=(BinarySemaphore&&) = delete; 51 52 /// Atomically increments the internal counter by 1. 53 /// Any thread(s) waiting for the counter to be greater than 0, i.e. 54 /// blocked in acquire, will subsequently be unblocked. 55 /// This is thread and IRQ safe. 56 /// 57 /// There exists an overflow risk if one releases more than max() times 58 /// between acquires because many RTOS implementations internally 59 /// increment the counter past one where it is only cleared when acquired. 60 /// 61 /// @b PRECONDITION: `1 <= max() - counter` 62 void release(); 63 64 /// Decrements the internal counter to 0 or blocks indefinitely until it can. 65 /// 66 /// This is thread safe, but not IRQ safe. 67 void acquire(); 68 69 /// Tries to decrement by the internal counter to 0 without blocking. 70 /// 71 /// @retval true if the internal counter was reset successfully. 72 /// 73 /// This is thread and IRQ safe. 74 [[nodiscard]] bool try_acquire() noexcept; 75 76 /// Tries to decrement the internal counter to 0. Blocks until the specified 77 /// timeout has elapsed or the counter was decremented to 0, whichever comes 78 /// first. 79 /// 80 /// @retval true if the internal counter was decremented successfully. 81 /// 82 /// This is thread safe, but not IRQ safe. 83 [[nodiscard]] bool try_acquire_for(chrono::SystemClock::duration timeout); 84 85 /// Tries to decrement the internal counter to 0. Blocks until the specified 86 /// deadline has been reached or the counter was decremented to 0, whichever 87 /// comes first. 88 /// 89 /// @retval true if the internal counter was decremented successfully. 90 /// 91 /// This is thread safe, but not IRQ safe. 92 [[nodiscard]] bool try_acquire_until( 93 chrono::SystemClock::time_point deadline); 94 95 /// @retval backend::kBinarySemaphoreMaxValue the internal counter's maximum 96 /// possible value. max()97 [[nodiscard]] static constexpr ptrdiff_t max() noexcept { 98 return backend::kBinarySemaphoreMaxValue; 99 } 100 101 [[nodiscard]] native_handle_type native_handle(); 102 103 private: 104 /// This may be a wrapper around a native type with additional members. 105 backend::NativeBinarySemaphore native_type_; 106 }; 107 108 } // namespace pw::sync 109 110 #include "pw_sync_backend/binary_semaphore_inline.h" 111 112 using pw_sync_BinarySemaphore = pw::sync::BinarySemaphore; 113 114 #else // !defined(__cplusplus) 115 116 typedef struct pw_sync_BinarySemaphore pw_sync_BinarySemaphore; 117 118 #endif // __cplusplus 119 120 PW_EXTERN_C_START 121 122 void pw_sync_BinarySemaphore_Release(pw_sync_BinarySemaphore* semaphore); 123 void pw_sync_BinarySemaphore_Acquire(pw_sync_BinarySemaphore* semaphore); 124 bool pw_sync_BinarySemaphore_TryAcquire(pw_sync_BinarySemaphore* semaphore); 125 bool pw_sync_BinarySemaphore_TryAcquireFor( 126 pw_sync_BinarySemaphore* semaphore, pw_chrono_SystemClock_Duration timeout); 127 bool pw_sync_BinarySemaphore_TryAcquireUntil( 128 pw_sync_BinarySemaphore* semaphore, 129 pw_chrono_SystemClock_TimePoint deadline); 130 ptrdiff_t pw_sync_BinarySemaphore_Max(void); 131 132 PW_EXTERN_C_END 133