Statistics
| Branch: | Revision:

root / qemu-coroutine.c @ feature-archipelago

History | View | Annotate | Download (3 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 70c60c08 Stefan Hajnoczi
    Coroutine *co = NULL;
34 40239784 Paolo Bonzini
35 70c60c08 Stefan Hajnoczi
    if (CONFIG_COROUTINE_POOL) {
36 70c60c08 Stefan Hajnoczi
        qemu_mutex_lock(&pool_lock);
37 70c60c08 Stefan Hajnoczi
        co = QSLIST_FIRST(&pool);
38 70c60c08 Stefan Hajnoczi
        if (co) {
39 70c60c08 Stefan Hajnoczi
            QSLIST_REMOVE_HEAD(&pool, pool_next);
40 70c60c08 Stefan Hajnoczi
            pool_size--;
41 70c60c08 Stefan Hajnoczi
        }
42 70c60c08 Stefan Hajnoczi
        qemu_mutex_unlock(&pool_lock);
43 b84c4586 Stefan Hajnoczi
    }
44 b84c4586 Stefan Hajnoczi
45 b84c4586 Stefan Hajnoczi
    if (!co) {
46 40239784 Paolo Bonzini
        co = qemu_coroutine_new();
47 40239784 Paolo Bonzini
    }
48 40239784 Paolo Bonzini
49 00dccaf1 Kevin Wolf
    co->entry = entry;
50 02ffb504 Stefan Hajnoczi
    QTAILQ_INIT(&co->co_queue_wakeup);
51 00dccaf1 Kevin Wolf
    return co;
52 00dccaf1 Kevin Wolf
}
53 00dccaf1 Kevin Wolf
54 40239784 Paolo Bonzini
static void coroutine_delete(Coroutine *co)
55 40239784 Paolo Bonzini
{
56 70c60c08 Stefan Hajnoczi
    if (CONFIG_COROUTINE_POOL) {
57 70c60c08 Stefan Hajnoczi
        qemu_mutex_lock(&pool_lock);
58 70c60c08 Stefan Hajnoczi
        if (pool_size < POOL_MAX_SIZE) {
59 70c60c08 Stefan Hajnoczi
            QSLIST_INSERT_HEAD(&pool, co, pool_next);
60 70c60c08 Stefan Hajnoczi
            co->caller = NULL;
61 70c60c08 Stefan Hajnoczi
            pool_size++;
62 70c60c08 Stefan Hajnoczi
            qemu_mutex_unlock(&pool_lock);
63 70c60c08 Stefan Hajnoczi
            return;
64 70c60c08 Stefan Hajnoczi
        }
65 b84c4586 Stefan Hajnoczi
        qemu_mutex_unlock(&pool_lock);
66 40239784 Paolo Bonzini
    }
67 40239784 Paolo Bonzini
68 40239784 Paolo Bonzini
    qemu_coroutine_delete(co);
69 40239784 Paolo Bonzini
}
70 40239784 Paolo Bonzini
71 b84c4586 Stefan Hajnoczi
static void __attribute__((constructor)) coroutine_pool_init(void)
72 b84c4586 Stefan Hajnoczi
{
73 b84c4586 Stefan Hajnoczi
    qemu_mutex_init(&pool_lock);
74 b84c4586 Stefan Hajnoczi
}
75 b84c4586 Stefan Hajnoczi
76 b84c4586 Stefan Hajnoczi
static void __attribute__((destructor)) coroutine_pool_cleanup(void)
77 40239784 Paolo Bonzini
{
78 40239784 Paolo Bonzini
    Coroutine *co;
79 40239784 Paolo Bonzini
    Coroutine *tmp;
80 40239784 Paolo Bonzini
81 40239784 Paolo Bonzini
    QSLIST_FOREACH_SAFE(co, &pool, pool_next, tmp) {
82 40239784 Paolo Bonzini
        QSLIST_REMOVE_HEAD(&pool, pool_next);
83 40239784 Paolo Bonzini
        qemu_coroutine_delete(co);
84 40239784 Paolo Bonzini
    }
85 b84c4586 Stefan Hajnoczi
86 b84c4586 Stefan Hajnoczi
    qemu_mutex_destroy(&pool_lock);
87 40239784 Paolo Bonzini
}
88 40239784 Paolo Bonzini
89 00dccaf1 Kevin Wolf
static void coroutine_swap(Coroutine *from, Coroutine *to)
90 00dccaf1 Kevin Wolf
{
91 00dccaf1 Kevin Wolf
    CoroutineAction ret;
92 00dccaf1 Kevin Wolf
93 00dccaf1 Kevin Wolf
    ret = qemu_coroutine_switch(from, to, COROUTINE_YIELD);
94 00dccaf1 Kevin Wolf
95 02ffb504 Stefan Hajnoczi
    qemu_co_queue_run_restart(to);
96 02ffb504 Stefan Hajnoczi
97 00dccaf1 Kevin Wolf
    switch (ret) {
98 00dccaf1 Kevin Wolf
    case COROUTINE_YIELD:
99 00dccaf1 Kevin Wolf
        return;
100 00dccaf1 Kevin Wolf
    case COROUTINE_TERMINATE:
101 00dccaf1 Kevin Wolf
        trace_qemu_coroutine_terminate(to);
102 40239784 Paolo Bonzini
        coroutine_delete(to);
103 00dccaf1 Kevin Wolf
        return;
104 00dccaf1 Kevin Wolf
    default:
105 00dccaf1 Kevin Wolf
        abort();
106 00dccaf1 Kevin Wolf
    }
107 00dccaf1 Kevin Wolf
}
108 00dccaf1 Kevin Wolf
109 00dccaf1 Kevin Wolf
void qemu_coroutine_enter(Coroutine *co, void *opaque)
110 00dccaf1 Kevin Wolf
{
111 00dccaf1 Kevin Wolf
    Coroutine *self = qemu_coroutine_self();
112 00dccaf1 Kevin Wolf
113 00dccaf1 Kevin Wolf
    trace_qemu_coroutine_enter(self, co, opaque);
114 00dccaf1 Kevin Wolf
115 00dccaf1 Kevin Wolf
    if (co->caller) {
116 00dccaf1 Kevin Wolf
        fprintf(stderr, "Co-routine re-entered recursively\n");
117 00dccaf1 Kevin Wolf
        abort();
118 00dccaf1 Kevin Wolf
    }
119 00dccaf1 Kevin Wolf
120 00dccaf1 Kevin Wolf
    co->caller = self;
121 00dccaf1 Kevin Wolf
    co->entry_arg = opaque;
122 00dccaf1 Kevin Wolf
    coroutine_swap(self, co);
123 00dccaf1 Kevin Wolf
}
124 00dccaf1 Kevin Wolf
125 00dccaf1 Kevin Wolf
void coroutine_fn qemu_coroutine_yield(void)
126 00dccaf1 Kevin Wolf
{
127 00dccaf1 Kevin Wolf
    Coroutine *self = qemu_coroutine_self();
128 00dccaf1 Kevin Wolf
    Coroutine *to = self->caller;
129 00dccaf1 Kevin Wolf
130 00dccaf1 Kevin Wolf
    trace_qemu_coroutine_yield(self, to);
131 00dccaf1 Kevin Wolf
132 00dccaf1 Kevin Wolf
    if (!to) {
133 00dccaf1 Kevin Wolf
        fprintf(stderr, "Co-routine is yielding to no one\n");
134 00dccaf1 Kevin Wolf
        abort();
135 00dccaf1 Kevin Wolf
    }
136 00dccaf1 Kevin Wolf
137 00dccaf1 Kevin Wolf
    self->caller = NULL;
138 00dccaf1 Kevin Wolf
    coroutine_swap(self, to);
139 00dccaf1 Kevin Wolf
}