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 GenericBasicLockable<TimedMutex> { 75 public: timed_mutex()76 TimedMutex& timed_mutex() { return impl(); } 77 }; 78 79 } // namespace pw::sync 80 81 #include "pw_sync_backend/timed_mutex_inline.h" 82 83 using pw_sync_TimedMutex = pw::sync::TimedMutex; 84 85 #else // !defined(__cplusplus) 86 87 typedef struct pw_sync_TimedMutex pw_sync_TimedMutex; 88 89 #endif // __cplusplus 90 91 PW_EXTERN_C_START 92 93 /// Invokes the `TimedMutex::lock` member function on the given `mutex`. 94 void pw_sync_TimedMutex_Lock(pw_sync_TimedMutex* mutex) 95 PW_NO_LOCK_SAFETY_ANALYSIS; 96 97 /// Invokes the `TimedMutex::try_lock` member function on the given `mutex`. 98 bool pw_sync_TimedMutex_TryLock(pw_sync_TimedMutex* mutex) 99 PW_NO_LOCK_SAFETY_ANALYSIS; 100 101 /// Invokes the `TimedMutex::try_lock_for` member function on the given `mutex`. 102 bool pw_sync_TimedMutex_TryLockFor(pw_sync_TimedMutex* mutex, 103 pw_chrono_SystemClock_Duration timeout) 104 PW_NO_LOCK_SAFETY_ANALYSIS; 105 106 /// Invokes the `TimedMutex::try_lock_until` member function on the given 107 /// `mutex`. 108 bool pw_sync_TimedMutex_TryLockUntil(pw_sync_TimedMutex* mutex, 109 pw_chrono_SystemClock_TimePoint deadline) 110 PW_NO_LOCK_SAFETY_ANALYSIS; 111 112 /// Invokes the `TimedMutex::unlock` member function on the given `mutex`. 113 void pw_sync_TimedMutex_Unlock(pw_sync_TimedMutex* mutex) 114 PW_NO_LOCK_SAFETY_ANALYSIS; 115 116 PW_EXTERN_C_END 117