diff options
Diffstat (limited to 'libcr/coroutine.c')
-rw-r--r-- | libcr/coroutine.c | 68 |
1 files changed, 62 insertions, 6 deletions
diff --git a/libcr/coroutine.c b/libcr/coroutine.c index 252eca2..041b624 100644 --- a/libcr/coroutine.c +++ b/libcr/coroutine.c @@ -161,7 +161,30 @@ /* For a signal to be *in* the mask means that the signal is * *blocked*. */ + bool cr_is_in_intrhandler(void) { + sigset_t cur_mask; + sigfillset(&cur_mask); + sigprocmask(0, NULL, &cur_mask); + if (sigismember(&cur_mask, SIGHUP)) + /* Interrupts are disabled, so we cannot be in + * an interrupt handler. */ + return false; + for (int sig = SIGRTMIN; sig <= SIGRTMAX; sig++) + if (sigismember(&cur_mask, sig)) + return true; + return false; + } + static inline bool _cr_plat_are_interrupts_enabled(void) { + assert(!cr_is_in_intrhandler()); + sigset_t cur_mask; + sigfillset(&cur_mask); + sigprocmask(0, NULL, &cur_mask); + return !sigismember(&cur_mask, SIGHUP); + } + static inline void cr_plat_wait_for_interrupt(void) { + assert(!cr_is_in_intrhandler()); + assert(!_cr_plat_are_interrupts_enabled()); sigset_t set; sigemptyset(&set); sigsuspend(&set); @@ -170,29 +193,54 @@ sigprocmask(SIG_SETMASK, &set, NULL); } bool _cr_plat_save_and_disable_interrupts(void) { + assert(!cr_is_in_intrhandler()); sigset_t all, old; sigfillset(&all); sigprocmask(SIG_SETMASK, &all, &old); - return !sigismember(&old, SIGRTMIN); + return !sigismember(&old, SIGHUP); } void _cr_plat_enable_interrupts(void) { + assert(!cr_is_in_intrhandler()); + assert(!_cr_plat_are_interrupts_enabled()); sigset_t zero; sigemptyset(&zero); sigprocmask(SIG_SETMASK, &zero, NULL); } #elif __ARM_ARCH_6M__ && __ARM_EABI__ - static ALWAYS_INLINE void cr_plat_wait_for_interrupt(void) { - asm volatile ("wfi":::"memory"); + bool cr_is_in_intrhandler(void) { + uint32_t isr_number; + asm volatile ("mrs %0, ipsr" + : /* %0 */"=l"(isr_number) + ); + return isr_number != 0; } - bool _cr_plat_save_and_disable_interrupts(void) { + static ALWAYS_INLINE bool _cr_plat_are_interrupts_enabled(void) { + assert(!cr_is_in_intrhandler()); uint32_t primask; - asm volatile ("mrs %0, PRIMASK\n" - "cpsid i" + asm volatile ("mrs %0, PRIMASK" : /* %0 */"=l"(primask) ); return primask == 0; } + + static ALWAYS_INLINE void cr_plat_wait_for_interrupt(void) { + assert(!cr_is_in_intrhandler()); + assert(!_cr_plat_are_interrupts_enabled()); + asm volatile ("wfi\n" + "cpsie i\n" + "isb\n" + "cpsid i" + :::"memory"); + } + bool _cr_plat_save_and_disable_interrupts(void) { + assert(!cr_is_in_intrhandler()); + bool were_enabled = _cr_plat_are_interrupts_enabled(); + asm volatile ("cpsid i"); + return were_enabled; + } void _cr_plat_enable_interrupts(void) { + assert(!cr_is_in_intrhandler()); + assert(!_cr_plat_are_interrupts_enabled()); asm volatile ("cpsie i"); } #else @@ -498,6 +546,7 @@ __attribute__ ((noreturn)) void coroutine_main(void) { debugf("coroutine_main()\n"); bool saved = cr_save_and_disable_interrupts(); assert(saved); + assert(!cr_is_in_intrhandler()); coroutine_running = 0; for (;;) { cid_t next; @@ -561,6 +610,7 @@ static inline void _cr_yield() { void cr_yield(void) { debugf("cid=%zu: cr_yield()\n", coroutine_running); + assert(!cr_is_in_intrhandler()); assert_cid_state(coroutine_running, state == CR_RUNNING); bool saved = cr_save_and_disable_interrupts(); @@ -572,6 +622,7 @@ void cr_yield(void) { void cr_pause_and_yield(void) { debugf("cid=%zu: cr_pause_and_yield()\n", coroutine_running); + assert(!cr_is_in_intrhandler()); assert_cid_state(coroutine_running, state == CR_RUNNING); bool saved = cr_save_and_disable_interrupts(); @@ -582,6 +633,7 @@ void cr_pause_and_yield(void) { __attribute__ ((noreturn)) void cr_exit(void) { debugf("cid=%zu: cr_exit()\n", coroutine_running); + assert(!cr_is_in_intrhandler()); assert_cid_state(coroutine_running, state == CR_RUNNING); (void)cr_save_and_disable_interrupts(); @@ -598,7 +650,9 @@ static void _cr_unpause(cid_t cid) { void cr_unpause(cid_t cid) { debugf("cr_unpause(%zu)\n", cid); + assert(!cr_is_in_intrhandler()); assert_cid_state(coroutine_running, state == CR_RUNNING); + bool saved = cr_save_and_disable_interrupts(); _cr_unpause(cid); cr_restore_interrupts(saved); @@ -606,11 +660,13 @@ void cr_unpause(cid_t cid) { void cr_unpause_from_intrhandler(cid_t cid) { debugf("cr_unpause_from_intrhandler(%zu)\n", cid); + assert(cr_is_in_intrhandler()); _cr_unpause(cid); } cid_t cr_getcid(void) { + assert(!cr_is_in_intrhandler()); assert_cid_state(coroutine_running, state == CR_RUNNING); return coroutine_running; } |