]> Git Repo - qemu.git/blob - coroutine-gthread.c
usb-uhci: Use PCI DMA stub functions
[qemu.git] / coroutine-gthread.c
1 /*
2  * GThread coroutine initialization code
3  *
4  * Copyright (C) 2006  Anthony Liguori <[email protected]>
5  * Copyright (C) 2011  Aneesh Kumar K.V <[email protected]>
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)g_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 }
This page took 0.031275 seconds and 4 git commands to generate.