diff options
Diffstat (limited to 'libcr')
-rw-r--r-- | libcr/coroutine.c | 72 | ||||
-rw-r--r-- | libcr/include/libcr/coroutine.h | 38 |
2 files changed, 85 insertions, 25 deletions
diff --git a/libcr/coroutine.c b/libcr/coroutine.c index 121cc3b..182e85c 100644 --- a/libcr/coroutine.c +++ b/libcr/coroutine.c @@ -399,6 +399,7 @@ struct coroutine { #if CONFIG_COROUTINE_VALGRIND unsigned stack_id; #endif + bool stack_free; /* 4. env ***************************************************/ cr_plat_jmp_buf env; @@ -547,16 +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); - log_debugln("coroutine_add_with_stack_size(", stack_size, ", ", (qstr, name), ", ", (ptr, fn), ", ", (ptr, args), ")..."); if (!coroutine_initialized) { cr_plat_init(); @@ -577,27 +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; - log_infoln("allocing ", (qstr, name), " stack with size ", - stack_size, "+2*", (base10, 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); - log_infoln("...done, stack is [", + 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 + coroutine_table[child-1].stack_size), ")"); - log_infoln(" usable stack is [", + (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 + CR_STACK_GUARD_SIZE + stack_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 ***************************************************/ @@ -605,9 +614,10 @@ 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 ; log_debugln("...stack_base=", (ptr, stack_base)); @@ -624,10 +634,33 @@ 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) { @@ -665,7 +698,8 @@ 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); + if (coroutine_table[coroutine_running-1].stack_free) + free(coroutine_table[coroutine_running-1].stack); coroutine_table[coroutine_running-1] = (struct coroutine){}; coroutine_cnt--; } diff --git a/libcr/include/libcr/coroutine.h b/libcr/include/libcr/coroutine.h index 589664f..f0e6e61 100644 --- a/libcr/include/libcr/coroutine.h +++ b/libcr/include/libcr/coroutine.h @@ -83,7 +83,15 @@ typedef void (*cr_fn_t)(void *args); /* managing coroutines ********************************************************/ /** - * Call `fn(args)` in a new coroutine with stack size `stack_size`. + * Call `fn(args)` in a new coroutine with the `full_stack_size`-sized + * block of memory `stack` as the coroutine stack. + * + * There may be CPU-specific requirements on the alignment of the + * `stack` pointer. + * + * If CONFIG_COROUTINE_PROTECT_STACK: The usable stack size will be + * slightly less than `full_stack_size`, in order to make room for a + * stack guard at each end. * * See the doc comment on c_fn_t for the requirements imposed on fn. * @@ -94,17 +102,35 @@ typedef void (*cr_fn_t)(void *args); * Returns the cid of the newly-created coroutine. May return 0 if * there are already COROUTINE_NUM active coroutines. */ -cid_t coroutine_add_with_stack_size(size_t stack_size, const char *name, cr_fn_t fn, void *args); +cid_t coroutine_add_with_stack(void *stack, size_t full_stack_size, const char *name, cr_fn_t fn, void *args); + +/** + * Like coroutine_add_with_stack(), but will use aligned_alloc() to + * allocate a block of memory to use as the stack. + * + * If CONFIG_COROUTINE_PROTECT_STACK: `usable_stack_size` does *not* + * include the size of the stack guard at each end; the amount of + * memory allocated for the stack will be slightly larger than + * `usable_stack_size`. + */ +cid_t coroutine_add_with_stack_size(size_t usable_stack_size, const char *name, cr_fn_t fn, void *args); /** * Like coroutine_add_with_stack_size(), but uses a default stack size so * you don't need to think about it. * - * Either define CONFIG_COROUTINE_STACK_SIZE_DEFAULT to use for all - * coroutines, or CONFIG_COROUTINE_STACK_SIZE_{fn} for each COROUTINE - * function. + * Either: + * - define CONFIG_COROUTINE_STACK_SIZE_DEFAULT to use for all + * coroutines; or + * - define/declare CONFIG_COROUTINE_STACK_SIZE_{fn} for each COROUTINE + * function; or + * - define CONFIG_COROUTINE_STACK_PREALLOCATE and then + * define/declare COROUTINE_STACK_{fn} and COROUTINE_STACK_{fn}_len + * for each COROUTINE function. */ -#ifdef CONFIG_COROUTINE_STACK_SIZE_DEFAULT +#if defined(CONFIG_COROUTINE_STACK_PREALLOCATE) +#define coroutine_add(name, fn, args) coroutine_add_with_stack(COROUTINE_STACK_##fn, COROUTINE_STACK_##fn##_len, name, fn, args) +#elif defined(CONFIG_COROUTINE_STACK_SIZE_DEFAULT) #define coroutine_add(name, fn, args) coroutine_add_with_stack_size(CONFIG_COROUTINE_STACK_SIZE_DEFAULT, name, fn, args) #else #define coroutine_add(name, fn, args) coroutine_add_with_stack_size(CONFIG_COROUTINE_STACK_SIZE_##fn, name, fn, args) |