diff options
author | Luke T. Shumaker <lukeshu@lukeshu.com> | 2024-09-29 12:14:45 -0600 |
---|---|---|
committer | Luke T. Shumaker <lukeshu@lukeshu.com> | 2024-09-29 12:24:10 -0600 |
commit | cd0b080d638005bff762f1f8cae9a6c76648265b (patch) | |
tree | f9b76002924a16afae66df3815d521f0e7b25efb | |
parent | 6940b244de7c5048c55fc57ada93501c1be5ab20 (diff) |
tidy, s/sighandler/intrhandler/
-rw-r--r-- | libcr/coroutine.c | 20 | ||||
-rw-r--r-- | libcr/include/libcr/coroutine.h | 4 | ||||
-rw-r--r-- | libcr_ipc/include/libcr_ipc/sema.h | 49 | ||||
-rw-r--r-- | libnetio/netio_posix.c | 4 |
4 files changed, 50 insertions, 27 deletions
diff --git a/libcr/coroutine.c b/libcr/coroutine.c index 25e3e4f..74c74d8 100644 --- a/libcr/coroutine.c +++ b/libcr/coroutine.c @@ -131,7 +131,7 @@ enum coroutine_state { struct coroutine { volatile enum coroutine_state state; - volatile bool sig_unpause; + volatile bool intr_unpause; jmp_buf env; size_t stack_size; void *stack; @@ -444,11 +444,11 @@ void cr_yield(void) { void cr_pause_and_yield(void) { assert_cid_state(coroutine_running, == CR_RUNNING); - if (coroutine_table[coroutine_running-1].sig_unpause) + if (coroutine_table[coroutine_running-1].intr_unpause) _cr_transition(CR_RUNNABLE); else _cr_transition(CR_PAUSED); - coroutine_table[coroutine_running-1].sig_unpause = false; + coroutine_table[coroutine_running-1].intr_unpause = false; } void cr_exit(void) { @@ -463,23 +463,23 @@ void cr_unpause(cid_t cid) { assert_cid_state(cid, == CR_PAUSED); debugf("cr_unpause(%zu)\n", cid); - coroutine_table[cid-1].sig_unpause = false; - coroutine_table[cid-1].state = CR_RUNNABLE; + coroutine_table[cid-1].intr_unpause = false; + coroutine_table[cid-1].state = CR_RUNNABLE; } -void cr_unpause_from_sighandler(cid_t cid) { +void cr_unpause_from_intrhandler(cid_t cid) { assert_cid(cid); - debugf("cr_unpause_from_sighandler(%zu)\n", cid); + debugf("cr_unpause_from_intrhandler(%zu)\n", cid); switch (coroutine_table[cid-1].state) { case CR_RUNNING: debugf("... raced, deferring unpause\n"); - coroutine_table[cid-1].sig_unpause = true; + coroutine_table[cid-1].intr_unpause = true; break; case CR_PAUSED: debugf("... actual unpause\n"); - coroutine_table[cid-1].sig_unpause = false; - coroutine_table[cid-1].state = CR_RUNNABLE; + coroutine_table[cid-1].intr_unpause = false; + coroutine_table[cid-1].state = CR_RUNNABLE; break; default: assertf(false, "cid=%zu state=%s\n", diff --git a/libcr/include/libcr/coroutine.h b/libcr/include/libcr/coroutine.h index faaf6c3..f580b09 100644 --- a/libcr/include/libcr/coroutine.h +++ b/libcr/include/libcr/coroutine.h @@ -113,8 +113,8 @@ void cr_yield(void); void cr_pause_and_yield(void); /** cr_unpause() marks a coroutine as runnable that has previously marked itself as non-runnable with cr_pause_and_yield(). */ void cr_unpause(cid_t); -/** cr_unpause_from_sighandler() is like cr_unpause(), but safe to call from a signal handler that might race with the coroutine actually pausing itself. */ -void cr_unpause_from_sighandler(cid_t); +/** cr_unpause_from_intrhandler() is like cr_unpause(), but safe to call from a interrupt handler that might race with the coroutine actually pausing itself. */ +void cr_unpause_from_intrhandler(cid_t); /** cr_end() is a counterpart to cr_begin(), but is really just cr_exit(). */ #define cr_end cr_exit 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 <stdbool.h> #include <libcr_ipc/_common.h> +/* 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); diff --git a/libnetio/netio_posix.c b/libnetio/netio_posix.c index 34f415d..54df412 100644 --- a/libnetio/netio_posix.c +++ b/libnetio/netio_posix.c @@ -40,7 +40,7 @@ struct netio_socket { static struct netio_socket socket_table[CONFIG_NETIO_NUM_PORTS] = {0}; static void handle_sig_io(int sig __attribute__ ((unused)), siginfo_t *info, void *ucontext __attribute__ ((unused))) { - cr_unpause_from_sighandler((cid_t)info->si_value.sival_int); + cr_unpause_from_intrhandler((cid_t)info->si_value.sival_int); } #if CONFIG_NETIO_ISLINUX @@ -51,7 +51,7 @@ static void handle_sig_accept(int sig __attribute__ ((unused)), siginfo_t *info, sock = &socket_table[i]; if (!sock) return; - cr_sema_signal(&sock->accept_waiters); + cr_sema_signal_from_intrhandler(&sock->accept_waiters); } #endif |