xref: /aosp_15_r20/external/pigweed/pw_sync/public/pw_sync/recursive_mutex.h (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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