summaryrefslogtreecommitdiff
path: root/libcr
diff options
context:
space:
mode:
authorLuke T. Shumaker <lukeshu@lukeshu.com>2024-10-01 11:51:06 -0600
committerLuke T. Shumaker <lukeshu@lukeshu.com>2024-10-01 20:56:52 -0600
commitec80ab676556a45150380338b64c0d0cf26f2141 (patch)
tree8dccd4a178fe4a1fa668293ca8d3476806657d25 /libcr
parent5cbc2d4a3e3b279667e26774ad1cd37682bdbf28 (diff)
libcr: expose cr_{disable,enable}_interrupts
Diffstat (limited to 'libcr')
-rw-r--r--libcr/coroutine.c24
-rw-r--r--libcr/include/libcr/coroutine.h46
2 files changed, 54 insertions, 16 deletions
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;