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