root / coroutine-gthread.c @ 7267c094
History | View | Annotate | Download (3.6 kB)
1 |
/*
|
---|---|
2 |
* GThread coroutine initialization code
|
3 |
*
|
4 |
* Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
|
5 |
* Copyright (C) 2011 Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
|
6 |
*
|
7 |
* This library is free software; you can redistribute it and/or
|
8 |
* modify it under the terms of the GNU Lesser General Public
|
9 |
* License as published by the Free Software Foundation; either
|
10 |
* version 2.0 of the License, or (at your option) any later version.
|
11 |
*
|
12 |
* This library is distributed in the hope that it will be useful,
|
13 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
15 |
* Lesser General Public License for more details.
|
16 |
*
|
17 |
* You should have received a copy of the GNU Lesser General Public
|
18 |
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
19 |
*/
|
20 |
|
21 |
#include <glib.h> |
22 |
#include "qemu-common.h" |
23 |
#include "qemu-coroutine-int.h" |
24 |
|
25 |
typedef struct { |
26 |
Coroutine base; |
27 |
GThread *thread; |
28 |
bool runnable;
|
29 |
CoroutineAction action; |
30 |
} CoroutineGThread; |
31 |
|
32 |
static GCond *coroutine_cond;
|
33 |
static GStaticMutex coroutine_lock = G_STATIC_MUTEX_INIT;
|
34 |
static GStaticPrivate coroutine_key = G_STATIC_PRIVATE_INIT;
|
35 |
|
36 |
static void __attribute__((constructor)) coroutine_init(void) |
37 |
{ |
38 |
if (!g_thread_supported()) {
|
39 |
g_thread_init(NULL);
|
40 |
} |
41 |
|
42 |
coroutine_cond = g_cond_new(); |
43 |
} |
44 |
|
45 |
static void coroutine_wait_runnable_locked(CoroutineGThread *co) |
46 |
{ |
47 |
while (!co->runnable) {
|
48 |
g_cond_wait(coroutine_cond, g_static_mutex_get_mutex(&coroutine_lock)); |
49 |
} |
50 |
} |
51 |
|
52 |
static void coroutine_wait_runnable(CoroutineGThread *co) |
53 |
{ |
54 |
g_static_mutex_lock(&coroutine_lock); |
55 |
coroutine_wait_runnable_locked(co); |
56 |
g_static_mutex_unlock(&coroutine_lock); |
57 |
} |
58 |
|
59 |
static gpointer coroutine_thread(gpointer opaque)
|
60 |
{ |
61 |
CoroutineGThread *co = opaque; |
62 |
|
63 |
g_static_private_set(&coroutine_key, co, NULL);
|
64 |
coroutine_wait_runnable(co); |
65 |
co->base.entry(co->base.entry_arg); |
66 |
qemu_coroutine_switch(&co->base, co->base.caller, COROUTINE_TERMINATE); |
67 |
return NULL; |
68 |
} |
69 |
|
70 |
Coroutine *qemu_coroutine_new(void)
|
71 |
{ |
72 |
CoroutineGThread *co; |
73 |
|
74 |
co = g_malloc0(sizeof(*co));
|
75 |
co->thread = g_thread_create_full(coroutine_thread, co, 0, TRUE, TRUE,
|
76 |
G_THREAD_PRIORITY_NORMAL, NULL);
|
77 |
if (!co->thread) {
|
78 |
g_free(co); |
79 |
return NULL; |
80 |
} |
81 |
return &co->base;
|
82 |
} |
83 |
|
84 |
void qemu_coroutine_delete(Coroutine *co_)
|
85 |
{ |
86 |
CoroutineGThread *co = DO_UPCAST(CoroutineGThread, base, co_); |
87 |
|
88 |
g_thread_join(co->thread); |
89 |
g_free(co); |
90 |
} |
91 |
|
92 |
CoroutineAction qemu_coroutine_switch(Coroutine *from_, |
93 |
Coroutine *to_, |
94 |
CoroutineAction action) |
95 |
{ |
96 |
CoroutineGThread *from = DO_UPCAST(CoroutineGThread, base, from_); |
97 |
CoroutineGThread *to = DO_UPCAST(CoroutineGThread, base, to_); |
98 |
|
99 |
g_static_mutex_lock(&coroutine_lock); |
100 |
from->runnable = false;
|
101 |
from->action = action; |
102 |
to->runnable = true;
|
103 |
to->action = action; |
104 |
g_cond_broadcast(coroutine_cond); |
105 |
|
106 |
if (action != COROUTINE_TERMINATE) {
|
107 |
coroutine_wait_runnable_locked(from); |
108 |
} |
109 |
g_static_mutex_unlock(&coroutine_lock); |
110 |
return from->action;
|
111 |
} |
112 |
|
113 |
Coroutine *qemu_coroutine_self(void)
|
114 |
{ |
115 |
CoroutineGThread *co = g_static_private_get(&coroutine_key); |
116 |
|
117 |
if (!co) {
|
118 |
co = g_malloc0(sizeof(*co));
|
119 |
co->runnable = true;
|
120 |
g_static_private_set(&coroutine_key, co, (GDestroyNotify)qemu_free); |
121 |
} |
122 |
|
123 |
return &co->base;
|
124 |
} |
125 |
|
126 |
bool qemu_in_coroutine(void) |
127 |
{ |
128 |
CoroutineGThread *co = g_static_private_get(&coroutine_key); |
129 |
|
130 |
return co && co->base.caller;
|
131 |
} |