1*6739825aSPaolo Bonzini /*
2*6739825aSPaolo Bonzini * Win32 coroutine initialization code
3*6739825aSPaolo Bonzini *
4*6739825aSPaolo Bonzini * Copyright (c) 2011 Kevin Wolf <kwolf@redhat.com>
5*6739825aSPaolo Bonzini *
6*6739825aSPaolo Bonzini * Permission is hereby granted, free of charge, to any person obtaining a copy
7*6739825aSPaolo Bonzini * of this software and associated documentation files (the "Software"), to deal
8*6739825aSPaolo Bonzini * in the Software without restriction, including without limitation the rights
9*6739825aSPaolo Bonzini * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10*6739825aSPaolo Bonzini * copies of the Software, and to permit persons to whom the Software is
11*6739825aSPaolo Bonzini * furnished to do so, subject to the following conditions:
12*6739825aSPaolo Bonzini *
13*6739825aSPaolo Bonzini * The above copyright notice and this permission notice shall be included in
14*6739825aSPaolo Bonzini * all copies or substantial portions of the Software.
15*6739825aSPaolo Bonzini *
16*6739825aSPaolo Bonzini * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17*6739825aSPaolo Bonzini * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18*6739825aSPaolo Bonzini * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19*6739825aSPaolo Bonzini * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20*6739825aSPaolo Bonzini * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21*6739825aSPaolo Bonzini * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22*6739825aSPaolo Bonzini * THE SOFTWARE.
23*6739825aSPaolo Bonzini */
24*6739825aSPaolo Bonzini
25*6739825aSPaolo Bonzini #include "qemu/osdep.h"
26*6739825aSPaolo Bonzini #include "qemu/coroutine_int.h"
27*6739825aSPaolo Bonzini #include "qemu/coroutine-tls.h"
28*6739825aSPaolo Bonzini
29*6739825aSPaolo Bonzini typedef struct
30*6739825aSPaolo Bonzini {
31*6739825aSPaolo Bonzini Coroutine base;
32*6739825aSPaolo Bonzini
33*6739825aSPaolo Bonzini LPVOID fiber;
34*6739825aSPaolo Bonzini CoroutineAction action;
35*6739825aSPaolo Bonzini } CoroutineWin32;
36*6739825aSPaolo Bonzini
37*6739825aSPaolo Bonzini QEMU_DEFINE_STATIC_CO_TLS(CoroutineWin32, leader);
38*6739825aSPaolo Bonzini QEMU_DEFINE_STATIC_CO_TLS(Coroutine *, current);
39*6739825aSPaolo Bonzini
40*6739825aSPaolo Bonzini /* This function is marked noinline to prevent GCC from inlining it
41*6739825aSPaolo Bonzini * into coroutine_trampoline(). If we allow it to do that then it
42*6739825aSPaolo Bonzini * hoists the code to get the address of the TLS variable "current"
43*6739825aSPaolo Bonzini * out of the while() loop. This is an invalid transformation because
44*6739825aSPaolo Bonzini * the SwitchToFiber() call may be called when running thread A but
45*6739825aSPaolo Bonzini * return in thread B, and so we might be in a different thread
46*6739825aSPaolo Bonzini * context each time round the loop.
47*6739825aSPaolo Bonzini */
48*6739825aSPaolo Bonzini CoroutineAction __attribute__((noinline))
qemu_coroutine_switch(Coroutine * from_,Coroutine * to_,CoroutineAction action)49*6739825aSPaolo Bonzini qemu_coroutine_switch(Coroutine *from_, Coroutine *to_,
50*6739825aSPaolo Bonzini CoroutineAction action)
51*6739825aSPaolo Bonzini {
52*6739825aSPaolo Bonzini CoroutineWin32 *from = DO_UPCAST(CoroutineWin32, base, from_);
53*6739825aSPaolo Bonzini CoroutineWin32 *to = DO_UPCAST(CoroutineWin32, base, to_);
54*6739825aSPaolo Bonzini
55*6739825aSPaolo Bonzini set_current(to_);
56*6739825aSPaolo Bonzini
57*6739825aSPaolo Bonzini to->action = action;
58*6739825aSPaolo Bonzini SwitchToFiber(to->fiber);
59*6739825aSPaolo Bonzini return from->action;
60*6739825aSPaolo Bonzini }
61*6739825aSPaolo Bonzini
coroutine_trampoline(void * co_)62*6739825aSPaolo Bonzini static void CALLBACK coroutine_trampoline(void *co_)
63*6739825aSPaolo Bonzini {
64*6739825aSPaolo Bonzini Coroutine *co = co_;
65*6739825aSPaolo Bonzini
66*6739825aSPaolo Bonzini while (true) {
67*6739825aSPaolo Bonzini co->entry(co->entry_arg);
68*6739825aSPaolo Bonzini qemu_coroutine_switch(co, co->caller, COROUTINE_TERMINATE);
69*6739825aSPaolo Bonzini }
70*6739825aSPaolo Bonzini }
71*6739825aSPaolo Bonzini
qemu_coroutine_new(void)72*6739825aSPaolo Bonzini Coroutine *qemu_coroutine_new(void)
73*6739825aSPaolo Bonzini {
74*6739825aSPaolo Bonzini const size_t stack_size = COROUTINE_STACK_SIZE;
75*6739825aSPaolo Bonzini CoroutineWin32 *co;
76*6739825aSPaolo Bonzini
77*6739825aSPaolo Bonzini co = g_malloc0(sizeof(*co));
78*6739825aSPaolo Bonzini co->fiber = CreateFiber(stack_size, coroutine_trampoline, &co->base);
79*6739825aSPaolo Bonzini return &co->base;
80*6739825aSPaolo Bonzini }
81*6739825aSPaolo Bonzini
qemu_coroutine_delete(Coroutine * co_)82*6739825aSPaolo Bonzini void qemu_coroutine_delete(Coroutine *co_)
83*6739825aSPaolo Bonzini {
84*6739825aSPaolo Bonzini CoroutineWin32 *co = DO_UPCAST(CoroutineWin32, base, co_);
85*6739825aSPaolo Bonzini
86*6739825aSPaolo Bonzini DeleteFiber(co->fiber);
87*6739825aSPaolo Bonzini g_free(co);
88*6739825aSPaolo Bonzini }
89*6739825aSPaolo Bonzini
qemu_coroutine_self(void)90*6739825aSPaolo Bonzini Coroutine *qemu_coroutine_self(void)
91*6739825aSPaolo Bonzini {
92*6739825aSPaolo Bonzini Coroutine *current = get_current();
93*6739825aSPaolo Bonzini
94*6739825aSPaolo Bonzini if (!current) {
95*6739825aSPaolo Bonzini CoroutineWin32 *leader = get_ptr_leader();
96*6739825aSPaolo Bonzini
97*6739825aSPaolo Bonzini current = &leader->base;
98*6739825aSPaolo Bonzini set_current(current);
99*6739825aSPaolo Bonzini leader->fiber = ConvertThreadToFiber(NULL);
100*6739825aSPaolo Bonzini }
101*6739825aSPaolo Bonzini return current;
102*6739825aSPaolo Bonzini }
103*6739825aSPaolo Bonzini
qemu_in_coroutine(void)104*6739825aSPaolo Bonzini bool qemu_in_coroutine(void)
105*6739825aSPaolo Bonzini {
106*6739825aSPaolo Bonzini Coroutine *current = get_current();
107*6739825aSPaolo Bonzini
108*6739825aSPaolo Bonzini return current && current->caller;
109*6739825aSPaolo Bonzini }
110