diff options
Diffstat (limited to 'coroutine/ucontext')
| -rw-r--r-- | coroutine/ucontext/Context.c | 23 | ||||
| -rw-r--r-- | coroutine/ucontext/Context.h | 79 |
2 files changed, 102 insertions, 0 deletions
diff --git a/coroutine/ucontext/Context.c b/coroutine/ucontext/Context.c new file mode 100644 index 0000000000..5d728d554d --- /dev/null +++ b/coroutine/ucontext/Context.c @@ -0,0 +1,23 @@ +/* + * 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. +*/ + +/* According to Solaris' ucontext.h, makecontext, etc. are removed in SUSv4. + * To enable the prototype declarations, we need to define __EXTENSIONS__. + */ +#if defined(__sun) && !defined(__EXTENSIONS__) +#define __EXTENSIONS__ +#endif + +#include "Context.h" + +void coroutine_trampoline(void * _start, void * _context) +{ + coroutine_start start = (coroutine_start)_start; + struct coroutine_context * context = _context; + + start(context->from, context); +} diff --git a/coroutine/ucontext/Context.h b/coroutine/ucontext/Context.h new file mode 100644 index 0000000000..d338d8de60 --- /dev/null +++ b/coroutine/ucontext/Context.h @@ -0,0 +1,79 @@ +#ifndef COROUTINE_UCONTEXT_CONTEXT_H +#define COROUTINE_UCONTEXT_CONTEXT_H 1 + +/* + * 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. +*/ + +#pragma once + +#include <assert.h> +#include <stddef.h> +#include <ucontext.h> + +#define COROUTINE __attribute__((noreturn)) void + +#ifdef HAVE_STDINT_H +#include <stdint.h> +#if INTPTR_MAX <= INT32_MAX +#define COROUTINE_LIMITED_ADDRESS_SPACE +#endif +#endif + +struct coroutine_context +{ + ucontext_t state; + struct coroutine_context * from; + void *argument; +}; + +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(¤t->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; +} + +#endif /* COROUTINE_UCONTEXT_CONTEXT_H */ |
