2 This is a ucontext-like userland context switching API for WebAssembly based on Binaryen's Asyncify.
5 * This mechanism doesn't take care of stack state. Just save and restore program counter and
6 * registers (rephrased as locals by Wasm term). So use-site need to save and restore the C stack pointer.
7 * This Asyncify based implementation is not much efficient and will be replaced with future stack-switching feature.
11 #include "wasm/fiber.h"
12 #include "wasm/asyncify.h"
14 #ifdef RB_WASM_ENABLE_DEBUG_LOG
16 # define RB_WASM_DEBUG_LOG(...) fprintf(stderr, __VA_ARGS__)
18 # define RB_WASM_DEBUG_LOG(...)
22 rb_wasm_init_context(rb_wasm_fiber_context
*fcp
, void (*func
)(void *, void *), void *arg0
, void *arg1
)
24 fcp
->asyncify_buf
.top
= &fcp
->asyncify_buf
.buffer
[0];
25 fcp
->asyncify_buf
.end
= &fcp
->asyncify_buf
.buffer
[WASM_FIBER_STACK_BUFFER_SIZE
];
26 fcp
->is_rewinding
= false;
27 fcp
->is_started
= false;
28 fcp
->entry_point
= func
;
31 RB_WASM_DEBUG_LOG("[%s] fcp->asyncify_buf %p\n", __func__
, &fcp
->asyncify_buf
);
34 static rb_wasm_fiber_context
*_rb_wasm_active_next_fiber
;
37 rb_wasm_swapcontext(rb_wasm_fiber_context
*ofcp
, rb_wasm_fiber_context
*fcp
)
39 RB_WASM_DEBUG_LOG("[%s] enter ofcp = %p fcp = %p\n", __func__
, ofcp
, fcp
);
40 if (ofcp
->is_rewinding
) {
41 asyncify_stop_rewind();
42 ofcp
->is_rewinding
= false;
45 _rb_wasm_active_next_fiber
= fcp
;
46 RB_WASM_DEBUG_LOG("[%s] start unwinding asyncify_buf = %p\n", __func__
, &ofcp
->asyncify_buf
);
47 asyncify_start_unwind(&ofcp
->asyncify_buf
);
51 rb_wasm_handle_fiber_unwind(void (**new_fiber_entry
)(void *, void *),
52 void **arg0
, void **arg1
, bool *is_new_fiber_started
)
54 rb_wasm_fiber_context
*next_fiber
;
55 if (!_rb_wasm_active_next_fiber
) {
56 RB_WASM_DEBUG_LOG("[%s] no next fiber\n", __func__
);
57 *is_new_fiber_started
= false;
61 next_fiber
= _rb_wasm_active_next_fiber
;
62 _rb_wasm_active_next_fiber
= NULL
;
64 RB_WASM_DEBUG_LOG("[%s] next_fiber->asyncify_buf = %p\n", __func__
, &next_fiber
->asyncify_buf
);
66 *new_fiber_entry
= next_fiber
->entry_point
;
67 *arg0
= next_fiber
->arg0
;
68 *arg1
= next_fiber
->arg1
;
70 if (!next_fiber
->is_started
) {
71 RB_WASM_DEBUG_LOG("[%s] new fiber started\n", __func__
);
72 // start a new fiber if not started yet.
73 next_fiber
->is_started
= true;
74 *is_new_fiber_started
= true;
77 RB_WASM_DEBUG_LOG("[%s] resume a fiber\n", __func__
);
78 // resume a fiber again
79 next_fiber
->is_rewinding
= true;
80 *is_new_fiber_started
= false;
81 return &next_fiber
->asyncify_buf
;