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