• 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_chrono/system_clock.h"
19 #include "pw_preprocessor/util.h"
20 #include "pw_sync/lock_annotations.h"
21 #include "pw_sync/mutex.h"
22 
23 #ifdef __cplusplus
24 
25 #include "pw_sync/virtual_basic_lockable.h"
26 
27 namespace pw::sync {
28 
29 /// The `TimedMutex` is a synchronization primitive that can be used to protect
30 /// shared data from being simultaneously accessed by multiple threads with
31 /// timeouts and deadlines, extending the `Mutex`. It offers exclusive,
32 /// non-recursive ownership semantics where priority inheritance is used to
33 /// solve the classic priority-inversion problem. This is thread safe, but NOT
34 /// IRQ safe.
35 ///
36 /// @rst
37 /// .. warning::
38 ///    In order to support global statically constructed TimedMutexes, the user
39 ///    and/or backend MUST ensure that any initialization required in your
40 ///    environment is done prior to the creation and/or initialization of the
41 ///    native synchronization primitives (e.g. kernel initialization).
42 /// @endrst
43 class TimedMutex : public Mutex {
44  public:
45   TimedMutex() = default;
46   ~TimedMutex() = default;
47   TimedMutex(const TimedMutex&) = delete;
48   TimedMutex(TimedMutex&&) = delete;
49   TimedMutex& operator=(const TimedMutex&) = delete;
50   TimedMutex& operator=(TimedMutex&&) = delete;
51 
52   /// Tries to lock the mutex. Blocks until specified the timeout has elapsed or
53   /// the lock is acquired, whichever comes first.
54   /// Returns true if the mutex was successfully acquired.
55   ///
56   /// @b PRECONDITION:
57   ///   The lock isn't already held by this thread. Recursive locking is
58   ///   undefined behavior.
59   bool try_lock_for(chrono::SystemClock::duration timeout)
60       PW_EXCLUSIVE_TRYLOCK_FUNCTION(true);
61 
62   /// Tries to lock the mutex. Blocks until specified deadline has been reached
63   /// or the lock is acquired, whichever comes first.
64   /// Returns true if the mutex was successfully acquired.
65   ///
66   /// @b PRECONDITION:
67   ///   The lock isn't already held by this thread. Recursive locking is
68   ///   undefined behavior.
69   bool try_lock_until(chrono::SystemClock::time_point deadline)
70       PW_EXCLUSIVE_TRYLOCK_FUNCTION(true);
71 };
72 
73 class PW_LOCKABLE("pw::sync::VirtualTimedMutex") VirtualTimedMutex final
74     : public VirtualBasicLockable {
75  public:
76   VirtualTimedMutex() = default;
77 
78   VirtualTimedMutex(const VirtualTimedMutex&) = delete;
79   VirtualTimedMutex(VirtualTimedMutex&&) = delete;
80   VirtualTimedMutex& operator=(const VirtualTimedMutex&) = delete;
81   VirtualTimedMutex& operator=(VirtualTimedMutex&&) = delete;
82 
timed_mutex()83   TimedMutex& timed_mutex() { return timed_mutex_; }
84 
85  private:
DoLockOperation(Operation operation)86   void DoLockOperation(Operation operation) override
87       PW_NO_LOCK_SAFETY_ANALYSIS {
88     switch (operation) {
89       case Operation::kLock:
90         return timed_mutex_.lock();
91 
92       case Operation::kUnlock:
93       default:
94         return timed_mutex_.unlock();
95     }
96   }
97 
98   TimedMutex timed_mutex_;
99 };
100 
101 }  // namespace pw::sync
102 
103 #include "pw_sync_backend/timed_mutex_inline.h"
104 
105 using pw_sync_TimedMutex = pw::sync::TimedMutex;
106 
107 #else  // !defined(__cplusplus)
108 
109 typedef struct pw_sync_TimedMutex pw_sync_TimedMutex;
110 
111 #endif  // __cplusplus
112 
113 PW_EXTERN_C_START
114 
115 /// Invokes the `TimedMutex::lock` member function on the given `mutex`.
116 void pw_sync_TimedMutex_Lock(pw_sync_TimedMutex* mutex)
117     PW_NO_LOCK_SAFETY_ANALYSIS;
118 
119 /// Invokes the `TimedMutex::try_lock` member function on the given `mutex`.
120 bool pw_sync_TimedMutex_TryLock(pw_sync_TimedMutex* mutex)
121     PW_NO_LOCK_SAFETY_ANALYSIS;
122 
123 /// Invokes the `TimedMutex::try_lock_for` member function on the given `mutex`.
124 bool pw_sync_TimedMutex_TryLockFor(pw_sync_TimedMutex* mutex,
125                                    pw_chrono_SystemClock_Duration timeout)
126     PW_NO_LOCK_SAFETY_ANALYSIS;
127 
128 /// Invokes the `TimedMutex::try_lock_until` member function on the given
129 /// `mutex`.
130 bool pw_sync_TimedMutex_TryLockUntil(pw_sync_TimedMutex* mutex,
131                                      pw_chrono_SystemClock_TimePoint deadline)
132     PW_NO_LOCK_SAFETY_ANALYSIS;
133 
134 /// Invokes the `TimedMutex::unlock` member function on the given `mutex`.
135 void pw_sync_TimedMutex_Unlock(pw_sync_TimedMutex* mutex)
136     PW_NO_LOCK_SAFETY_ANALYSIS;
137 
138 PW_EXTERN_C_END
139