1 /*
2 * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #ifndef _PICO_MUTEX_H
8 #define _PICO_MUTEX_H
9
10 #include "pico/lock_core.h"
11
12 #ifdef __cplusplus
13 extern "C" {
14 #endif
15
16 /** \file mutex.h
17 * \defgroup mutex mutex
18 * \ingroup pico_sync
19 * \brief Mutex API for non IRQ mutual exclusion between cores
20 *
21 * Mutexes are application level locks usually used protecting data structures that might be used by
22 * multiple threads of execution. Unlike critical sections, the mutex protected code is not necessarily
23 * required/expected to complete quickly, as no other system wide locks are held on account of an acquired mutex.
24 *
25 * When acquired, the mutex has an owner (see \ref lock_get_caller_owner_id) which with the plain SDK is just
26 * the acquiring core, but in an RTOS it could be a task, or an IRQ handler context.
27 *
28 * Two variants of mutex are provided; \ref mutex_t (and associated mutex_ functions) is a regular mutex that cannot
29 * be acquired recursively by the same owner (a deadlock will occur if you try). \ref recursive_mutex_t
30 * (and associated recursive_mutex_ functions) is a recursive mutex that can be recursively obtained by
31 * the same caller, at the expense of some more overhead when acquiring and releasing.
32 *
33 * It is generally a bad idea to call blocking mutex_ or recursive_mutex_ functions from within an IRQ handler.
34 * It is valid to call \ref mutex_try_enter or \ref recursive_mutex_try_enter from within an IRQ handler, if the operation
35 * that would be conducted under lock can be skipped if the mutex is locked (at least by the same owner).
36 *
37 * NOTE: For backwards compatibility with version 1.2.0 of the SDK, if the define
38 * PICO_MUTEX_ENABLE_SDK120_COMPATIBILITY is set to 1, then the the regular mutex_ functions
39 * may also be used for recursive mutexes. This flag will be removed in a future version of the SDK.
40 *
41 * See \ref critical_section.h for protecting access between multiple cores AND IRQ handlers
42 */
43
44 /*! \brief recursive mutex instance
45 * \ingroup mutex
46 */
47 typedef struct {
48 lock_core_t core;
49 lock_owner_id_t owner; //! owner id LOCK_INVALID_OWNER_ID for unowned
50 uint8_t enter_count; //! ownership count
51 #if PICO_MUTEX_ENABLE_SDK120_COMPATIBILITY
52 bool recursive;
53 #endif
54 } recursive_mutex_t;
55
56 /*! \brief regular (non recursive) mutex instance
57 * \ingroup mutex
58 */
59 #if !PICO_MUTEX_ENABLE_SDK120_COMPATIBILITY
60 typedef struct mutex {
61 lock_core_t core;
62 lock_owner_id_t owner; //! owner id LOCK_INVALID_OWNER_ID for unowned
63 } mutex_t;
64 #else
65 typedef recursive_mutex_t mutex_t; // they are one and the same when backwards compatible with SDK1.2.0
66 #endif
67
68 /*! \brief Initialise a mutex structure
69 * \ingroup mutex
70 *
71 * \param mtx Pointer to mutex structure
72 */
73 void mutex_init(mutex_t *mtx);
74
75 /*! \brief Initialise a recursive mutex structure
76 * \ingroup mutex
77 *
78 * A recursive mutex may be entered in a nested fashion by the same owner
79 *
80 * \param mtx Pointer to recursive mutex structure
81 */
82 void recursive_mutex_init(recursive_mutex_t *mtx);
83
84 /*! \brief Take ownership of a mutex
85 * \ingroup mutex
86 *
87 * This function will block until the caller can be granted ownership of the mutex.
88 * On return the caller owns the mutex
89 *
90 * \param mtx Pointer to mutex structure
91 */
92 void mutex_enter_blocking(mutex_t *mtx);
93
94 /*! \brief Take ownership of a recursive mutex
95 * \ingroup mutex
96 *
97 * This function will block until the caller can be granted ownership of the mutex.
98 * On return the caller owns the mutex
99 *
100 * \param mtx Pointer to recursive mutex structure
101 */
102 void recursive_mutex_enter_blocking(recursive_mutex_t *mtx);
103
104 /*! \brief Attempt to take ownership of a mutex
105 * \ingroup mutex
106 *
107 * If the mutex wasn't owned, this will claim the mutex for the caller and return true.
108 * Otherwise (if the mutex was already owned) this will return false and the
109 * caller will NOT own the mutex.
110 *
111 * \param mtx Pointer to mutex structure
112 * \param owner_out If mutex was already owned, and this pointer is non-zero, it will be filled in with the owner id of the current owner of the mutex
113 * \return true if mutex now owned, false otherwise
114 */
115 bool mutex_try_enter(mutex_t *mtx, uint32_t *owner_out);
116
117 /*! \brief Attempt to take ownership of a mutex until the specified time
118 * \ingroup mutex
119 *
120 * If the mutex wasn't owned, this method will immediately claim the mutex for the caller and return true.
121 * If the mutex is owned by the caller, this method will immediately return false,
122 * If the mutex is owned by someone else, this method will try to claim it until the specified time, returning
123 * true if it succeeds, or false on timeout
124 *
125 * \param mtx Pointer to mutex structure
126 * \param until The time after which to return if the caller cannot be granted ownership of the mutex
127 * \return true if mutex now owned, false otherwise
128 */
129 bool mutex_try_enter_block_until(mutex_t *mtx, absolute_time_t until);
130
131 /*! \brief Attempt to take ownership of a recursive mutex
132 * \ingroup mutex
133 *
134 * If the mutex wasn't owned or was owned by the caller, this will claim the mutex and return true.
135 * Otherwise (if the mutex was already owned by another owner) this will return false and the
136 * caller will NOT own the mutex.
137 *
138 * \param mtx Pointer to recursive mutex structure
139 * \param owner_out If mutex was already owned by another owner, and this pointer is non-zero,
140 * it will be filled in with the owner id of the current owner of the mutex
141 * \return true if the recursive mutex (now) owned, false otherwise
142 */
143 bool recursive_mutex_try_enter(recursive_mutex_t *mtx, uint32_t *owner_out);
144
145 /*! \brief Wait for mutex with timeout
146 * \ingroup mutex
147 *
148 * Wait for up to the specific time to take ownership of the mutex. If the caller
149 * can be granted ownership of the mutex before the timeout expires, then true will be returned
150 * and the caller will own the mutex, otherwise false will be returned and the caller will NOT own the mutex.
151 *
152 * \param mtx Pointer to mutex structure
153 * \param timeout_ms The timeout in milliseconds.
154 * \return true if mutex now owned, false if timeout occurred before ownership could be granted
155 */
156 bool mutex_enter_timeout_ms(mutex_t *mtx, uint32_t timeout_ms);
157
158 /*! \brief Wait for recursive mutex with timeout
159 * \ingroup mutex
160 *
161 * Wait for up to the specific time to take ownership of the recursive mutex. If the caller
162 * already has ownership of the mutex or can be granted ownership of the mutex before the timeout expires,
163 * then true will be returned and the caller will own the mutex, otherwise false will be returned and the caller
164 * will NOT own the mutex.
165 *
166 * \param mtx Pointer to recursive mutex structure
167 * \param timeout_ms The timeout in milliseconds.
168 * \return true if the recursive mutex (now) owned, false if timeout occurred before ownership could be granted
169 */
170 bool recursive_mutex_enter_timeout_ms(recursive_mutex_t *mtx, uint32_t timeout_ms);
171
172 /*! \brief Wait for mutex with timeout
173 * \ingroup mutex
174 *
175 * Wait for up to the specific time to take ownership of the mutex. If the caller
176 * can be granted ownership of the mutex before the timeout expires, then true will be returned
177 * and the caller will own the mutex, otherwise false will be returned and the caller
178 * will NOT own the mutex.
179 *
180 * \param mtx Pointer to mutex structure
181 * \param timeout_us The timeout in microseconds.
182 * \return true if mutex now owned, false if timeout occurred before ownership could be granted
183 */
184 bool mutex_enter_timeout_us(mutex_t *mtx, uint32_t timeout_us);
185
186 /*! \brief Wait for recursive mutex with timeout
187 * \ingroup mutex
188 *
189 * Wait for up to the specific time to take ownership of the recursive mutex. If the caller
190 * already has ownership of the mutex or can be granted ownership of the mutex before the timeout expires,
191 * then true will be returned and the caller will own the mutex, otherwise false will be returned and the caller
192 * will NOT own the mutex.
193 *
194 * \param mtx Pointer to mutex structure
195 * \param timeout_us The timeout in microseconds.
196 * \return true if the recursive mutex (now) owned, false if timeout occurred before ownership could be granted
197 */
198 bool recursive_mutex_enter_timeout_us(recursive_mutex_t *mtx, uint32_t timeout_us);
199
200 /*! \brief Wait for mutex until a specific time
201 * \ingroup mutex
202 *
203 * Wait until the specific time to take ownership of the mutex. If the caller
204 * can be granted ownership of the mutex before the timeout expires, then true will be returned
205 * and the caller will own the mutex, otherwise false will be returned and the caller
206 * will NOT own the mutex.
207 *
208 * \param mtx Pointer to mutex structure
209 * \param until The time after which to return if the caller cannot be granted ownership of the mutex
210 * \return true if mutex now owned, false if timeout occurred before ownership could be granted
211 */
212 bool mutex_enter_block_until(mutex_t *mtx, absolute_time_t until);
213
214 /*! \brief Wait for mutex until a specific time
215 * \ingroup mutex
216 *
217 * Wait until the specific time to take ownership of the mutex. If the caller
218 * already has ownership of the mutex or can be granted ownership of the mutex before the timeout expires,
219 * then true will be returned and the caller will own the mutex, otherwise false will be returned and the caller
220 * will NOT own the mutex.
221 *
222 * \param mtx Pointer to recursive mutex structure
223 * \param until The time after which to return if the caller cannot be granted ownership of the mutex
224 * \return true if the recursive mutex (now) owned, false if timeout occurred before ownership could be granted
225 */
226 bool recursive_mutex_enter_block_until(recursive_mutex_t *mtx, absolute_time_t until);
227
228 /*! \brief Release ownership of a mutex
229 * \ingroup mutex
230 *
231 * \param mtx Pointer to mutex structure
232 */
233 void mutex_exit(mutex_t *mtx);
234
235 /*! \brief Release ownership of a recursive mutex
236 * \ingroup mutex
237 *
238 * \param mtx Pointer to recursive mutex structure
239 */
240 void recursive_mutex_exit(recursive_mutex_t *mtx);
241
242 /*! \brief Test for mutex initialized state
243 * \ingroup mutex
244 *
245 * \param mtx Pointer to mutex structure
246 * \return true if the mutex is initialized, false otherwise
247 */
mutex_is_initialized(mutex_t * mtx)248 static inline bool mutex_is_initialized(mutex_t *mtx) {
249 return mtx->core.spin_lock != 0;
250 }
251
252 /*! \brief Test for recursive mutex initialized state
253 * \ingroup mutex
254 *
255 * \param mtx Pointer to recursive mutex structure
256 * \return true if the recursive mutex is initialized, false otherwise
257 */
recursive_mutex_is_initialized(recursive_mutex_t * mtx)258 static inline bool recursive_mutex_is_initialized(recursive_mutex_t *mtx) {
259 return mtx->core.spin_lock != 0;
260 }
261
262 /*! \brief Helper macro for static definition of mutexes
263 * \ingroup mutex
264 *
265 * A mutex defined as follows:
266 *
267 * ```c
268 * auto_init_mutex(my_mutex);
269 * ```
270 *
271 * Is equivalent to doing
272 *
273 * ```c
274 * static mutex_t my_mutex;
275 *
276 * void my_init_function() {
277 * mutex_init(&my_mutex);
278 * }
279 * ```
280 *
281 * But the initialization of the mutex is performed automatically during runtime initialization
282 */
283 #define auto_init_mutex(name) static __attribute__((section(".mutex_array"))) mutex_t name
284
285 /*! \brief Helper macro for static definition of recursive mutexes
286 * \ingroup mutex
287 *
288 * A recursive mutex defined as follows:
289 *
290 * ```c
291 * auto_init_recursive_mutex(my_recursive_mutex);
292 * ```
293 *
294 * Is equivalent to doing
295 *
296 * ```c
297 * static recursive_mutex_t my_recursive_mutex;
298 *
299 * void my_init_function() {
300 * recursive_mutex_init(&my_recursive_mutex);
301 * }
302 * ```
303 *
304 * But the initialization of the mutex is performed automatically during runtime initialization
305 */
306 #define auto_init_recursive_mutex(name) static __attribute__((section(".mutex_array"))) recursive_mutex_t name = { .core = { .spin_lock = (spin_lock_t *)1 /* marker for runtime_init */ }, .owner = 0, .enter_count = 0 }
307
308 void runtime_init_mutex(void);
309
310 #ifdef __cplusplus
311 }
312 #endif
313 #endif
314