1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25#include "qemu/osdep.h"
26#include "qemu/coroutine_int.h"
27#include "qemu/coroutine-tls.h"
28
29typedef struct
30{
31 Coroutine base;
32
33 LPVOID fiber;
34 CoroutineAction action;
35} CoroutineWin32;
36
37QEMU_DEFINE_STATIC_CO_TLS(CoroutineWin32, leader);
38QEMU_DEFINE_STATIC_CO_TLS(Coroutine *, current);
39
40
41
42
43
44
45
46
47
48CoroutineAction __attribute__((noinline))
49qemu_coroutine_switch(Coroutine *from_, Coroutine *to_,
50 CoroutineAction action)
51{
52 CoroutineWin32 *from = DO_UPCAST(CoroutineWin32, base, from_);
53 CoroutineWin32 *to = DO_UPCAST(CoroutineWin32, base, to_);
54
55 set_current(to_);
56
57 to->action = action;
58 SwitchToFiber(to->fiber);
59 return from->action;
60}
61
62static void CALLBACK coroutine_trampoline(void *co_)
63{
64 Coroutine *co = co_;
65
66 while (true) {
67 co->entry(co->entry_arg);
68 qemu_coroutine_switch(co, co->caller, COROUTINE_TERMINATE);
69 }
70}
71
72Coroutine *qemu_coroutine_new(void)
73{
74 const size_t stack_size = COROUTINE_STACK_SIZE;
75 CoroutineWin32 *co;
76
77 co = g_malloc0(sizeof(*co));
78 co->fiber = CreateFiber(stack_size, coroutine_trampoline, &co->base);
79 return &co->base;
80}
81
82void qemu_coroutine_delete(Coroutine *co_)
83{
84 CoroutineWin32 *co = DO_UPCAST(CoroutineWin32, base, co_);
85
86 DeleteFiber(co->fiber);
87 g_free(co);
88}
89
90Coroutine *qemu_coroutine_self(void)
91{
92 Coroutine *current = get_current();
93
94 if (!current) {
95 CoroutineWin32 *leader = get_ptr_leader();
96
97 current = &leader->base;
98 set_current(current);
99 leader->fiber = ConvertThreadToFiber(NULL);
100 }
101 return current;
102}
103
104bool qemu_in_coroutine(void)
105{
106 Coroutine *current = get_current();
107
108 return current && current->caller;
109}
110