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