From ec80ab676556a45150380338b64c0d0cf26f2141 Mon Sep 17 00:00:00 2001 From: "Luke T. Shumaker" Date: Tue, 1 Oct 2024 11:51:06 -0600 Subject: libcr: expose cr_{disable,enable}_interrupts --- libcr/coroutine.c | 24 ++++++++++----------- libcr/include/libcr/coroutine.h | 46 +++++++++++++++++++++++++++++++++++++---- 2 files changed, 54 insertions(+), 16 deletions(-) (limited to 'libcr') diff --git a/libcr/coroutine.c b/libcr/coroutine.c index 8bfdb86..be8d378 100644 --- a/libcr/coroutine.c +++ b/libcr/coroutine.c @@ -140,10 +140,10 @@ static ALWAYS_INLINE void cr_plat_wait_for_interrupt(void) { asm volatile ("wfi":::"memory"); } - static ALWAYS_INLINE void cr_plat_disable_interrupts(void) { + void _cr_plat_disable_interrupts(void) { asm volatile ("cpsid i":::"memory"); } - static ALWAYS_INLINE void cr_plat_enable_interrupts(void) { + void _cr_plat_enable_interrupts(void) { asm volatile ("cpsie i":::"memory"); } @@ -196,12 +196,12 @@ static inline void cr_plat_wait_for_interrupt(void) { pause(); } - static inline void cr_plat_disable_interrupts(void) { + void _cr_plat_disable_interrupts(void) { sigset_t all; sigfillset(&all); sigprocmask(SIG_BLOCK, &all, NULL); } - static inline void cr_plat_enable_interrupts(void) { + void _cr_plat_enable_interrupts(void) { sigset_t all; sigfillset(&all); sigprocmask(SIG_UNBLOCK, &all, NULL); @@ -450,12 +450,12 @@ static inline cid_t next_coroutine() { void coroutine_main(void) { debugf("coroutine_main()\n"); - cr_plat_disable_interrupts(); + cr_disable_interrupts(); coroutine_running = 0; for (;;) { cid_t next = next_coroutine(); if (!next) { - cr_plat_enable_interrupts(); + cr_enable_interrupts(); errorf("no coroutines\n"); return; } @@ -482,7 +482,7 @@ void cr_begin(void) { coroutine_table[coroutine_running-1].sp = cr_plat_get_sp(); if (!cr_plat_setjmp(coroutine_table[coroutine_running-1].env)) /* point=c1 */ cr_plat_longjmp(coroutine_add_env, 1); /* jump to point=a */ - cr_plat_enable_interrupts(); + cr_enable_interrupts(); } static inline void _cr_transition(enum coroutine_state state) { @@ -517,28 +517,28 @@ void cr_yield(void) { debugf("cid=%zu: cr_yield()\n", coroutine_running); assert_cid_state(coroutine_running, state == CR_RUNNING); - cr_plat_disable_interrupts(); + cr_disable_interrupts(); _cr_transition(CR_RUNNABLE); - cr_plat_enable_interrupts(); + cr_enable_interrupts(); } void cr_pause_and_yield(void) { debugf("cid=%zu: cr_pause_and_yield()\n", coroutine_running); assert_cid_state(coroutine_running, state == CR_RUNNING || state == CR_PRE_RUNNABLE); - cr_plat_disable_interrupts(); + cr_disable_interrupts(); if (coroutine_table[coroutine_running-1].state == CR_PRE_RUNNABLE) _cr_transition(CR_RUNNABLE); else _cr_transition(CR_PAUSED); - cr_plat_enable_interrupts(); + cr_enable_interrupts(); } void cr_exit(void) { debugf("cid=%zu: cr_exit()\n", coroutine_running); assert_cid_state(coroutine_running, state == CR_RUNNING); - cr_plat_disable_interrupts(); + cr_disable_interrupts(); coroutine_table[coroutine_running-1].state = CR_NONE; cr_plat_longjmp(coroutine_main_env, 1); /* jump to point=b */ } diff --git a/libcr/include/libcr/coroutine.h b/libcr/include/libcr/coroutine.h index 0c5eac3..458e74e 100644 --- a/libcr/include/libcr/coroutine.h +++ b/libcr/include/libcr/coroutine.h @@ -113,8 +113,6 @@ 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_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 @@ -126,9 +124,49 @@ cid_t cr_getcid(void); * another as paused; a coroutine may only do those things to itself. */ -/* While the following are defined here unconditionally, the - * implementations are #if'd on CONFIG_COROUTINE_MEASURE_STACK. +/* dealing with interrupts ****************************************************/ + +/** + * "Disable" interrupts. Interrupts that come in while disabled will + * be placed in a "pending" queue. + * + * This is fast on bare-metal, but slow on an OS (because on an OS it + * uses a syscall). + */ +#define cr_disable_interrupts() do { \ + _cr_plat_disable_interrupts(); \ + asm volatile ("":::"memory"); \ + } while (0) +void _cr_plat_disable_interrupts(void); + +/** + * Enable interrupts. Any "pending" interrupts that came in while + * interrupts were disabled will have their handlers called. + * + * This is fast on bare-metal, but slow on an OS (because on an OS it + * uses a syscall). */ +#define cr_enable_interrupts() do { \ + asm volatile ("":::"memory"); \ + _cr_plat_enable_interrupts(); \ + } while (0) +void _cr_plat_enable_interrupts(void); + +/** + * 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. + * + * It is also safe to call from a regular coroutine, but compared to + * regular cr_unpause() it is less capable of detecting programming + * errors. So don't do that? + */ +void cr_unpause_from_intrhandler(cid_t); + +/* answering questions about coroutines ***************************************/ + +/* While the following are defined here unconditionally, the + * implementations are #if'd on CONFIG_COROUTINE_MEASURE_STACK. */ struct cr_cid_info { size_t stack_cap; -- cgit v1.2.3-2-g168b