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