xref: /openbmc/qemu/util/coroutine-wasm.c (revision c5f122fdcc280a82e7c5f31de890f985aa7ba773)
1*5b78d120SKohei Tokunaga /*
2*5b78d120SKohei Tokunaga  * emscripten fiber coroutine initialization code
3*5b78d120SKohei Tokunaga  * based on coroutine-ucontext.c
4*5b78d120SKohei Tokunaga  *
5*5b78d120SKohei Tokunaga  * Copyright (C) 2006  Anthony Liguori <anthony@codemonkey.ws>
6*5b78d120SKohei Tokunaga  * Copyright (C) 2011  Kevin Wolf <kwolf@redhat.com>
7*5b78d120SKohei Tokunaga  *
8*5b78d120SKohei Tokunaga  * This library is free software; you can redistribute it and/or
9*5b78d120SKohei Tokunaga  * modify it under the terms of the GNU Lesser General Public
10*5b78d120SKohei Tokunaga  * License as published by the Free Software Foundation; either
11*5b78d120SKohei Tokunaga  * version 2.0 of the License, or (at your option) any later version.
12*5b78d120SKohei Tokunaga  *
13*5b78d120SKohei Tokunaga  * This library is distributed in the hope that it will be useful,
14*5b78d120SKohei Tokunaga  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15*5b78d120SKohei Tokunaga  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16*5b78d120SKohei Tokunaga  * Lesser General Public License for more details.
17*5b78d120SKohei Tokunaga  *
18*5b78d120SKohei Tokunaga  * You should have received a copy of the GNU Lesser General Public
19*5b78d120SKohei Tokunaga  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
20*5b78d120SKohei Tokunaga  */
21*5b78d120SKohei Tokunaga 
22*5b78d120SKohei Tokunaga #include "qemu/osdep.h"
23*5b78d120SKohei Tokunaga #include "qemu/coroutine_int.h"
24*5b78d120SKohei Tokunaga #include "qemu/coroutine-tls.h"
25*5b78d120SKohei Tokunaga 
26*5b78d120SKohei Tokunaga #include <emscripten/fiber.h>
27*5b78d120SKohei Tokunaga 
28*5b78d120SKohei Tokunaga typedef struct {
29*5b78d120SKohei Tokunaga     Coroutine base;
30*5b78d120SKohei Tokunaga     void *stack;
31*5b78d120SKohei Tokunaga     size_t stack_size;
32*5b78d120SKohei Tokunaga 
33*5b78d120SKohei Tokunaga     void *asyncify_stack;
34*5b78d120SKohei Tokunaga     size_t asyncify_stack_size;
35*5b78d120SKohei Tokunaga 
36*5b78d120SKohei Tokunaga     CoroutineAction action;
37*5b78d120SKohei Tokunaga 
38*5b78d120SKohei Tokunaga     emscripten_fiber_t fiber;
39*5b78d120SKohei Tokunaga } CoroutineEmscripten;
40*5b78d120SKohei Tokunaga 
41*5b78d120SKohei Tokunaga /**
42*5b78d120SKohei Tokunaga  * Per-thread coroutine bookkeeping
43*5b78d120SKohei Tokunaga  */
44*5b78d120SKohei Tokunaga QEMU_DEFINE_STATIC_CO_TLS(Coroutine *, current);
45*5b78d120SKohei Tokunaga QEMU_DEFINE_STATIC_CO_TLS(CoroutineEmscripten *, leader);
46*5b78d120SKohei Tokunaga size_t leader_asyncify_stack_size = COROUTINE_STACK_SIZE;
47*5b78d120SKohei Tokunaga 
coroutine_trampoline(void * co_)48*5b78d120SKohei Tokunaga static void coroutine_trampoline(void *co_)
49*5b78d120SKohei Tokunaga {
50*5b78d120SKohei Tokunaga     Coroutine *co = co_;
51*5b78d120SKohei Tokunaga 
52*5b78d120SKohei Tokunaga     while (true) {
53*5b78d120SKohei Tokunaga         co->entry(co->entry_arg);
54*5b78d120SKohei Tokunaga         qemu_coroutine_switch(co, co->caller, COROUTINE_TERMINATE);
55*5b78d120SKohei Tokunaga     }
56*5b78d120SKohei Tokunaga }
57*5b78d120SKohei Tokunaga 
qemu_coroutine_new(void)58*5b78d120SKohei Tokunaga Coroutine *qemu_coroutine_new(void)
59*5b78d120SKohei Tokunaga {
60*5b78d120SKohei Tokunaga     CoroutineEmscripten *co;
61*5b78d120SKohei Tokunaga 
62*5b78d120SKohei Tokunaga     co = g_malloc0(sizeof(*co));
63*5b78d120SKohei Tokunaga 
64*5b78d120SKohei Tokunaga     co->stack_size = COROUTINE_STACK_SIZE;
65*5b78d120SKohei Tokunaga     co->stack = qemu_alloc_stack(&co->stack_size);
66*5b78d120SKohei Tokunaga 
67*5b78d120SKohei Tokunaga     co->asyncify_stack_size = COROUTINE_STACK_SIZE;
68*5b78d120SKohei Tokunaga     co->asyncify_stack = g_malloc0(co->asyncify_stack_size);
69*5b78d120SKohei Tokunaga     emscripten_fiber_init(&co->fiber, coroutine_trampoline, &co->base,
70*5b78d120SKohei Tokunaga                           co->stack, co->stack_size, co->asyncify_stack,
71*5b78d120SKohei Tokunaga                           co->asyncify_stack_size);
72*5b78d120SKohei Tokunaga 
73*5b78d120SKohei Tokunaga     return &co->base;
74*5b78d120SKohei Tokunaga }
75*5b78d120SKohei Tokunaga 
qemu_coroutine_delete(Coroutine * co_)76*5b78d120SKohei Tokunaga void qemu_coroutine_delete(Coroutine *co_)
77*5b78d120SKohei Tokunaga {
78*5b78d120SKohei Tokunaga     CoroutineEmscripten *co = DO_UPCAST(CoroutineEmscripten, base, co_);
79*5b78d120SKohei Tokunaga 
80*5b78d120SKohei Tokunaga     qemu_free_stack(co->stack, co->stack_size);
81*5b78d120SKohei Tokunaga     g_free(co->asyncify_stack);
82*5b78d120SKohei Tokunaga     g_free(co);
83*5b78d120SKohei Tokunaga }
84*5b78d120SKohei Tokunaga 
qemu_coroutine_switch(Coroutine * from_,Coroutine * to_,CoroutineAction action)85*5b78d120SKohei Tokunaga CoroutineAction qemu_coroutine_switch(Coroutine *from_, Coroutine *to_,
86*5b78d120SKohei Tokunaga                       CoroutineAction action)
87*5b78d120SKohei Tokunaga {
88*5b78d120SKohei Tokunaga     CoroutineEmscripten *from = DO_UPCAST(CoroutineEmscripten, base, from_);
89*5b78d120SKohei Tokunaga     CoroutineEmscripten *to = DO_UPCAST(CoroutineEmscripten, base, to_);
90*5b78d120SKohei Tokunaga 
91*5b78d120SKohei Tokunaga     set_current(to_);
92*5b78d120SKohei Tokunaga     to->action = action;
93*5b78d120SKohei Tokunaga     emscripten_fiber_swap(&from->fiber, &to->fiber);
94*5b78d120SKohei Tokunaga     return from->action;
95*5b78d120SKohei Tokunaga }
96*5b78d120SKohei Tokunaga 
qemu_coroutine_self(void)97*5b78d120SKohei Tokunaga Coroutine *qemu_coroutine_self(void)
98*5b78d120SKohei Tokunaga {
99*5b78d120SKohei Tokunaga     Coroutine *self = get_current();
100*5b78d120SKohei Tokunaga 
101*5b78d120SKohei Tokunaga     if (!self) {
102*5b78d120SKohei Tokunaga         CoroutineEmscripten *leaderp = get_leader();
103*5b78d120SKohei Tokunaga         if (!leaderp) {
104*5b78d120SKohei Tokunaga             leaderp = g_malloc0(sizeof(*leaderp));
105*5b78d120SKohei Tokunaga             leaderp->asyncify_stack = g_malloc0(leader_asyncify_stack_size);
106*5b78d120SKohei Tokunaga             leaderp->asyncify_stack_size = leader_asyncify_stack_size;
107*5b78d120SKohei Tokunaga             emscripten_fiber_init_from_current_context(
108*5b78d120SKohei Tokunaga                 &leaderp->fiber,
109*5b78d120SKohei Tokunaga                 leaderp->asyncify_stack,
110*5b78d120SKohei Tokunaga                 leaderp->asyncify_stack_size);
111*5b78d120SKohei Tokunaga             leaderp->stack = leaderp->fiber.stack_limit;
112*5b78d120SKohei Tokunaga             leaderp->stack_size =
113*5b78d120SKohei Tokunaga                 leaderp->fiber.stack_base - leaderp->fiber.stack_limit;
114*5b78d120SKohei Tokunaga             set_leader(leaderp);
115*5b78d120SKohei Tokunaga         }
116*5b78d120SKohei Tokunaga         self = &leaderp->base;
117*5b78d120SKohei Tokunaga         set_current(self);
118*5b78d120SKohei Tokunaga     }
119*5b78d120SKohei Tokunaga     return self;
120*5b78d120SKohei Tokunaga }
121*5b78d120SKohei Tokunaga 
qemu_in_coroutine(void)122*5b78d120SKohei Tokunaga bool qemu_in_coroutine(void)
123*5b78d120SKohei Tokunaga {
124*5b78d120SKohei Tokunaga     Coroutine *self = get_current();
125*5b78d120SKohei Tokunaga 
126*5b78d120SKohei Tokunaga     return self && self->caller;
127*5b78d120SKohei Tokunaga }
128