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_preprocessor/util.h" 19 #include "pw_sync/lock_annotations.h" 20 21 #ifdef __cplusplus 22 23 #include "pw_sync/virtual_basic_lockable.h" 24 #include "pw_sync_backend/mutex_native.h" 25 26 namespace pw::sync { 27 28 /// The `Mutex` is a synchronization primitive that can be used to protect 29 /// shared data from being simultaneously accessed by multiple threads. It 30 /// offers exclusive, non-recursive ownership semantics where priority 31 /// inheritance is used to solve the classic priority-inversion problem. This 32 /// is thread safe, but NOT IRQ safe. 33 /// 34 /// @rst 35 /// .. warning:: 36 /// 37 /// In order to support global statically constructed Mutexes, the user 38 /// and/or backend MUST ensure that any initialization required in your 39 /// environment is done prior to the creation and/or initialization of the 40 /// native synchronization primitives (e.g. kernel initialization). 41 /// @endrst 42 class PW_LOCKABLE("pw::sync::Mutex") Mutex { 43 public: 44 using native_handle_type = backend::NativeMutexHandle; 45 46 Mutex(); 47 ~Mutex(); 48 Mutex(const Mutex&) = delete; 49 Mutex(Mutex&&) = delete; 50 Mutex& operator=(const Mutex&) = delete; 51 Mutex& operator=(Mutex&&) = delete; 52 53 /// Locks the mutex, blocking indefinitely. Failures are fatal. 54 /// 55 /// @b PRECONDITION: 56 /// The lock isn't already held by this thread. Recursive locking is 57 /// undefined behavior. 58 void lock() PW_EXCLUSIVE_LOCK_FUNCTION(); 59 60 /// Attempts to lock the mutex in a non-blocking manner. 61 /// Returns true if the mutex was successfully acquired. 62 /// 63 /// @b PRECONDITION: 64 /// The lock isn't already held by this thread. Recursive locking is 65 /// undefined behavior. 66 bool try_lock() PW_EXCLUSIVE_TRYLOCK_FUNCTION(true); 67 68 /// Unlocks the mutex. Failures are fatal. 69 /// 70 /// @b PRECONDITION: 71 /// The mutex is held by this thread. 72 void unlock() PW_UNLOCK_FUNCTION(); 73 74 native_handle_type native_handle(); 75 76 protected: 77 /// Expose the NativeMutex directly to derived classes (TimedMutex) in case 78 /// implementations use different types for backend::NativeMutex and 79 /// native_handle(). native_type()80 backend::NativeMutex& native_type() { return native_type_; } native_type()81 const backend::NativeMutex& native_type() const { return native_type_; } 82 83 private: 84 /// This may be a wrapper around a native type with additional members. 85 backend::NativeMutex native_type_; 86 }; 87 88 class PW_LOCKABLE("pw::sync::VirtualMutex") VirtualMutex final 89 : public VirtualBasicLockable { 90 public: 91 VirtualMutex() = default; 92 93 VirtualMutex(const VirtualMutex&) = delete; 94 VirtualMutex(VirtualMutex&&) = delete; 95 VirtualMutex& operator=(const VirtualMutex&) = delete; 96 VirtualMutex& operator=(VirtualMutex&&) = delete; 97 mutex()98 Mutex& mutex() { return mutex_; } 99 100 private: DoLockOperation(Operation operation)101 void DoLockOperation(Operation operation) override 102 PW_NO_LOCK_SAFETY_ANALYSIS { 103 switch (operation) { 104 case Operation::kLock: 105 return mutex_.lock(); 106 107 case Operation::kUnlock: 108 default: 109 return mutex_.unlock(); 110 } 111 } 112 113 Mutex mutex_; 114 }; 115 116 } // namespace pw::sync 117 118 #include "pw_sync_backend/mutex_inline.h" 119 120 using pw_sync_Mutex = pw::sync::Mutex; 121 122 #else // !defined(__cplusplus) 123 124 typedef struct pw_sync_Mutex pw_sync_Mutex; 125 126 #endif // __cplusplus 127 128 PW_EXTERN_C_START 129 130 /// Invokes the `Mutex::lock` member function on the given `mutex`. 131 void pw_sync_Mutex_Lock(pw_sync_Mutex* mutex) PW_NO_LOCK_SAFETY_ANALYSIS; 132 133 /// Invokes the `Mutex::try_lock` member function on the given `mutex`. 134 bool pw_sync_Mutex_TryLock(pw_sync_Mutex* mutex) PW_NO_LOCK_SAFETY_ANALYSIS; 135 136 /// Invokes the `Mutex::unlock` member function on the given `mutex`. 137 void pw_sync_Mutex_Unlock(pw_sync_Mutex* mutex) PW_NO_LOCK_SAFETY_ANALYSIS; 138 139 PW_EXTERN_C_END 140