1 /*
2  * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include "pico/mutex.h"
8 #include "pico/time.h"
9 
10 #if !PICO_NO_HARDWARE
11 static_assert(sizeof(mutex_t) == 8, "");
12 #endif
13 
mutex_init(mutex_t * mtx)14 void mutex_init(mutex_t *mtx) {
15     lock_init(&mtx->core, next_striped_spin_lock_num());
16     mtx->owner = -1;
17     __mem_fence_release();
18 }
19 
__time_critical_func(mutex_enter_blocking)20 void __time_critical_func(mutex_enter_blocking)(mutex_t *mtx) {
21     assert(mtx->core.spin_lock);
22     bool block = true;
23     do {
24         uint32_t save = spin_lock_blocking(mtx->core.spin_lock);
25         if (mtx->owner < 0) {
26             mtx->owner = get_core_num();
27             block = false;
28         }
29         spin_unlock(mtx->core.spin_lock, save);
30         if (block) {
31             __wfe();
32         }
33     } while (block);
34 }
35 
__time_critical_func(mutex_try_enter)36 bool __time_critical_func(mutex_try_enter)(mutex_t *mtx, uint32_t *owner_out) {
37     bool entered;
38     uint32_t save = spin_lock_blocking(mtx->core.spin_lock);
39     if (mtx->owner < 0) {
40         mtx->owner = get_core_num();
41         entered = true;
42     } else {
43         if (owner_out) *owner_out = mtx->owner;
44         entered = false;
45     }
46     spin_unlock(mtx->core.spin_lock, save);
47     return entered;
48 }
49 
__time_critical_func(mutex_enter_timeout_ms)50 bool __time_critical_func(mutex_enter_timeout_ms)(mutex_t *mtx, uint32_t timeout_ms) {
51     return mutex_enter_block_until(mtx, make_timeout_time_ms(timeout_ms));
52 }
53 
__time_critical_func(mutex_enter_block_until)54 bool __time_critical_func(mutex_enter_block_until)(mutex_t *mtx, absolute_time_t until) {
55     assert(mtx->core.spin_lock);
56     bool block = true;
57     do {
58         uint32_t save = spin_lock_blocking(mtx->core.spin_lock);
59         if (mtx->owner < 0) {
60             mtx->owner = get_core_num();
61             block = false;
62         }
63         spin_unlock(mtx->core.spin_lock, save);
64         if (block) {
65             if (best_effort_wfe_or_timeout(until)) {
66                 return false;
67             }
68         }
69     } while (block);
70     return true;
71 }
72 
__time_critical_func(mutex_exit)73 void __time_critical_func(mutex_exit)(mutex_t *mtx) {
74     uint32_t save = spin_lock_blocking(mtx->core.spin_lock);
75     assert(mtx->owner >= 0);
76     mtx->owner = -1;
77     __sev();
78     spin_unlock(mtx->core.spin_lock, save);
79 }
80