1 // Copyright 2022 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_backend/recursive_mutex_native.h" 24 25 namespace pw::sync { 26 27 // WARNING: Recursive mutexes are problematic and their use is discouraged. DO 28 // NOT use this class without consulting with the Pigweed team first. 29 // 30 // RecursiveMutex is the same as Mutex, except that the thread holding the mutex 31 // may safely attempt to lock the mutex again. 32 // This is thread safe, but NOT IRQ safe. 33 // 34 // Note that RecursiveMutex's lock safety annotations the same as Mutex's, so 35 // lock safety analysis will not allow for recursive locking. Many cases where 36 // recursive locking is needed cannot be checked with lock safety analysis 37 // anyway (e.g. callbacks). For cases where lock safety analysis complains 38 // about safe usage, disable it locally. 39 // 40 // WARNING: In order to support global statically constructed RecusiveMutexes, 41 // the user and/or backend MUST ensure that any initialization required in your 42 // environment is done prior to the creation and/or initialization of the native 43 // synchronization primitives (e.g. kernel initialization). 44 class PW_LOCKABLE("pw::sync::RecursiveMutex") RecursiveMutex { 45 public: 46 using native_handle_type = backend::NativeRecursiveMutexHandle; 47 48 RecursiveMutex(); 49 ~RecursiveMutex(); 50 51 RecursiveMutex(const RecursiveMutex&) = delete; 52 RecursiveMutex(RecursiveMutex&&) = delete; 53 54 RecursiveMutex& operator=(const RecursiveMutex&) = delete; 55 RecursiveMutex& operator=(RecursiveMutex&&) = delete; 56 57 // Locks the mutex, blocking indefinitely. Failures are fatal. 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 [[nodiscard]] bool try_lock() PW_EXCLUSIVE_TRYLOCK_FUNCTION(true); 63 64 // Unlocks the mutex. Failures are fatal. 65 void unlock() PW_UNLOCK_FUNCTION(); 66 67 [[nodiscard]] native_handle_type native_handle(); 68 69 private: 70 // This may be a wrapper around a native type with additional members. 71 backend::NativeRecursiveMutex native_type_; 72 }; 73 74 } // namespace pw::sync 75 76 #include "pw_sync_backend/recursive_mutex_inline.h" 77 78 using pw_sync_RecursiveMutex = pw::sync::RecursiveMutex; 79 80 #else // !defined(__cplusplus) 81 82 typedef struct pw_sync_RecursiveMutex pw_sync_RecursiveMutex; 83 84 #endif // __cplusplus 85 86 PW_EXTERN_C_START 87 88 void pw_sync_RecursiveMutex_Lock(pw_sync_RecursiveMutex* mutex) 89 PW_NO_LOCK_SAFETY_ANALYSIS; 90 bool pw_sync_RecursiveMutex_TryLock(pw_sync_RecursiveMutex* mutex) 91 PW_NO_LOCK_SAFETY_ANALYSIS; 92 void pw_sync_RecursiveMutex_Unlock(pw_sync_RecursiveMutex* mutex) 93 PW_NO_LOCK_SAFETY_ANALYSIS; 94 95 PW_EXTERN_C_END 96