summaryrefslogtreecommitdiff
path: root/coroutine.c
diff options
context:
space:
mode:
authorLuke T. Shumaker <lukeshu@lukeshu.com>2024-09-26 19:31:05 -0600
committerLuke T. Shumaker <lukeshu@lukeshu.com>2024-09-26 19:31:05 -0600
commitf5da707e77ee954b12f3c961012e4f40fa4e1bd3 (patch)
tree6a9ddcdd487ee5c60f3c8570866b813e5fe74d9e /coroutine.c
parenta9acf65bc8e3439d7fd2c927b2a920f120cb3a47 (diff)
races
Diffstat (limited to 'coroutine.c')
-rw-r--r--coroutine.c53
1 files changed, 38 insertions, 15 deletions
diff --git a/coroutine.c b/coroutine.c
index f138fcf..12d4a25 100644
--- a/coroutine.c
+++ b/coroutine.c
@@ -154,10 +154,11 @@ enum coroutine_state {
*/
struct coroutine {
- enum coroutine_state state;
- jmp_buf env;
- size_t stack_size;
- void *stack;
+ volatile enum coroutine_state state;
+ volatile bool sig_unpause;
+ jmp_buf env;
+ size_t stack_size;
+ void *stack;
};
static struct coroutine coroutine_table[CONFIG_COROUTINE_NUM] = {0};
@@ -213,8 +214,10 @@ static void call_with_stack(void *stack, cr_fn_t fn, void *args) {
static const uint8_t stack_pattern[] = {0x1e, 0x15, 0x16, 0x0a, 0xcc, 0x52, 0x7e, 0xb7};
#endif
+static void inline assert_cid(cid_t cid) {
+ assert(cid > 0);
+ assert(cid <= CONFIG_COROUTINE_NUM);
#if CONFIG_COROUTINE_PROTECT_STACK
-void assert_stack_protection(cid_t cid) {
assert(coroutine_table[cid-1].stack_size);
assert(coroutine_table[cid-1].stack);
for (size_t i = 0; i < sizeof(stack_pattern); i++) {
@@ -222,16 +225,12 @@ void assert_stack_protection(cid_t cid) {
assert(((uint8_t*)coroutine_table[cid-1].stack)[i] == stack_pattern[i]);
assert(((uint8_t*)coroutine_table[cid-1].stack)[j] == stack_pattern[j%sizeof(stack_pattern)]);
}
-}
-#else
-# define assert_stack_protection(cid) ((void)0)
#endif
+}
#define assert_cid_state(cid, opstate) do { \
- assert((cid) > 0); \
- assert((cid) <= CONFIG_COROUTINE_NUM); \
+ assert_cid(cid); \
assert(coroutine_table[(cid)-1].state opstate); \
- assert_stack_protection(cid); \
} while (0)
cid_t coroutine_add_with_stack_size(size_t stack_size, cr_fn_t fn, void *args) {
@@ -344,7 +343,6 @@ void cr_begin(void) {
}
static inline void _cr_transition(enum coroutine_state state) {
- assert_cid_state(coroutine_running, == CR_RUNNING);
debugf("cid=%zu: transition %i->%i\n", coroutine_running, coroutine_table[coroutine_running-1].state, state);
coroutine_table[coroutine_running-1].state = state;
@@ -352,8 +350,19 @@ static inline void _cr_transition(enum coroutine_state state) {
longjmp(coroutine_main_env, 1); /* jump to point=b */
}
-void cr_yield(void) { _cr_transition(CR_RUNNABLE); }
-void cr_pause_and_yield(void) { _cr_transition(CR_PAUSED); }
+void cr_yield(void) {
+ assert_cid_state(coroutine_running, == CR_RUNNING);
+ _cr_transition(CR_RUNNABLE);
+}
+
+void cr_pause_and_yield(void) {
+ assert_cid_state(coroutine_running, == CR_RUNNING);
+ if (coroutine_table[cid-1].sig_unpause)
+ _cr_transition(CR_RUNNABLE);
+ else
+ _cr_transition(CR_PAUSED);
+ coroutine_table[cid-1].sig_unpause = false;
+}
void cr_exit(void) {
assert_cid_state(coroutine_running, == CR_RUNNING);
@@ -367,7 +376,21 @@ void cr_unpause(cid_t cid) {
assert_cid_state(cid, == CR_PAUSED);
debugf("cr_unpause(%zu)\n", cid);
- coroutine_table[cid-1].state = CR_RUNNABLE;
+ coroutine_table[cid-1].sig_unpause = false;
+ coroutine_table[cid-1].state = CR_RUNNABLE;
+}
+
+void cr_unpause_from_sighandler(cid_t cid) {
+ assert_cid(cid);
+
+ switch (coroutine_table[cid-1].state) {
+ case CR_RUNNING:
+ coroutine_table[cid-1].sig_unpause = true;
+ case CR_PAUSED:
+ coroutine_table[cid-1].state = CR_RUNNABLE;
+ default:
+ assert(false);
+ }
}
cid_t cr_getcid(void) {