• 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   [[nodiscard]] 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   [[nodiscard]] 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 GenericLockable<TimedMutex> {
75  public:
timed_mutex()76   TimedMutex& timed_mutex() { return impl(); }
77 
try_lock_for(chrono::SystemClock::duration timeout)78   [[nodiscard]] bool try_lock_for(chrono::SystemClock::duration timeout)
79       PW_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
80     return impl().try_lock_for(timeout);
81   }
82 
try_lock_until(chrono::SystemClock::time_point deadline)83   [[nodiscard]] bool try_lock_until(chrono::SystemClock::time_point deadline)
84       PW_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
85     return impl().try_lock_until(deadline);
86   }
87 };
88 
89 }  // namespace pw::sync
90 
91 #include "pw_sync_backend/timed_mutex_inline.h"
92 
93 using pw_sync_TimedMutex = pw::sync::TimedMutex;
94 
95 #else  // !defined(__cplusplus)
96 
97 typedef struct pw_sync_TimedMutex pw_sync_TimedMutex;
98 
99 #endif  // __cplusplus
100 
101 PW_EXTERN_C_START
102 
103 /// Invokes the `TimedMutex::lock` member function on the given `mutex`.
104 void pw_sync_TimedMutex_Lock(pw_sync_TimedMutex* mutex)
105     PW_NO_LOCK_SAFETY_ANALYSIS;
106 
107 /// Invokes the `TimedMutex::try_lock` member function on the given `mutex`.
108 bool pw_sync_TimedMutex_TryLock(pw_sync_TimedMutex* mutex)
109     PW_NO_LOCK_SAFETY_ANALYSIS;
110 
111 /// Invokes the `TimedMutex::try_lock_for` member function on the given `mutex`.
112 bool pw_sync_TimedMutex_TryLockFor(pw_sync_TimedMutex* mutex,
113                                    pw_chrono_SystemClock_Duration timeout)
114     PW_NO_LOCK_SAFETY_ANALYSIS;
115 
116 /// Invokes the `TimedMutex::try_lock_until` member function on the given
117 /// `mutex`.
118 bool pw_sync_TimedMutex_TryLockUntil(pw_sync_TimedMutex* mutex,
119                                      pw_chrono_SystemClock_TimePoint deadline)
120     PW_NO_LOCK_SAFETY_ANALYSIS;
121 
122 /// Invokes the `TimedMutex::unlock` member function on the given `mutex`.
123 void pw_sync_TimedMutex_Unlock(pw_sync_TimedMutex* mutex)
124     PW_NO_LOCK_SAFETY_ANALYSIS;
125 
126 PW_EXTERN_C_END
127