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 18 #include "pw_chrono/system_clock.h" 19 #include "pw_preprocessor/util.h" 20 #include "pw_sync/lock_annotations.h" 21 #include "pw_sync/mutex.h" 22 23 #ifdef __cplusplus 24 25 #include "pw_sync/virtual_basic_lockable.h" 26 27 namespace pw::sync { 28 29 /// The `TimedMutex` is a synchronization primitive that can be used to protect 30 /// shared data from being simultaneously accessed by multiple threads with 31 /// timeouts and deadlines, extending the `Mutex`. It offers exclusive, 32 /// non-recursive ownership semantics where priority inheritance is used to 33 /// solve the classic priority-inversion problem. This is thread safe, but NOT 34 /// IRQ safe. 35 /// 36 /// @rst 37 /// .. warning:: 38 /// In order to support global statically constructed TimedMutexes, the user 39 /// and/or backend MUST ensure that any initialization required in your 40 /// environment is done prior to the creation and/or initialization of the 41 /// native synchronization primitives (e.g. kernel initialization). 42 /// @endrst 43 class TimedMutex : public Mutex { 44 public: 45 TimedMutex() = default; 46 ~TimedMutex() = default; 47 TimedMutex(const TimedMutex&) = delete; 48 TimedMutex(TimedMutex&&) = delete; 49 TimedMutex& operator=(const TimedMutex&) = delete; 50 TimedMutex& operator=(TimedMutex&&) = delete; 51 52 /// Tries to lock the mutex. Blocks until specified the timeout has elapsed or 53 /// the lock is acquired, whichever comes first. 54 /// Returns true if the mutex was successfully acquired. 55 /// 56 /// @b PRECONDITION: 57 /// The lock isn't already held by this thread. Recursive locking is 58 /// undefined behavior. 59 [[nodiscard]] bool try_lock_for(chrono::SystemClock::duration timeout) 60 PW_EXCLUSIVE_TRYLOCK_FUNCTION(true); 61 62 /// Tries to lock the mutex. Blocks until specified deadline has been reached 63 /// or the lock is acquired, whichever comes first. 64 /// Returns true if the mutex was successfully acquired. 65 /// 66 /// @b PRECONDITION: 67 /// The lock isn't already held by this thread. Recursive locking is 68 /// undefined behavior. 69 [[nodiscard]] bool try_lock_until(chrono::SystemClock::time_point deadline) 70 PW_EXCLUSIVE_TRYLOCK_FUNCTION(true); 71 }; 72 73 class PW_LOCKABLE("pw::sync::VirtualTimedMutex") VirtualTimedMutex final 74 : public GenericLockable<TimedMutex> { 75 public: timed_mutex()76 TimedMutex& timed_mutex() { return impl(); } 77 try_lock_for(chrono::SystemClock::duration timeout)78 [[nodiscard]] bool try_lock_for(chrono::SystemClock::duration timeout) 79 PW_EXCLUSIVE_TRYLOCK_FUNCTION(true) { 80 return impl().try_lock_for(timeout); 81 } 82 try_lock_until(chrono::SystemClock::time_point deadline)83 [[nodiscard]] bool try_lock_until(chrono::SystemClock::time_point deadline) 84 PW_EXCLUSIVE_TRYLOCK_FUNCTION(true) { 85 return impl().try_lock_until(deadline); 86 } 87 }; 88 89 } // namespace pw::sync 90 91 #include "pw_sync_backend/timed_mutex_inline.h" 92 93 using pw_sync_TimedMutex = pw::sync::TimedMutex; 94 95 #else // !defined(__cplusplus) 96 97 typedef struct pw_sync_TimedMutex pw_sync_TimedMutex; 98 99 #endif // __cplusplus 100 101 PW_EXTERN_C_START 102 103 /// Invokes the `TimedMutex::lock` member function on the given `mutex`. 104 void pw_sync_TimedMutex_Lock(pw_sync_TimedMutex* mutex) 105 PW_NO_LOCK_SAFETY_ANALYSIS; 106 107 /// Invokes the `TimedMutex::try_lock` member function on the given `mutex`. 108 bool pw_sync_TimedMutex_TryLock(pw_sync_TimedMutex* mutex) 109 PW_NO_LOCK_SAFETY_ANALYSIS; 110 111 /// Invokes the `TimedMutex::try_lock_for` member function on the given `mutex`. 112 bool pw_sync_TimedMutex_TryLockFor(pw_sync_TimedMutex* mutex, 113 pw_chrono_SystemClock_Duration timeout) 114 PW_NO_LOCK_SAFETY_ANALYSIS; 115 116 /// Invokes the `TimedMutex::try_lock_until` member function on the given 117 /// `mutex`. 118 bool pw_sync_TimedMutex_TryLockUntil(pw_sync_TimedMutex* mutex, 119 pw_chrono_SystemClock_TimePoint deadline) 120 PW_NO_LOCK_SAFETY_ANALYSIS; 121 122 /// Invokes the `TimedMutex::unlock` member function on the given `mutex`. 123 void pw_sync_TimedMutex_Unlock(pw_sync_TimedMutex* mutex) 124 PW_NO_LOCK_SAFETY_ANALYSIS; 125 126 PW_EXTERN_C_END 127