blob: ec49fdba5a2ce6fb353f2163d2faf7e82e8a22ed [file] [log] [blame]
Austin Schuh208337d2022-01-01 14:29:11 -08001/*
2 * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include "pico/sem.h"
8#include "pico/time.h"
9
10void sem_init(semaphore_t *sem, int16_t initial_permits, int16_t max_permits) {
11 lock_init(&sem->core, next_striped_spin_lock_num());
12 sem->permits = initial_permits;
13 sem->max_permits = max_permits;
14 __mem_fence_release();
15}
16
17int __time_critical_func(sem_available)(semaphore_t *sem) {
18 return *(volatile typeof(sem->permits) *) &sem->permits;
19}
20
21void __time_critical_func(sem_acquire_blocking)(semaphore_t *sem) {
22 do {
23 uint32_t save = spin_lock_blocking(sem->core.spin_lock);
24 if (sem->permits > 0) {
25 sem->permits--;
Ravago Jonesd208ae72023-02-13 02:24:07 -080026 spin_unlock(sem->core.spin_lock, save);
Austin Schuh208337d2022-01-01 14:29:11 -080027 break;
28 }
29 lock_internal_spin_unlock_with_wait(&sem->core, save);
30 } while (true);
31}
32
33bool __time_critical_func(sem_acquire_timeout_ms)(semaphore_t *sem, uint32_t timeout_ms) {
34 return sem_acquire_block_until(sem, make_timeout_time_ms(timeout_ms));
35}
36
37bool __time_critical_func(sem_acquire_timeout_us)(semaphore_t *sem, uint32_t timeout_us) {
38 return sem_acquire_block_until(sem, make_timeout_time_us(timeout_us));
39}
40
41bool __time_critical_func(sem_acquire_block_until)(semaphore_t *sem, absolute_time_t until) {
42 do {
43 uint32_t save = spin_lock_blocking(sem->core.spin_lock);
44 if (sem->permits > 0) {
45 sem->permits--;
Ravago Jonesd208ae72023-02-13 02:24:07 -080046 spin_unlock(sem->core.spin_lock, save);
Austin Schuh208337d2022-01-01 14:29:11 -080047 return true;
48 }
49 if (lock_internal_spin_unlock_with_best_effort_wait_or_timeout(&sem->core, save, until)) {
50 return false;
51 }
52 } while (true);
53}
54
Ravago Jonesd208ae72023-02-13 02:24:07 -080055bool __time_critical_func(sem_try_acquire)(semaphore_t *sem) {
56 uint32_t save = spin_lock_blocking(sem->core.spin_lock);
57 if (sem->permits > 0) {
58 sem->permits--;
59 spin_unlock(sem->core.spin_lock, save);
60 return true;
61 }
62 spin_unlock(sem->core.spin_lock, save);
63 return false;
64}
65
Austin Schuh208337d2022-01-01 14:29:11 -080066// todo this should really have a blocking variant for when permits are maxed out
67bool __time_critical_func(sem_release)(semaphore_t *sem) {
68 uint32_t save = spin_lock_blocking(sem->core.spin_lock);
69 int32_t count = sem->permits;
70 if (count < sem->max_permits) {
71 sem->permits = (int16_t)(count + 1);
72 lock_internal_spin_unlock_with_notify(&sem->core, save);
73 return true;
74 } else {
75 spin_unlock(sem->core.spin_lock, save);
76 return false;
77 }
78}
79
80void __time_critical_func(sem_reset)(semaphore_t *sem, int16_t permits) {
81 assert(permits >= 0 && permits <= sem->max_permits);
82 uint32_t save = spin_lock_blocking(sem->core.spin_lock);
83 if (permits > sem->permits) {
84 sem->permits = permits;
85 lock_internal_spin_unlock_with_notify(&sem->core, save);
86 } else {
87 sem->permits = permits;
88 spin_unlock(sem->core.spin_lock, save);
89 }
90}