xref: /openbmc/qemu/util/coroutine-windows.c (revision 6739825a)
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