summaryrefslogtreecommitdiff
path: root/wasm/fiber.c
diff options
context:
space:
mode:
authorYuta Saito <kateinoigakukun@gmail.com>2022-01-15 23:10:48 +0900
committerYuta Saito <kateinoigakukun@gmail.com>2022-01-19 11:19:06 +0900
commit65f95f26ff0e7b4be4704fedc52344a26d22a4e2 (patch)
treee4bd17869d8dd479855592f3a571aacae19e964c /wasm/fiber.c
parente41b121e94ccce9877824e55f865885bbabe40c3 (diff)
[wasm] add asyncify based setjmp, fiber, register scan emulation
configure.ac: setup build tools and register objects main.c: wrap main with rb_wasm_rt_start to handle asyncify unwinds tool/m4/ruby_wasm_tools.m4: setup default command based on WASI_SDK_PATH environment variable. checks wasm-opt which is used for asyncify. tool/wasm-clangw wasm/wasm-opt: a clang wrapper which replaces real wasm-opt with do-nothing wasm-opt to avoid misoptimization before asyncify. asyncify is performed at POSTLINK, but clang linker driver tries to run optimization by wasm-opt unconditionally. inlining pass at wasm level breaks asyncify's assumption, so should not optimize before POSTLIK. wasm/GNUmakefile.in: wasm specific rules to compile objects
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/5407
Diffstat (limited to 'wasm/fiber.c')
-rw-r--r--wasm/fiber.c83
1 files changed, 83 insertions, 0 deletions
diff --git a/wasm/fiber.c b/wasm/fiber.c
new file mode 100644
index 0000000000..ecc481b0ee
--- /dev/null
+++ b/wasm/fiber.c
@@ -0,0 +1,83 @@
+/*
+ This is a ucontext-like userland context switching API for WebAssembly based on Binaryen's Asyncify.
+
+ * NOTE:
+ * This mechanism doesn't take care of stack state. Just save and restore program counter and
+ * registers (rephrased as locals by Wasm term). So use-site need to save and restore the C stack pointer.
+ * This Asyncify based implementation is not much efficient and will be replaced with future stack-switching feature.
+ */
+
+#include <stdlib.h>
+#include "wasm/fiber.h"
+#include "wasm/asyncify.h"
+
+#ifdef RB_WASM_ENABLE_DEBUG_LOG
+# include <stdio.h>
+# define RB_WASM_DEBUG_LOG(...) fprintf(stderr, __VA_ARGS__)
+#else
+# define RB_WASM_DEBUG_LOG(...)
+#endif
+
+void
+rb_wasm_init_context(rb_wasm_fiber_context *fcp, void (*func)(void *, void *), void *arg0, void *arg1)
+{
+ fcp->asyncify_buf.top = &fcp->asyncify_buf.buffer[0];
+ fcp->asyncify_buf.end = &fcp->asyncify_buf.buffer[WASM_FIBER_STACK_BUFFER_SIZE];
+ fcp->is_rewinding = false;
+ fcp->is_started = false;
+ fcp->entry_point = func;
+ fcp->arg0 = arg0;
+ fcp->arg1 = arg1;
+ RB_WASM_DEBUG_LOG("[%s] fcp->asyncify_buf %p\n", __func__, &fcp->asyncify_buf);
+}
+
+static rb_wasm_fiber_context *_rb_wasm_active_next_fiber;
+
+void
+rb_wasm_swapcontext(rb_wasm_fiber_context *ofcp, rb_wasm_fiber_context *fcp)
+{
+ RB_WASM_DEBUG_LOG("[%s] enter ofcp = %p fcp = %p\n", __func__, ofcp, fcp);
+ if (ofcp->is_rewinding) {
+ asyncify_stop_rewind();
+ ofcp->is_rewinding = false;
+ return;
+ }
+ _rb_wasm_active_next_fiber = fcp;
+ RB_WASM_DEBUG_LOG("[%s] start unwinding asyncify_buf = %p\n", __func__, &ofcp->asyncify_buf);
+ asyncify_start_unwind(&ofcp->asyncify_buf);
+}
+
+void *
+rb_wasm_handle_fiber_unwind(void (**new_fiber_entry)(void *, void *),
+ void **arg0, void **arg1, bool *is_new_fiber_started)
+{
+ rb_wasm_fiber_context *next_fiber;
+ if (!_rb_wasm_active_next_fiber) {
+ RB_WASM_DEBUG_LOG("[%s] no next fiber\n", __func__);
+ *is_new_fiber_started = false;
+ return NULL;
+ }
+
+ next_fiber = _rb_wasm_active_next_fiber;
+ _rb_wasm_active_next_fiber = NULL;
+
+ RB_WASM_DEBUG_LOG("[%s] next_fiber->asyncify_buf = %p\n", __func__, &next_fiber->asyncify_buf);
+
+ *new_fiber_entry = next_fiber->entry_point;
+ *arg0 = next_fiber->arg0;
+ *arg1 = next_fiber->arg1;
+
+ if (!next_fiber->is_started) {
+ RB_WASM_DEBUG_LOG("[%s] new fiber started\n", __func__);
+ // start a new fiber if not started yet.
+ next_fiber->is_started = true;
+ *is_new_fiber_started = true;
+ return NULL;
+ } else {
+ RB_WASM_DEBUG_LOG("[%s] resume a fiber\n", __func__);
+ // resume a fiber again
+ next_fiber->is_rewinding = true;
+ *is_new_fiber_started = false;
+ return &next_fiber->asyncify_buf;
+ }
+}