| 1 | /* @title: One-time atomic countdown latches */ |
|---|---|
| 2 | #pragma once |
| 3 | #include <asm.h> |
| 4 | #include <atomic.h> |
| 5 | #include <stdbool.h> |
| 6 | #include <stdint.h> |
| 7 | #include <time/time.h> |
| 8 | |
| 9 | struct once_latch { |
| 10 | atomic_uint64_t count; |
| 11 | }; |
| 12 | |
| 13 | #define ONCE_LATCH_INIT(n) {.count = ATOMIC_VAR_INIT(n)} |
| 14 | |
| 15 | static inline void once_latch_init(struct once_latch *latch, uint64_t count) { |
| 16 | atomic_init(&latch->count, count); |
| 17 | } |
| 18 | |
| 19 | static inline bool once_latch_count_down(struct once_latch *latch) { |
| 20 | return atomic_dec_and_test(&latch->count); |
| 21 | } |
| 22 | |
| 23 | static inline bool once_latch_is_ready(const struct once_latch *latch) { |
| 24 | return atomic_load_acq(&latch->count) == 0; |
| 25 | } |
| 26 | |
| 27 | static inline uint64_t once_latch_get_count(const struct once_latch *latch) { |
| 28 | return atomic_load_acq(&latch->count); |
| 29 | } |
| 30 | |
| 31 | static inline void once_latch_spin_wait(const struct once_latch *latch) { |
| 32 | while (!once_latch_is_ready(latch)) |
| 33 | cpu_pause(); |
| 34 | } |
| 35 | |
| 36 | static inline bool once_latch_spin_timeout(const struct once_latch *latch, |
| 37 | time_ms_t timeout_ms) { |
| 38 | time_ms_t deadline = time_get_ms() + timeout_ms; |
| 39 | while (!once_latch_is_ready(latch)) { |
| 40 | if (time_get_ms() >= deadline) |
| 41 | return once_latch_is_ready(latch); |
| 42 | cpu_pause(); |
| 43 | } |
| 44 | return true; |
| 45 | } |
| 46 |