| 1 | /* @title: Countdown latch (using events) */ |
| 2 | #pragma once |
| 3 | #include <sync/event.h> |
| 4 | #include <sync/once_latch.h> |
| 5 | #include <time/time.h> |
| 6 | |
| 7 | struct event_latch { |
| 8 | struct once_latch latch; |
| 9 | struct event ready; |
| 10 | }; |
| 11 | |
| 12 | #define EVENT_LATCH_INIT(name_, n) \ |
| 13 | (struct event_latch) { \ |
| 14 | .latch = ONCE_LATCH_INIT(n), \ |
| 15 | .ready = EVENT_INIT((name_).ready, EVENT_NOTIFICATION, false), \ |
| 16 | } |
| 17 | |
| 18 | static inline void event_latch_init(struct event_latch *el, uint64_t count) { |
| 19 | once_latch_init(latch: &el->latch, count); |
| 20 | event_init(e: &el->ready, type: EVENT_NOTIFICATION, false); |
| 21 | } |
| 22 | |
| 23 | static inline bool event_latch_count_down(struct event_latch *el) { |
| 24 | if (once_latch_count_down(latch: &el->latch)) { |
| 25 | event_set(e: &el->ready); |
| 26 | return true; |
| 27 | } |
| 28 | return false; |
| 29 | } |
| 30 | |
| 31 | static inline bool event_latch_is_ready(const struct event_latch *el) { |
| 32 | return once_latch_is_ready(latch: &el->latch); |
| 33 | } |
| 34 | |
| 35 | static inline uint64_t event_latch_count(const struct event_latch *el) { |
| 36 | return once_latch_get_count(latch: &el->latch); |
| 37 | } |
| 38 | |
| 39 | static inline void event_latch_wait(struct event_latch *el) TSA_MAY_SLEEP { |
| 40 | if (event_latch_is_ready(el)) |
| 41 | return; |
| 42 | event_wait(e: &el->ready, type: THREAD_WAIT_UNINTERRUPTIBLE, |
| 43 | reason: THREAD_BLOCK_REASON_MANUAL); |
| 44 | } |
| 45 | |
| 46 | static inline bool |
| 47 | event_latch_wait_timeout(struct event_latch *el, |
| 48 | time_ms_t timeout_ms) TSA_MAY_SLEEP { |
| 49 | if (event_latch_is_ready(el)) |
| 50 | return true; |
| 51 | return event_wait_timeout(e: &el->ready, type: THREAD_WAIT_UNINTERRUPTIBLE, |
| 52 | reason: THREAD_BLOCK_REASON_MANUAL, timeout_ms) |
| 53 | .status == THREAD_WAIT_SATISFIED; |
| 54 | } |
| 55 | |