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 up to max_count. 51 // Any thread(s) waiting for the counter to be greater than 0, 52 // such as due to being blocked in acquire, will subsequently be unblocked. 53 // This is IRQ safe. 54 // 55 // PRECONDITIONS: 56 // 1 <= max() - counter 57 void release(); 58 59 // Decrements the internal counter to 0 or blocks indefinitely until it can. 60 // This is thread safe. 61 62 // update <= max() - counter 63 void acquire(); 64 65 // Attempts to decrement by the internal counter to 0 without blocking. 66 // Returns true if the internal counter was reset successfully. 67 // This is IRQ safe. 68 bool try_acquire() noexcept; 69 70 // Attempts to decrement the internal counter to 0 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 to 0 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::kBinarySemaphoreMaxValue; 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::NativeBinarySemaphore native_type_; 91 }; 92 93 } // namespace pw::sync 94 95 #include "pw_sync_backend/binary_semaphore_inline.h" 96 97 using pw_sync_BinarySemaphore = pw::sync::BinarySemaphore; 98 99 #else // !defined(__cplusplus) 100 101 typedef struct pw_sync_BinarySemaphore pw_sync_BinarySemaphore; 102 103 #endif // __cplusplus 104 105 PW_EXTERN_C_START 106 107 void pw_sync_BinarySemaphore_Release(pw_sync_BinarySemaphore* semaphore); 108 void pw_sync_BinarySemaphore_Acquire(pw_sync_BinarySemaphore* semaphore); 109 bool pw_sync_BinarySemaphore_TryAcquire(pw_sync_BinarySemaphore* semaphore); 110 bool pw_sync_BinarySemaphore_TryAcquireFor( 111 pw_sync_BinarySemaphore* semaphore, 112 pw_chrono_SystemClock_Duration for_at_least); 113 bool pw_sync_BinarySemaphore_TryAcquireUntil( 114 pw_sync_BinarySemaphore* semaphore, 115 pw_chrono_SystemClock_TimePoint until_at_least); 116 ptrdiff_t pw_sync_BinarySemaphore_Max(void); 117 118 PW_EXTERN_C_END 119