diff options
Diffstat (limited to 'libcr/coroutine.c')
-rw-r--r-- | libcr/coroutine.c | 107 |
1 files changed, 71 insertions, 36 deletions
diff --git a/libcr/coroutine.c b/libcr/coroutine.c index 33e8141..182e85c 100644 --- a/libcr/coroutine.c +++ b/libcr/coroutine.c @@ -349,7 +349,7 @@ static_assert(CONFIG_COROUTINE_NUM > 1); uintptr_t sp; #endif } cr_plat_jmp_buf; - static void _cr_plat_setjmp_pre(cr_plat_jmp_buf *env [[gnu::unused]]) { + static void _cr_plat_setjmp_pre(cr_plat_jmp_buf *env [[maybe_unused]]) { #if CONFIG_COROUTINE_MEASURE_STACK env->sp = cr_plat_get_sp(); #endif @@ -399,6 +399,7 @@ struct coroutine { #if CONFIG_COROUTINE_VALGRIND unsigned stack_id; #endif + bool stack_free; /* 4. env ***************************************************/ cr_plat_jmp_buf env; @@ -424,9 +425,9 @@ static const uint8_t stack_pattern[] = { #endif #if CONFIG_COROUTINE_PROTECT_STACK #define CR_STACK_GUARD_SIZE \ - LM_ROUND_UP(sizeof(stack_pattern), CR_PLAT_STACK_ALIGNMENT) + ((size_t)LM_ROUND_UP(sizeof(stack_pattern), CR_PLAT_STACK_ALIGNMENT)) #else - #define CR_STACK_GUARD_SIZE 0 + #define CR_STACK_GUARD_SIZE ((size_t)0) #endif /* global variables ***********************************************************/ @@ -457,7 +458,7 @@ static cr_plat_jmp_buf coroutine_gdb_env; * coroutine_ringbuf queue. */ -static struct coroutine coroutine_table[CONFIG_COROUTINE_NUM] = {0}; +static struct coroutine coroutine_table[CONFIG_COROUTINE_NUM] = {}; static struct { /* tail == head means empty */ /* buf[tail] is the next thing to run */ @@ -468,7 +469,7 @@ static struct { * we don't have to worry about funny wrap-around behavior * when head or tail overflow. */ cid_t buf[LM_NEXT_POWER_OF_2(CONFIG_COROUTINE_NUM)]; -} coroutine_ringbuf = {0}; +} coroutine_ringbuf = {}; static cid_t coroutine_running = 0; static size_t coroutine_cnt = 0; @@ -547,17 +548,15 @@ cid_t coroutine_allocate_cid(void) { return 0; } -cid_t coroutine_add_with_stack_size(size_t stack_size, - const char *name, - cr_fn_t fn, void *args) { +static cid_t _coroutine_add(void *stack, size_t full_stack_size, + const char *name, + cr_fn_t fn, void *args) { cid_t parent = coroutine_running; if (parent) assert_cid_state(parent, state == CR_RUNNING); - assert(stack_size); + assert(full_stack_size > 2*CR_STACK_GUARD_SIZE); assert(fn); - debugf("coroutine_add_with_stack_size(%zu, \"%s\", %p, %p)...", - stack_size, name, fn, args); if (!coroutine_initialized) { cr_plat_init(); @@ -567,7 +566,7 @@ cid_t coroutine_add_with_stack_size(size_t stack_size, cid_t child = coroutine_allocate_cid(); if (!child) return 0; - debugf("...child=%zu", child); + log_debugln("...child=", child); /* 1. state *************************************************/ coroutine_table[child-1].state = CR_INITIALIZING; @@ -578,24 +577,36 @@ cid_t coroutine_add_with_stack_size(size_t stack_size, else memset(coroutine_table[child-1].name, 0, sizeof(coroutine_table[child-1].name)); + log_infoln("starting cid ", child, + " ", (qstrn, coroutine_table[child-1].name, sizeof(coroutine_table[child-1].name)), + ":"); + /* 3. stack *************************************************/ - coroutine_table[child-1].stack_size = stack_size + 2*CR_STACK_GUARD_SIZE; - infof("allocing \"%s\" stack with size %zu+2*%zu=%zu", - name, stack_size, CR_STACK_GUARD_SIZE, coroutine_table[child-1].stack_size); - coroutine_table[child-1].stack = - aligned_alloc(CR_PLAT_STACK_ALIGNMENT, coroutine_table[child-1].stack_size); - infof("... done, stack is [%#zx,%#zx)", - coroutine_table[child-1].stack + CR_STACK_GUARD_SIZE, - coroutine_table[child-1].stack + CR_STACK_GUARD_SIZE + stack_size); + coroutine_table[child-1].stack_size = full_stack_size; + coroutine_table[child-1].stack_free = (stack == NULL); + if (!stack) { + log_infoln("allocing stack with size ", full_stack_size, "..."); + stack = aligned_alloc(CR_PLAT_STACK_ALIGNMENT, full_stack_size); + log_infoln("...done"); + } + coroutine_table[child-1].stack = stack; + log_infoln(" -> full stack is [", + (ptr, coroutine_table[child-1].stack), ",", + (ptr, coroutine_table[child-1].stack + full_stack_size), ")", + " ; size=", full_stack_size); + log_infoln(" -> usable stack is [", + (ptr, coroutine_table[child-1].stack + CR_STACK_GUARD_SIZE), ",", + (ptr, coroutine_table[child-1].stack + full_stack_size - CR_STACK_GUARD_SIZE), ")", + " ; size=", full_stack_size - 2*CR_STACK_GUARD_SIZE); #if CONFIG_COROUTINE_MEASURE_STACK || CONFIG_COROUTINE_PROTECT_STACK - for (size_t i = 0; i < coroutine_table[child-1].stack_size; i++) + for (size_t i = 0; i < full_stack_size; i++) ((uint8_t *)coroutine_table[child-1].stack)[i] = stack_pattern[i%sizeof(stack_pattern)]; #endif #if CONFIG_COROUTINE_VALGRIND coroutine_table[child-1].stack_id = VALGRIND_STACK_REGISTER( coroutine_table[child-1].stack + CR_STACK_GUARD_SIZE, - coroutine_table[child-1].stack + CR_STACK_GUARD_SIZE + stack_size); + coroutine_table[child-1].stack + full_stack_size - CR_STACK_GUARD_SIZE); #endif /* 4. env ***************************************************/ @@ -603,13 +614,13 @@ cid_t coroutine_add_with_stack_size(size_t stack_size, coroutine_cnt++; if (!cr_setjmp(&coroutine_add_env)) { /* point=a */ void *stack_base = coroutine_table[child-1].stack - + CR_STACK_GUARD_SIZE #if CR_PLAT_STACK_GROWS_DOWNWARD - + stack_size + + full_stack_size - CR_STACK_GUARD_SIZE +#else + + CR_STACK_GUARD_SIZE #endif ; - debugf("...stack =%p", coroutine_table[child-1].stack); - debugf("...stack_base=%p", stack_base); + log_debugln("...stack_base=", (ptr, stack_base)); /* run until cr_begin() */ cr_plat_call_with_stack(stack_base, fn, args); assert_notreached("should cr_begin() instead of returning"); @@ -623,14 +634,37 @@ cid_t coroutine_add_with_stack_size(size_t stack_size, * didn't actually check. */ cr_restore_interrupts(true); coroutine_running = parent; + log_infoln(" -> done"); return child; } +cid_t coroutine_add_with_stack(void *stack, size_t full_stack_size, + const char *name, + cr_fn_t fn, void *args) { + if (name) + log_debugln("coroutine_add_with_stack(", (ptr, stack), full_stack_size, ", ", (qstr, name), ", ", (ptr, fn), ", ", (ptr, args), ")..."); + else + log_debugln("coroutine_add_with_stack(", (ptr, stack), full_stack_size, ", ", (ptr, name), ", ", (ptr, fn), ", ", (ptr, args), ")..."); + + return _coroutine_add(stack, full_stack_size, name, fn, args); +} + +cid_t coroutine_add_with_stack_size(size_t usable_stack_size, + const char *name, + cr_fn_t fn, void *args) { + if (name) + log_debugln("coroutine_add_with_stack_size(", usable_stack_size, ", ", (qstr, name), ", ", (ptr, fn), ", ", (ptr, args), ")..."); + else + log_debugln("coroutine_add_with_stack_size(", usable_stack_size, ", ", (ptr, name), ", ", (ptr, fn), ", ", (ptr, args), ")..."); + + return _coroutine_add(NULL, usable_stack_size + 2*CR_STACK_GUARD_SIZE, name, fn, args); +} + /* coroutine_main() ***********************************************************/ void coroutine_main(void) { - debugf("coroutine_main()"); + log_debugln("coroutine_main()"); if (!coroutine_initialized) { cr_plat_init(); coroutine_initialized = true; @@ -664,8 +698,9 @@ void coroutine_main(void) { #if CONFIG_COROUTINE_VALGRIND VALGRIND_STACK_DEREGISTER(coroutine_table[coroutine_running-1].stack_id); #endif - free(coroutine_table[coroutine_running-1].stack); - coroutine_table[coroutine_running-1] = (struct coroutine){0}; + if (coroutine_table[coroutine_running-1].stack_free) + free(coroutine_table[coroutine_running-1].stack); + coroutine_table[coroutine_running-1] = (struct coroutine){}; coroutine_cnt--; } coroutine_running = 0; @@ -675,7 +710,7 @@ void coroutine_main(void) { /* cr_*() *********************************************************************/ void cr_begin(void) { - debugf("cid=%zu: cr_begin()", coroutine_running); + log_debugln("cid=", coroutine_running, ": cr_begin()"); assert_cid_state(coroutine_running, state == CR_INITIALIZING); bool saved = cr_save_and_disable_interrupts(); @@ -686,7 +721,7 @@ void cr_begin(void) { cr_restore_interrupts(saved); } -static inline void _cr_yield() { +static inline void _cr_yield(void) { cid_t next; while ( !((next = coroutine_ringbuf_pop())) ) { /* No coroutines are runnable, wait for an interrupt @@ -707,7 +742,7 @@ static inline void _cr_yield() { } void cr_yield(void) { - debugf("cid=%zu: cr_yield()", coroutine_running); + log_debugln("cid=", coroutine_running ,": cr_yield()"); assert(!cr_plat_is_in_intrhandler()); assert_cid_state(coroutine_running, state == CR_RUNNING); @@ -719,7 +754,7 @@ void cr_yield(void) { } void cr_pause_and_yield(void) { - debugf("cid=%zu: cr_pause_and_yield()", coroutine_running); + log_debugln("cid=", coroutine_running, ": cr_pause_and_yield()"); assert(!cr_plat_is_in_intrhandler()); assert_cid_state(coroutine_running, state == CR_RUNNING); @@ -730,7 +765,7 @@ void cr_pause_and_yield(void) { } [[noreturn]] void cr_exit(void) { - debugf("cid=%zu: cr_exit()", coroutine_running); + log_debugln("cid=", coroutine_running, ": cr_exit()"); assert(!cr_plat_is_in_intrhandler()); assert_cid_state(coroutine_running, state == CR_RUNNING); @@ -747,7 +782,7 @@ static void _cr_unpause(cid_t cid) { } void cr_unpause(cid_t cid) { - debugf("cr_unpause(%zu)", cid); + log_debugln("cr_unpause(", cid, ")"); assert(!cr_plat_is_in_intrhandler()); assert_cid_state(coroutine_running, state == CR_RUNNING); @@ -757,7 +792,7 @@ void cr_unpause(cid_t cid) { } void cr_unpause_from_intrhandler(cid_t cid) { - debugf("cr_unpause_from_intrhandler(%zu)", cid); + log_debugln("cr_unpause_from_intrhandler(", cid, ")"); assert(cr_plat_is_in_intrhandler()); _cr_unpause(cid); |