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_backend/mutex_native.h"
24 
25 namespace pw::sync {
26 
27 // The Mutex is a synchronization primitive that can be used to protect
28 // shared data from being simultaneously accessed by multiple threads.
29 // It offers exclusive, non-recursive ownership semantics where priority
30 // inheritance is used to solve the classic priority-inversion problem.
31 // This is thread safe, but NOT IRQ safe.
32 //
33 // WARNING: In order to support global statically constructed Mutexes, the user
34 // and/or backend MUST ensure that any initialization required in your
35 // environment is done prior to the creation and/or initialization of the native
36 // synchronization primitives (e.g. kernel initialization).
37 class PW_LOCKABLE("pw::sync::Mutex") Mutex {
38  public:
39   using native_handle_type = backend::NativeMutexHandle;
40 
41   Mutex();
42   ~Mutex();
43   Mutex(const Mutex&) = delete;
44   Mutex(Mutex&&) = delete;
45   Mutex& operator=(const Mutex&) = delete;
46   Mutex& operator=(Mutex&&) = delete;
47 
48   // Locks the mutex, blocking indefinitely. Failures are fatal.
49   //
50   // PRECONDITION:
51   //   The lock isn't already held by this thread. Recursive locking is
52   //   undefined behavior.
53   void lock() PW_EXCLUSIVE_LOCK_FUNCTION();
54 
55   // Attempts to lock the mutex in a non-blocking manner.
56   // Returns true if the mutex was successfully acquired.
57   //
58   // PRECONDITION:
59   //   The lock isn't already held by this thread. Recursive locking is
60   //   undefined behavior.
61   bool try_lock() PW_EXCLUSIVE_TRYLOCK_FUNCTION(true);
62 
63   // Unlocks the mutex. Failures are fatal.
64   //
65   // PRECONDITION:
66   //   The mutex is held by this thread.
67   void unlock() PW_UNLOCK_FUNCTION();
68 
69   native_handle_type native_handle();
70 
71  private:
72   // This may be a wrapper around a native type with additional members.
73   backend::NativeMutex native_type_;
74 };
75 
76 }  // namespace pw::sync
77 
78 #include "pw_sync_backend/mutex_inline.h"
79 
80 using pw_sync_Mutex = pw::sync::Mutex;
81 
82 #else  // !defined(__cplusplus)
83 
84 typedef struct pw_sync_Mutex pw_sync_Mutex;
85 
86 #endif  // __cplusplus
87 
88 PW_EXTERN_C_START
89 
90 void pw_sync_Mutex_Lock(pw_sync_Mutex* mutex) PW_NO_LOCK_SAFETY_ANALYSIS;
91 bool pw_sync_Mutex_TryLock(pw_sync_Mutex* mutex) PW_NO_LOCK_SAFETY_ANALYSIS;
92 void pw_sync_Mutex_Unlock(pw_sync_Mutex* mutex) PW_NO_LOCK_SAFETY_ANALYSIS;
93 
94 PW_EXTERN_C_END
95