• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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