Statistics
| Branch: | Revision:

root / qemu-coroutine.c @ f53ec699

History | View | Annotate | Download (2.9 kB)

1 00dccaf1 Kevin Wolf
/*
2 00dccaf1 Kevin Wolf
 * QEMU coroutines
3 00dccaf1 Kevin Wolf
 *
4 00dccaf1 Kevin Wolf
 * Copyright IBM, Corp. 2011
5 00dccaf1 Kevin Wolf
 *
6 00dccaf1 Kevin Wolf
 * Authors:
7 00dccaf1 Kevin Wolf
 *  Stefan Hajnoczi    <stefanha@linux.vnet.ibm.com>
8 00dccaf1 Kevin Wolf
 *  Kevin Wolf         <kwolf@redhat.com>
9 00dccaf1 Kevin Wolf
 *
10 00dccaf1 Kevin Wolf
 * This work is licensed under the terms of the GNU LGPL, version 2 or later.
11 00dccaf1 Kevin Wolf
 * See the COPYING.LIB file in the top-level directory.
12 00dccaf1 Kevin Wolf
 *
13 00dccaf1 Kevin Wolf
 */
14 00dccaf1 Kevin Wolf
15 00dccaf1 Kevin Wolf
#include "trace.h"
16 00dccaf1 Kevin Wolf
#include "qemu-common.h"
17 b84c4586 Stefan Hajnoczi
#include "qemu/thread.h"
18 737e150e Paolo Bonzini
#include "block/coroutine.h"
19 737e150e Paolo Bonzini
#include "block/coroutine_int.h"
20 00dccaf1 Kevin Wolf
21 40239784 Paolo Bonzini
enum {
22 40239784 Paolo Bonzini
    /* Maximum free pool size prevents holding too many freed coroutines */
23 40239784 Paolo Bonzini
    POOL_MAX_SIZE = 64,
24 40239784 Paolo Bonzini
};
25 40239784 Paolo Bonzini
26 40239784 Paolo Bonzini
/** Free list to speed up creation */
27 b84c4586 Stefan Hajnoczi
static QemuMutex pool_lock;
28 40239784 Paolo Bonzini
static QSLIST_HEAD(, Coroutine) pool = QSLIST_HEAD_INITIALIZER(pool);
29 40239784 Paolo Bonzini
static unsigned int pool_size;
30 40239784 Paolo Bonzini
31 00dccaf1 Kevin Wolf
Coroutine *qemu_coroutine_create(CoroutineEntry *entry)
32 00dccaf1 Kevin Wolf
{
33 40239784 Paolo Bonzini
    Coroutine *co;
34 40239784 Paolo Bonzini
35 b84c4586 Stefan Hajnoczi
    qemu_mutex_lock(&pool_lock);
36 40239784 Paolo Bonzini
    co = QSLIST_FIRST(&pool);
37 40239784 Paolo Bonzini
    if (co) {
38 40239784 Paolo Bonzini
        QSLIST_REMOVE_HEAD(&pool, pool_next);
39 40239784 Paolo Bonzini
        pool_size--;
40 b84c4586 Stefan Hajnoczi
    }
41 b84c4586 Stefan Hajnoczi
    qemu_mutex_unlock(&pool_lock);
42 b84c4586 Stefan Hajnoczi
43 b84c4586 Stefan Hajnoczi
    if (!co) {
44 40239784 Paolo Bonzini
        co = qemu_coroutine_new();
45 40239784 Paolo Bonzini
    }
46 40239784 Paolo Bonzini
47 00dccaf1 Kevin Wolf
    co->entry = entry;
48 02ffb504 Stefan Hajnoczi
    QTAILQ_INIT(&co->co_queue_wakeup);
49 00dccaf1 Kevin Wolf
    return co;
50 00dccaf1 Kevin Wolf
}
51 00dccaf1 Kevin Wolf
52 40239784 Paolo Bonzini
static void coroutine_delete(Coroutine *co)
53 40239784 Paolo Bonzini
{
54 b84c4586 Stefan Hajnoczi
    qemu_mutex_lock(&pool_lock);
55 40239784 Paolo Bonzini
    if (pool_size < POOL_MAX_SIZE) {
56 40239784 Paolo Bonzini
        QSLIST_INSERT_HEAD(&pool, co, pool_next);
57 40239784 Paolo Bonzini
        co->caller = NULL;
58 40239784 Paolo Bonzini
        pool_size++;
59 b84c4586 Stefan Hajnoczi
        qemu_mutex_unlock(&pool_lock);
60 40239784 Paolo Bonzini
        return;
61 40239784 Paolo Bonzini
    }
62 b84c4586 Stefan Hajnoczi
    qemu_mutex_unlock(&pool_lock);
63 40239784 Paolo Bonzini
64 40239784 Paolo Bonzini
    qemu_coroutine_delete(co);
65 40239784 Paolo Bonzini
}
66 40239784 Paolo Bonzini
67 b84c4586 Stefan Hajnoczi
static void __attribute__((constructor)) coroutine_pool_init(void)
68 b84c4586 Stefan Hajnoczi
{
69 b84c4586 Stefan Hajnoczi
    qemu_mutex_init(&pool_lock);
70 b84c4586 Stefan Hajnoczi
}
71 b84c4586 Stefan Hajnoczi
72 b84c4586 Stefan Hajnoczi
static void __attribute__((destructor)) coroutine_pool_cleanup(void)
73 40239784 Paolo Bonzini
{
74 40239784 Paolo Bonzini
    Coroutine *co;
75 40239784 Paolo Bonzini
    Coroutine *tmp;
76 40239784 Paolo Bonzini
77 40239784 Paolo Bonzini
    QSLIST_FOREACH_SAFE(co, &pool, pool_next, tmp) {
78 40239784 Paolo Bonzini
        QSLIST_REMOVE_HEAD(&pool, pool_next);
79 40239784 Paolo Bonzini
        qemu_coroutine_delete(co);
80 40239784 Paolo Bonzini
    }
81 b84c4586 Stefan Hajnoczi
82 b84c4586 Stefan Hajnoczi
    qemu_mutex_destroy(&pool_lock);
83 40239784 Paolo Bonzini
}
84 40239784 Paolo Bonzini
85 00dccaf1 Kevin Wolf
static void coroutine_swap(Coroutine *from, Coroutine *to)
86 00dccaf1 Kevin Wolf
{
87 00dccaf1 Kevin Wolf
    CoroutineAction ret;
88 00dccaf1 Kevin Wolf
89 00dccaf1 Kevin Wolf
    ret = qemu_coroutine_switch(from, to, COROUTINE_YIELD);
90 00dccaf1 Kevin Wolf
91 02ffb504 Stefan Hajnoczi
    qemu_co_queue_run_restart(to);
92 02ffb504 Stefan Hajnoczi
93 00dccaf1 Kevin Wolf
    switch (ret) {
94 00dccaf1 Kevin Wolf
    case COROUTINE_YIELD:
95 00dccaf1 Kevin Wolf
        return;
96 00dccaf1 Kevin Wolf
    case COROUTINE_TERMINATE:
97 00dccaf1 Kevin Wolf
        trace_qemu_coroutine_terminate(to);
98 40239784 Paolo Bonzini
        coroutine_delete(to);
99 00dccaf1 Kevin Wolf
        return;
100 00dccaf1 Kevin Wolf
    default:
101 00dccaf1 Kevin Wolf
        abort();
102 00dccaf1 Kevin Wolf
    }
103 00dccaf1 Kevin Wolf
}
104 00dccaf1 Kevin Wolf
105 00dccaf1 Kevin Wolf
void qemu_coroutine_enter(Coroutine *co, void *opaque)
106 00dccaf1 Kevin Wolf
{
107 00dccaf1 Kevin Wolf
    Coroutine *self = qemu_coroutine_self();
108 00dccaf1 Kevin Wolf
109 00dccaf1 Kevin Wolf
    trace_qemu_coroutine_enter(self, co, opaque);
110 00dccaf1 Kevin Wolf
111 00dccaf1 Kevin Wolf
    if (co->caller) {
112 00dccaf1 Kevin Wolf
        fprintf(stderr, "Co-routine re-entered recursively\n");
113 00dccaf1 Kevin Wolf
        abort();
114 00dccaf1 Kevin Wolf
    }
115 00dccaf1 Kevin Wolf
116 00dccaf1 Kevin Wolf
    co->caller = self;
117 00dccaf1 Kevin Wolf
    co->entry_arg = opaque;
118 00dccaf1 Kevin Wolf
    coroutine_swap(self, co);
119 00dccaf1 Kevin Wolf
}
120 00dccaf1 Kevin Wolf
121 00dccaf1 Kevin Wolf
void coroutine_fn qemu_coroutine_yield(void)
122 00dccaf1 Kevin Wolf
{
123 00dccaf1 Kevin Wolf
    Coroutine *self = qemu_coroutine_self();
124 00dccaf1 Kevin Wolf
    Coroutine *to = self->caller;
125 00dccaf1 Kevin Wolf
126 00dccaf1 Kevin Wolf
    trace_qemu_coroutine_yield(self, to);
127 00dccaf1 Kevin Wolf
128 00dccaf1 Kevin Wolf
    if (!to) {
129 00dccaf1 Kevin Wolf
        fprintf(stderr, "Co-routine is yielding to no one\n");
130 00dccaf1 Kevin Wolf
        abort();
131 00dccaf1 Kevin Wolf
    }
132 00dccaf1 Kevin Wolf
133 00dccaf1 Kevin Wolf
    self->caller = NULL;
134 00dccaf1 Kevin Wolf
    coroutine_swap(self, to);
135 00dccaf1 Kevin Wolf
}