Statistics
| Branch: | Revision:

root / qemu-coroutine.c @ a8aec295

History | View | Annotate | Download (2.9 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;
34

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

    
43
    if (!co) {
44
        co = qemu_coroutine_new();
45
    }
46

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

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

    
64
    qemu_coroutine_delete(co);
65
}
66

    
67
static void __attribute__((constructor)) coroutine_pool_init(void)
68
{
69
    qemu_mutex_init(&pool_lock);
70
}
71

    
72
static void __attribute__((destructor)) coroutine_pool_cleanup(void)
73
{
74
    Coroutine *co;
75
    Coroutine *tmp;
76

    
77
    QSLIST_FOREACH_SAFE(co, &pool, pool_next, tmp) {
78
        QSLIST_REMOVE_HEAD(&pool, pool_next);
79
        qemu_coroutine_delete(co);
80
    }
81

    
82
    qemu_mutex_destroy(&pool_lock);
83
}
84

    
85
static void coroutine_swap(Coroutine *from, Coroutine *to)
86
{
87
    CoroutineAction ret;
88

    
89
    ret = qemu_coroutine_switch(from, to, COROUTINE_YIELD);
90

    
91
    qemu_co_queue_run_restart(to);
92

    
93
    switch (ret) {
94
    case COROUTINE_YIELD:
95
        return;
96
    case COROUTINE_TERMINATE:
97
        trace_qemu_coroutine_terminate(to);
98
        coroutine_delete(to);
99
        return;
100
    default:
101
        abort();
102
    }
103
}
104

    
105
void qemu_coroutine_enter(Coroutine *co, void *opaque)
106
{
107
    Coroutine *self = qemu_coroutine_self();
108

    
109
    trace_qemu_coroutine_enter(self, co, opaque);
110

    
111
    if (co->caller) {
112
        fprintf(stderr, "Co-routine re-entered recursively\n");
113
        abort();
114
    }
115

    
116
    co->caller = self;
117
    co->entry_arg = opaque;
118
    coroutine_swap(self, co);
119
}
120

    
121
void coroutine_fn qemu_coroutine_yield(void)
122
{
123
    Coroutine *self = qemu_coroutine_self();
124
    Coroutine *to = self->caller;
125

    
126
    trace_qemu_coroutine_yield(self, to);
127

    
128
    if (!to) {
129
        fprintf(stderr, "Co-routine is yielding to no one\n");
130
        abort();
131
    }
132

    
133
    self->caller = NULL;
134
    coroutine_swap(self, to);
135
}