ruby-changes:65016
From: Yusuke <ko1@a...>
Date: Sat, 23 Jan 2021 18:56:34 +0900 (JST)
Subject: [ruby-changes:65016] 62283f7a7a (master): coroutine/emscripten/: Experimentally support emscripten fiber API
https://git.ruby-lang.org/ruby.git/commit/?id=62283f7a7a From 62283f7a7a87fa2f353814a3ef6a3b1cab2a32b8 Mon Sep 17 00:00:00 2001 From: Yusuke Endoh <mame@r...> Date: Sat, 23 Jan 2021 18:54:50 +0900 Subject: coroutine/emscripten/: Experimentally support emscripten fiber API --- configure.ac | 6 +++- coroutine/emscripten/Context.c | 8 +++++ coroutine/emscripten/Context.h | 76 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 coroutine/emscripten/Context.c create mode 100644 coroutine/emscripten/Context.h diff --git a/configure.ac b/configure.ac index 05d3e99..285a2f9 100644 --- a/configure.ac +++ b/configure.ac @@ -1138,7 +1138,8 @@ main() https://github.com/ruby/ruby/blob/trunk/configure.ac#L1138 ]) ], [emscripten*], [LIBS="-lm -lc $LIBS" - RUBY_APPEND_OPTIONS(LDFLAGS, -s ALLOW_MEMORY_GROWTH=1) + RUBY_APPEND_OPTIONS(LDFLAGS, "-s ALLOW_MEMORY_GROWTH=1") + RUBY_APPEND_OPTIONS(LDFLAGS, "-s ASYNCIFY") ], [ LIBS="-lm $LIBS"]) : ${ORIG_LIBS=$LIBS} @@ -2461,6 +2462,9 @@ AS_CASE([$rb_cv_coroutine], [yes|''], [ https://github.com/ruby/ruby/blob/trunk/configure.ac#L2462 [*-haiku*], [ rb_cv_coroutine=copy ], + [*-emscripten*], [ + rb_cv_coroutine=emscripten + ], [ rb_cv_coroutine=ucontext ] diff --git a/coroutine/emscripten/Context.c b/coroutine/emscripten/Context.c new file mode 100644 index 0000000..75c088d --- /dev/null +++ b/coroutine/emscripten/Context.c @@ -0,0 +1,8 @@ https://github.com/ruby/ruby/blob/trunk/coroutine/emscripten/Context.c#L1 +#include "Context.h" + +void coroutine_trampoline(void * _context) +{ + struct coroutine_context * context = _context; + + context->entry_func(context->from, context); +} diff --git a/coroutine/emscripten/Context.h b/coroutine/emscripten/Context.h new file mode 100644 index 0000000..aefbb92 --- /dev/null +++ b/coroutine/emscripten/Context.h @@ -0,0 +1,76 @@ https://github.com/ruby/ruby/blob/trunk/coroutine/emscripten/Context.h#L1 +#ifndef COROUTINE_EMSCRIPTEN_CONTEXT_H +#define COROUTINE_EMSCRIPTEN_CONTEXT_H 1 + +/* An experimental coroutine wrapper for emscripten + * Contact on Yusuke Endoh if you encounter any problem about this + */ + +#pragma once + +#include <assert.h> +#include <stddef.h> +#include <emscripten/fiber.h> + +#define COROUTINE __attribute__((noreturn)) void + +#if INTPTR_MAX <= INT32_MAX +#define COROUTINE_LIMITED_ADDRESS_SPACE +#endif + +struct coroutine_context; + +typedef COROUTINE(* coroutine_start)(struct coroutine_context *from, struct coroutine_context *self); + +struct coroutine_context +{ + emscripten_fiber_t state; + coroutine_start entry_func; + struct coroutine_context * from; +}; + +COROUTINE coroutine_trampoline(void * _context); + +#define MAIN_ASYNCIFY_STACK_SIZE 65536 +static inline void coroutine_initialize_main(struct coroutine_context * context) { + static char asyncify_stack[MAIN_ASYNCIFY_STACK_SIZE]; + emscripten_fiber_init_from_current_context(&context->state, asyncify_stack, MAIN_ASYNCIFY_STACK_SIZE); +} +#undef MAIN_ASYNCIFY_STACK_SIZE + +static inline void coroutine_initialize( + struct coroutine_context *context, + coroutine_start start, + void *stack, + size_t size +) { + assert(start && stack && size >= 1024); + + uintptr_t addr = (uintptr_t)stack; + size_t offset = addr & 0xF; + void *c_stack = (void*)((addr + 0xF) & ~0xF); + size -= offset; + size_t c_stack_size = (size / 2) & ~0xF; + void *asyncify_stack = (void*)((uintptr_t)c_stack + c_stack_size); + size_t asyncify_stack_size = size - c_stack_size; + context->entry_func = start; + + emscripten_fiber_init(&context->state, coroutine_trampoline, context, c_stack, c_stack_size, asyncify_stack, asyncify_stack_size); +} + +static inline struct coroutine_context * coroutine_transfer(struct coroutine_context * current, struct coroutine_context * target) +{ + struct coroutine_context * previous = target->from; + + target->from = current; + emscripten_fiber_swap(¤t->state, &target->state); + target->from = previous; + + return target; +} + +static inline void coroutine_destroy(struct coroutine_context * context) +{ + context->from = NULL; +} + +#endif /* COROUTINE_EMSCRIPTEN_CONTEXT_H */ -- cgit v1.1 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/