Ruby 3.5.0dev (2025-01-10 revision 5fab31b15e32622c4b71d1d347a41937e9f9c212)
Context.h
1#ifndef COROUTINE_EMSCRIPTEN_CONTEXT_H
2#define COROUTINE_EMSCRIPTEN_CONTEXT_H 1
3
4/* An experimental coroutine wrapper for emscripten
5 * Contact on Yusuke Endoh if you encounter any problem about this
6 */
7
8#pragma once
9
10#include <assert.h>
11#include <stddef.h>
12#include <emscripten/fiber.h>
13
14#define COROUTINE __attribute__((noreturn)) void
15
16#if INTPTR_MAX <= INT32_MAX
17#define COROUTINE_LIMITED_ADDRESS_SPACE
18#endif
19
21
22typedef COROUTINE(* coroutine_start)(struct coroutine_context *from, struct coroutine_context *self);
23
25{
26 emscripten_fiber_t state;
27 coroutine_start entry_func;
28 struct coroutine_context * from;
29 void *argument;
30};
31
32COROUTINE coroutine_trampoline(void * _context);
33
34#define MAIN_ASYNCIFY_STACK_SIZE 65536
35static inline void coroutine_initialize_main(struct coroutine_context * context) {
36 static char asyncify_stack[MAIN_ASYNCIFY_STACK_SIZE];
37 emscripten_fiber_init_from_current_context(&context->state, asyncify_stack, MAIN_ASYNCIFY_STACK_SIZE);
38}
39#undef MAIN_ASYNCIFY_STACK_SIZE
40
41static inline void coroutine_initialize(
42 struct coroutine_context *context,
43 coroutine_start start,
44 void *stack,
45 size_t size
46) {
47 assert(start && stack && size >= 1024);
48
49 uintptr_t addr = (uintptr_t)stack;
50 size_t offset = addr & 0xF;
51 void *c_stack = (void*)((addr + 0xF) & ~0xF);
52 size -= offset;
53 size_t c_stack_size = (size / 2) & ~0xF;
54 void *asyncify_stack = (void*)((uintptr_t)c_stack + c_stack_size);
55 size_t asyncify_stack_size = size - c_stack_size;
56 context->entry_func = start;
57
58 emscripten_fiber_init(&context->state, coroutine_trampoline, context, c_stack, c_stack_size, asyncify_stack, asyncify_stack_size);
59}
60
61static inline struct coroutine_context * coroutine_transfer(struct coroutine_context * current, struct coroutine_context * target)
62{
63 struct coroutine_context * previous = target->from;
64
65 target->from = current;
66 emscripten_fiber_swap(&current->state, &target->state);
67 target->from = previous;
68
69 return target;
70}
71
72static inline void coroutine_destroy(struct coroutine_context * context)
73{
74 context->from = NULL;
75}
76
77#endif /* COROUTINE_EMSCRIPTEN_CONTEXT_H */