Statistics
| Branch: | Revision:

root / qemu-coroutine.c @ feature-archipelago

History | View | Annotate | Download (3 kB)

1
/*
2
 * QEMU coroutines
3
 *
4
 * Copyright IBM, Corp. 2011
5
 *
6
 * Authors:
7
 *  Stefan Hajnoczi    <stefanha@linux.vnet.ibm.com>
8
 *  Kevin Wolf         <kwolf@redhat.com>
9
 *
10
 * This work is licensed under the terms of the GNU LGPL, version 2 or later.
11
 * See the COPYING.LIB file in the top-level directory.
12
 *
13
 */
14

    
15
#include "trace.h"
16
#include "qemu-common.h"
17
#include "qemu/thread.h"
18
#include "block/coroutine.h"
19
#include "block/coroutine_int.h"
20

    
21
enum {
22
    /* Maximum free pool size prevents holding too many freed coroutines */
23
    POOL_MAX_SIZE = 64,
24
};
25

    
26
/** Free list to speed up creation */
27
static QemuMutex pool_lock;
28
static QSLIST_HEAD(, Coroutine) pool = QSLIST_HEAD_INITIALIZER(pool);
29
static unsigned int pool_size;
30

    
31
Coroutine *qemu_coroutine_create(CoroutineEntry *entry)
32
{
33
    Coroutine *co = NULL;
34

    
35
    if (CONFIG_COROUTINE_POOL) {
36
        qemu_mutex_lock(&pool_lock);
37
        co = QSLIST_FIRST(&pool);
38
        if (co) {
39
            QSLIST_REMOVE_HEAD(&pool, pool_next);
40
            pool_size--;
41
        }
42
        qemu_mutex_unlock(&pool_lock);
43
    }
44

    
45
    if (!co) {
46
        co = qemu_coroutine_new();
47
    }
48

    
49
    co->entry = entry;
50
    QTAILQ_INIT(&co->co_queue_wakeup);
51
    return co;
52
}
53

    
54
static void coroutine_delete(Coroutine *co)
55
{
56
    if (CONFIG_COROUTINE_POOL) {
57
        qemu_mutex_lock(&pool_lock);
58
        if (pool_size < POOL_MAX_SIZE) {
59
            QSLIST_INSERT_HEAD(&pool, co, pool_next);
60
            co->caller = NULL;
61
            pool_size++;
62
            qemu_mutex_unlock(&pool_lock);
63
            return;
64
        }
65
        qemu_mutex_unlock(&pool_lock);
66
    }
67

    
68
    qemu_coroutine_delete(co);
69
}
70

    
71
static void __attribute__((constructor)) coroutine_pool_init(void)
72
{
73
    qemu_mutex_init(&pool_lock);
74
}
75

    
76
static void __attribute__((destructor)) coroutine_pool_cleanup(void)
77
{
78
    Coroutine *co;
79
    Coroutine *tmp;
80

    
81
    QSLIST_FOREACH_SAFE(co, &pool, pool_next, tmp) {
82
        QSLIST_REMOVE_HEAD(&pool, pool_next);
83
        qemu_coroutine_delete(co);
84
    }
85

    
86
    qemu_mutex_destroy(&pool_lock);
87
}
88

    
89
static void coroutine_swap(Coroutine *from, Coroutine *to)
90
{
91
    CoroutineAction ret;
92

    
93
    ret = qemu_coroutine_switch(from, to, COROUTINE_YIELD);
94

    
95
    qemu_co_queue_run_restart(to);
96

    
97
    switch (ret) {
98
    case COROUTINE_YIELD:
99
        return;
100
    case COROUTINE_TERMINATE:
101
        trace_qemu_coroutine_terminate(to);
102
        coroutine_delete(to);
103
        return;
104
    default:
105
        abort();
106
    }
107
}
108

    
109
void qemu_coroutine_enter(Coroutine *co, void *opaque)
110
{
111
    Coroutine *self = qemu_coroutine_self();
112

    
113
    trace_qemu_coroutine_enter(self, co, opaque);
114

    
115
    if (co->caller) {
116
        fprintf(stderr, "Co-routine re-entered recursively\n");
117
        abort();
118
    }
119

    
120
    co->caller = self;
121
    co->entry_arg = opaque;
122
    coroutine_swap(self, co);
123
}
124

    
125
void coroutine_fn qemu_coroutine_yield(void)
126
{
127
    Coroutine *self = qemu_coroutine_self();
128
    Coroutine *to = self->caller;
129

    
130
    trace_qemu_coroutine_yield(self, to);
131

    
132
    if (!to) {
133
        fprintf(stderr, "Co-routine is yielding to no one\n");
134
        abort();
135
    }
136

    
137
    self->caller = NULL;
138
    coroutine_swap(self, to);
139
}