Statistics
| Branch: | Revision:

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
}