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 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 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 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 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 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 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