summaryrefslogtreecommitdiff
path: root/coroutine/ucontext/Context.h
diff options
context:
space:
mode:
authorSamuel Williams <samuel.williams@oriontransfer.co.nz>2019-06-24 23:54:19 +1200
committerSamuel Williams <samuel.williams@oriontransfer.co.nz>2019-06-26 20:19:53 +1200
commit6c6bf9ffcbfeb8be9d9c342e7604b74ec819e88a (patch)
treea611c21b4a3f2a0c4a1eb43a123f2865c7d4e491 /coroutine/ucontext/Context.h
parenta84a99ffabf04d90be64ff28cf2e11766f6cce52 (diff)
Add `ucontext` coroutine implementation for generic fallback.
Diffstat (limited to 'coroutine/ucontext/Context.h')
-rw-r--r--coroutine/ucontext/Context.h66
1 files changed, 66 insertions, 0 deletions
diff --git a/coroutine/ucontext/Context.h b/coroutine/ucontext/Context.h
new file mode 100644
index 0000000000..bde9be302a
--- /dev/null
+++ b/coroutine/ucontext/Context.h
@@ -0,0 +1,66 @@
+/*
+ * This file is part of the "Coroutine" project and released under the MIT License.
+ *
+ * Created by Samuel Williams on 24/6/2019.
+ * Copyright, 2019, by Samuel Williams. All rights reserved.
+*/
+
+#pragma once
+
+#include <assert.h>
+#include <stddef.h>
+#include <ucontext.h>
+
+#define COROUTINE __attribute__((noreturn)) void
+
+struct coroutine_context
+{
+ ucontext_t state;
+ struct coroutine_context * from;
+};
+
+typedef COROUTINE(* coroutine_start)(struct coroutine_context *from, struct coroutine_context *self);
+
+COROUTINE coroutine_trampoline(void * _start, void * _context);
+
+static inline void coroutine_initialize_main(struct coroutine_context * context) {
+ context->from = NULL;
+ getcontext(&context->state);
+}
+
+static inline void coroutine_initialize(
+ struct coroutine_context *context,
+ coroutine_start start,
+ void *stack,
+ size_t size
+) {
+ assert(start && stack && size >= 1024);
+
+ coroutine_initialize_main(context);
+
+ context->state.uc_stack.ss_size = size;
+ // Despite what it's called, this is not actually a stack pointer. It points to the address of the stack allocation (the lowest address).
+ context->state.uc_stack.ss_sp = (char*)stack;
+ context->state.uc_stack.ss_flags = 0;
+ context->state.uc_link = NULL;
+
+ makecontext(&context->state, (void(*)(void))coroutine_trampoline, 2, (void*)start, (void*)context);
+}
+
+static inline struct coroutine_context * coroutine_transfer(struct coroutine_context * current, struct coroutine_context * target)
+{
+ struct coroutine_context * previous = target->from;
+
+ target->from = current;
+ swapcontext(&current->state, &target->state);
+ target->from = previous;
+
+ return target;
+}
+
+static inline void coroutine_destroy(struct coroutine_context * context)
+{
+ context->state.uc_stack.ss_sp = NULL;
+ context->state.uc_stack.ss_size = 0;
+ context->from = NULL;
+}