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
9struct once_latch {
10 atomic_uint64_t count;
11};
12
13#define ONCE_LATCH_INIT(n) {.count = ATOMIC_VAR_INIT(n)}
14
15static inline void once_latch_init(struct once_latch *latch, uint64_t count) {
16 atomic_init(&latch->count, count);
17}
18
19static inline bool once_latch_count_down(struct once_latch *latch) {
20 return atomic_dec_and_test(&latch->count);
21}
22
23static inline bool once_latch_is_ready(const struct once_latch *latch) {
24 return atomic_load_acq(&latch->count) == 0;
25}
26
27static inline uint64_t once_latch_get_count(const struct once_latch *latch) {
28 return atomic_load_acq(&latch->count);
29}
30
31static inline void once_latch_spin_wait(const struct once_latch *latch) {
32 while (!once_latch_is_ready(latch))
33 cpu_pause();
34}
35
36static 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