summaryrefslogtreecommitdiff
path: root/libcr/coroutine.c
diff options
context:
space:
mode:
Diffstat (limited to 'libcr/coroutine.c')
-rw-r--r--libcr/coroutine.c68
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;
}