mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
[wasm] add coroutine/asyncify implementation
set the default coroutine_type as asyncify when wasi
This commit is contained in:
parent
7ee786388a
commit
a4b73f1ba8
Notes:
git
2022-01-19 11:19:45 +09:00
3 changed files with 102 additions and 0 deletions
|
@ -2624,6 +2624,9 @@ AS_CASE([$coroutine_type], [yes|''], [
|
|||
[*-emscripten*], [
|
||||
coroutine_type=emscripten
|
||||
],
|
||||
[*-wasi*], [
|
||||
coroutine_type=asyncify
|
||||
],
|
||||
[
|
||||
AC_CHECK_FUNCS([getcontext swapcontext makecontext],
|
||||
[coroutine_type=ucontext],
|
||||
|
|
10
coroutine/asyncify/Context.c
Normal file
10
coroutine/asyncify/Context.c
Normal file
|
@ -0,0 +1,10 @@
|
|||
#include "Context.h"
|
||||
|
||||
void coroutine_trampoline(void * _start, void * _context)
|
||||
{
|
||||
coroutine_start start = (coroutine_start)_start;
|
||||
struct coroutine_context * context = _context;
|
||||
rb_wasm_set_stack_pointer(context->current_sp);
|
||||
|
||||
start(context->from, context);
|
||||
}
|
89
coroutine/asyncify/Context.h
Normal file
89
coroutine/asyncify/Context.h
Normal file
|
@ -0,0 +1,89 @@
|
|||
#ifndef COROUTINE_ASYNCIFY_CONTEXT_H
|
||||
#define COROUTINE_ASYNCIFY_CONTEXT_H
|
||||
|
||||
/*
|
||||
This is a coroutine implementation based on Binaryen's Asyncify transformation for WebAssembly.
|
||||
|
||||
This implementation is built on low-level ucontext-like API in wasm/fiber.c
|
||||
This file is an adapter for the common coroutine interface and for stack manipulation.
|
||||
wasm/fiber.c doesn't take care of stack to avoid duplicate management with this adapter.
|
||||
|
||||
* See also: wasm/fiber.c
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include "wasm/asyncify.h"
|
||||
#include "wasm/machine.h"
|
||||
#include "wasm/fiber.h"
|
||||
|
||||
#define COROUTINE void __attribute__((__noreturn__))
|
||||
|
||||
static const int ASYNCIFY_CORO_DEBUG = 0;
|
||||
|
||||
struct coroutine_context
|
||||
{
|
||||
rb_wasm_fiber_context fc;
|
||||
void *argument;
|
||||
struct coroutine_context *from;
|
||||
|
||||
void *current_sp;
|
||||
void *stack_base;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
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)
|
||||
{
|
||||
if (ASYNCIFY_CORO_DEBUG) fprintf(stderr, "[%s] entry (context = %p)\n", __func__, context);
|
||||
// NULL fiber entry means it's the main fiber, and handled specially.
|
||||
rb_wasm_init_context(&context->fc, NULL, NULL, NULL);
|
||||
// mark the main fiber has already started
|
||||
context->fc.is_started = true;
|
||||
}
|
||||
|
||||
static inline void coroutine_initialize(struct coroutine_context *context, coroutine_start start, void *stack, size_t size)
|
||||
{
|
||||
if (ASYNCIFY_CORO_DEBUG) fprintf(stderr, "[%s] entry (context = %p, stack = %p ... %p)\n", __func__, context, stack, (char *)stack + size);
|
||||
rb_wasm_init_context(&context->fc, coroutine_trampoline, start, context);
|
||||
// record the initial stack pointer position to restore it after resumption
|
||||
context->current_sp = (char *)stack + size;
|
||||
context->stack_base = stack;
|
||||
context->size = size;
|
||||
}
|
||||
|
||||
static inline struct coroutine_context * coroutine_transfer(struct coroutine_context * current, struct coroutine_context * target)
|
||||
{
|
||||
if (ASYNCIFY_CORO_DEBUG) fprintf(stderr, "[%s] entry (current = %p, target = %p)\n", __func__, current, target);
|
||||
struct coroutine_context * previous = target->from;
|
||||
|
||||
target->from = current;
|
||||
if (ASYNCIFY_CORO_DEBUG) fprintf(stderr, "[%s] current->current_sp = %p -> %p\n", __func__, current->current_sp, rb_wasm_get_stack_pointer());
|
||||
// record the current stack pointer position to restore it after resumption
|
||||
current->current_sp = rb_wasm_get_stack_pointer();
|
||||
|
||||
// suspend the current coroutine and resume another coroutine
|
||||
|
||||
rb_wasm_swapcontext(¤t->fc, &target->fc);
|
||||
|
||||
// after the original coroutine resumed
|
||||
|
||||
rb_wasm_set_stack_pointer(current->current_sp);
|
||||
|
||||
target->from = previous;
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
static inline void coroutine_destroy(struct coroutine_context * context)
|
||||
{
|
||||
if (ASYNCIFY_CORO_DEBUG) fprintf(stderr, "[%s] entry (context = %p)\n", __func__, context);
|
||||
context->stack_base = NULL;
|
||||
context->size = 0;
|
||||
context->from = NULL;
|
||||
}
|
||||
|
||||
#endif /* COROUTINE_ASYNCIFY_CONTEXT_H */
|
Loading…
Reference in a new issue