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