diff options
author | Luke T. Shumaker <lukeshu@lukeshu.com> | 2025-02-04 14:09:28 -0700 |
---|---|---|
committer | Luke T. Shumaker <lukeshu@lukeshu.com> | 2025-02-04 18:33:50 -0700 |
commit | a7c299d825038237c63cca919aec6de6be69c4db (patch) | |
tree | 4b2ab1dc25b3aeba1bf5e98c6c743ebf832907f4 | |
parent | 65f2a6fb8797385e06e61e13bac7a33d27f2097d (diff) |
libcr: Flesh out cr_cid_info, clarify stack bounds
-rw-r--r-- | libcr/coroutine.c | 105 | ||||
-rw-r--r-- | libcr/include/libcr/coroutine.h | 20 |
2 files changed, 85 insertions, 40 deletions
diff --git a/libcr/coroutine.c b/libcr/coroutine.c index 708e2ea..c6eeb43 100644 --- a/libcr/coroutine.c +++ b/libcr/coroutine.c @@ -387,23 +387,24 @@ static_assert(CONFIG_COROUTINE_NUM > 1); /* types **********************************************************************/ -enum coroutine_state { - CR_NONE = 0, /* this slot in the table is empty */ - CR_INITIALIZING, /* running, before cr_begin() */ - CR_RUNNING, /* running, after cr_begin() */ - CR_RUNNABLE, /* not running, but runnable */ - CR_PAUSED, /* not running, and not runnable */ -}; - struct coroutine { + /* 1. state *************************************************/ volatile enum coroutine_state state; - cr_plat_jmp_buf env; + + /* 2. name **************************************************/ + [[gnu::nonstring]] char name[CONFIG_COROUTINE_NAME_LEN]; + + /* 3. stack *************************************************/ + /* stack_size *includes* CR_STACK_GUARD at each end. */ size_t stack_size; + /* stack is the bottom of the CR_STACK_GUARD at the bottom of the stack. */ void *stack; #if CONFIG_COROUTINE_VALGRIND unsigned stack_id; #endif - [[gnu::nonstring]] char name[CONFIG_COROUTINE_NAME_LEN]; + + /* 4. env ***************************************************/ + cr_plat_jmp_buf env; }; /* constants ******************************************************************/ @@ -476,11 +477,6 @@ static size_t coroutine_cnt = 0; /* utility functions **********************************************************/ -static inline const char* coroutine_state_str(enum coroutine_state state) { - assert(state < LM_ARRAY_LEN(coroutine_state_strs)); - return coroutine_state_strs[state]; -} - static inline void coroutine_ringbuf_push(cid_t val) { coroutine_ringbuf.buf[coroutine_ringbuf.head++ % LM_ARRAY_LEN(coroutine_ringbuf.buf)] = val; assert((coroutine_ringbuf.head % LM_ARRAY_LEN(coroutine_ringbuf.buf)) != @@ -576,37 +572,43 @@ cid_t coroutine_add_with_stack_size(size_t stack_size, return 0; debugf("...child=%zu", child); + /* 1. state *************************************************/ + coroutine_table[child-1].state = CR_INITIALIZING; + + /* 2. name **************************************************/ if (name) strncpy(coroutine_table[child-1].name, name, sizeof(coroutine_table[child-1].name)); else memset(coroutine_table[child-1].name, 0, sizeof(coroutine_table[child-1].name)); - coroutine_table[child-1].stack_size = stack_size; - infof("allocing \"%s\" stack with size %zu", name, stack_size); + /* 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, stack_size); - infof("...done"); + 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); #if CONFIG_COROUTINE_MEASURE_STACK || CONFIG_COROUTINE_PROTECT_STACK - for (size_t i = 0; i < stack_size; i++) + for (size_t i = 0; i < coroutine_table[child-1].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 + stack_size - CR_STACK_GUARD_SIZE); + coroutine_table[child-1].stack + CR_STACK_GUARD_SIZE + stack_size); #endif + /* 4. env ***************************************************/ coroutine_running = child; - coroutine_table[child-1].state = CR_INITIALIZING; 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 - - CR_STACK_GUARD_SIZE -#else - + CR_STACK_GUARD_SIZE #endif ; debugf("...stack =%p", coroutine_table[child-1].stack); @@ -785,20 +787,35 @@ void cr_assert_in_intrhandler(void) { } #endif -/* cr_cid_info() **************************************************************/ - -#if CONFIG_COROUTINE_MEASURE_STACK +/* answering questions about coroutines ***************************************/ void cr_cid_info(cid_t cid, struct cr_cid_info *ret) { - assert_cid(cid); + assert(cid > 0); + assert(cid <= CONFIG_COROUTINE_NUM); assert(ret); + memset(ret, 0, sizeof(*ret)); + if (coroutine_table[cid-1].state == CR_NONE) + return; + assert_cid(cid); + + /* 1. state *************************************************/ + ret->state = coroutine_table[cid-1].state; + + /* 2. name **************************************************/ + memcpy(ret->name, coroutine_table[cid-1].name, CONFIG_COROUTINE_NAME_LEN); + + /* 3. stack *************************************************/ +#if CONFIG_COROUTINE_MEASURE_STACK + uint8_t *stack = (uint8_t *)coroutine_table[cid-1].stack; + uint8_t *stack_lo = stack + CR_STACK_GUARD_SIZE; + uint8_t *stack_hi = stack + coroutine_table[cid-1].stack_size - CR_STACK_GUARD_SIZE; + /* stack_cap */ - ret->stack_cap = coroutine_table[cid-1].stack_size - 2*CR_STACK_GUARD_SIZE; + ret->stack_cap = stack_hi - stack_lo; /* stack_max */ ret->stack_max = ret->stack_cap; - uint8_t *stack = (uint8_t *)coroutine_table[cid-1].stack; for (;;) { size_t i = #if CR_PLAT_STACK_GROWS_DOWNWARD @@ -807,8 +824,17 @@ void cr_cid_info(cid_t cid, struct cr_cid_info *ret) { ret->stack_max - 1 - CR_STACK_GUARD_SIZE #endif ; - if (ret->stack_max == 0 || - stack[i] != stack_pattern[i%sizeof(stack_pattern)]) + if (ret->stack_max == 0) + break; + assert(stack_lo <= &stack[i] && &stack[i] < stack_hi); +#if CONFIG_COROUTINE_VALGRIND + VALGRIND_DISABLE_ERROR_REPORTING; +#endif + uint8_t v = stack[i]; +#if CONFIG_COROUTINE_VALGRIND + VALGRIND_ENABLE_ERROR_REPORTING; +#endif + if (v != stack_pattern[i%sizeof(stack_pattern)]) break; ret->stack_max--; } @@ -822,12 +848,17 @@ void cr_cid_info(cid_t cid, struct cr_cid_info *ret) { else sp = cr_plat_setjmp_get_sp(&coroutine_table[cid-1].env); assert(sp); - uintptr_t sb = (uintptr_t)coroutine_table[cid-1].stack; #if CR_PLAT_STACK_GROWS_DOWNWARD - ret->stack_cur = (sb - CR_STACK_GUARD_SIZE) - sp; + uintptr_t sb = (uintptr_t)stack_hi; + ret->stack_cur = sb - sp; #else - ret->stack_cur = sp - (sb + CR_STACK_GUARD_SIZE); + uintptr_t sb = (uintptr_t)stack_lo; + ret->stack_cur = sp - sb; #endif +#endif /* CONFIG_COROUTINE_MEASURE_STACK */ } -#endif /* CONFIG_COROUTINE_MEASURE_STACK */ +const char *coroutine_state_str(enum coroutine_state state) { + assert(state < LM_ARRAY_LEN(coroutine_state_strs)); + return coroutine_state_strs[state]; +} diff --git a/libcr/include/libcr/coroutine.h b/libcr/include/libcr/coroutine.h index eb5828b..756352e 100644 --- a/libcr/include/libcr/coroutine.h +++ b/libcr/include/libcr/coroutine.h @@ -1,6 +1,6 @@ /* libcr/coroutine.h - Simple embeddable coroutine implementation * - * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> * SPDX-License-Identifier: AGPL-3.0-or-later */ @@ -29,6 +29,8 @@ #include <stddef.h> /* for size_t */ #include <stdbool.h> /* for bool */ +#include "config.h" + /* typedefs *******************************************************************/ /** @@ -187,13 +189,25 @@ void cr_assert_in_intrhandler(void); /* answering questions about coroutines ***************************************/ -/* While the following are defined here unconditionally, the - * implementations are #if'd on CONFIG_COROUTINE_MEASURE_STACK. */ +enum coroutine_state { + CR_NONE = 0, /* this slot in the table is empty */ + CR_INITIALIZING, /* running, before cr_begin() */ + CR_RUNNING, /* running, after cr_begin() */ + CR_RUNNABLE, /* not running, but runnable */ + CR_PAUSED, /* not running, and not runnable */ +}; + +const char *coroutine_state_str(enum coroutine_state); struct cr_cid_info { + enum coroutine_state state; + [[gnu::nonstring]] char name[CONFIG_COROUTINE_NAME_LEN]; + +#if CONFIG_COROUTINE_MEASURE_STACK size_t stack_cap; size_t stack_max; size_t stack_cur; +#endif }; void cr_cid_info(cid_t cid, struct cr_cid_info *ret); |