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