summaryrefslogtreecommitdiff
path: root/libcr/coroutine.c
diff options
context:
space:
mode:
Diffstat (limited to 'libcr/coroutine.c')
-rw-r--r--libcr/coroutine.c107
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);