From cd0b080d638005bff762f1f8cae9a6c76648265b Mon Sep 17 00:00:00 2001 From: "Luke T. Shumaker" Date: Sun, 29 Sep 2024 12:14:45 -0600 Subject: tidy, s/sighandler/intrhandler/ --- libcr_ipc/include/libcr_ipc/sema.h | 49 ++++++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 13 deletions(-) (limited to 'libcr_ipc') diff --git a/libcr_ipc/include/libcr_ipc/sema.h b/libcr_ipc/include/libcr_ipc/sema.h index 257c8d5..9fe3223 100644 --- a/libcr_ipc/include/libcr_ipc/sema.h +++ b/libcr_ipc/include/libcr_ipc/sema.h @@ -10,6 +10,10 @@ #include #include +/* Most of the complexity in this file is so that + * cr_sema_signal_from_intrhandler() can actually be safe when called + * in an interrupt handler. */ + /** * A cr_sema_t is a fair unbounded[1] counting semaphore. * @@ -20,18 +24,20 @@ typedef struct { struct _cr_ipc_cid_fifo waiters; /* locked indicates that a call from within a coroutine is is - * messing with ->waiters, so a signal handler can't read it. - * Use `asm volatile ("":::"memory")` after setting =true and - * before setting =false to make sure the compiler doesn't - * re-order writes! */ + * messing with ->waiters, so an interrupt handler can't read + * it. Use `asm volatile ("":::"memory")` after setting =true + * and before setting =false to make sure the compiler doesn't + * re-order writes to ->waiters to be outside of the critical + * section! */ volatile bool locked; } cr_sema_t; /** * Drain a maximum of sema->cnt coroutines from the sema->waiters - * list. Returns true if cr_getcid() was drained. + * list. Returns true if cr_getcid() was drained and we're not in an + * interrupt handler. */ -static inline bool _cr_sema_drain(cr_sema_t *sema) { +static inline bool _cr_sema_drain(cr_sema_t *sema, bool in_intrhandler) { assert(!sema->locked); cid_t self = cr_getcid(); @@ -52,10 +58,14 @@ static inline bool _cr_sema_drain(cr_sema_t *sema) { } else { sema->cnt--; cid_t cid = _cr_ipc_cid_fifo_pop(&sema->waiters); - if (cid == self) - state = DRAINED_SELF; - else - cr_unpause_from_sighandler(cid); + if (in_intrhandler) + cr_unpause_from_intrhandler(cid); + else { + if (cid == self) + state = DRAINED_SELF; + else + cr_unpause(cid); + } } } asm volatile ("":::"memory"); @@ -75,12 +85,25 @@ static inline bool _cr_sema_drain(cr_sema_t *sema) { * * @blocks never * @yields never - * @run_in anywhere (coroutine, sighandler) + * @run_in coroutine */ static inline void cr_sema_signal(cr_sema_t *sema) { sema->cnt++; if (!sema->locked) - _cr_sema_drain(sema); + assert(!_cr_sema_drain(sema, false)); +} + +/** + * Like cr_sema_signal(), but safe to call from an interrupt handler. + * + * @blocks never + * @yields never + * @run_in intrhandler + */ +static inline void cr_sema_signal_from_intrhandler(cr_sema_t *sema) { + sema->cnt++; + if (!sema->locked) + assert(!_cr_sema_drain(sema, true)); } /** @@ -99,7 +122,7 @@ static inline void cr_sema_wait(cr_sema_t *sema) { asm volatile ("":::"memory"); sema->locked = false; - if (_cr_sema_drain(sema)) + if (_cr_sema_drain(sema, false)) /* DRAINED_SELF: (1) No need to pause+yield, (2) we * better have been the last item in the list! */ assert(!self.next); -- cgit v1.2.3-2-g168b