Statistics
| Branch: | Revision:

root / qemu-coroutine-lock.c @ eb3fedf3

History | View | Annotate | Download (4.7 kB)

1 b96e9247 Kevin Wolf
/*
2 b96e9247 Kevin Wolf
 * coroutine queues and locks
3 b96e9247 Kevin Wolf
 *
4 b96e9247 Kevin Wolf
 * Copyright (c) 2011 Kevin Wolf <kwolf@redhat.com>
5 b96e9247 Kevin Wolf
 *
6 b96e9247 Kevin Wolf
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 b96e9247 Kevin Wolf
 * of this software and associated documentation files (the "Software"), to deal
8 b96e9247 Kevin Wolf
 * in the Software without restriction, including without limitation the rights
9 b96e9247 Kevin Wolf
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 b96e9247 Kevin Wolf
 * copies of the Software, and to permit persons to whom the Software is
11 b96e9247 Kevin Wolf
 * furnished to do so, subject to the following conditions:
12 b96e9247 Kevin Wolf
 *
13 b96e9247 Kevin Wolf
 * The above copyright notice and this permission notice shall be included in
14 b96e9247 Kevin Wolf
 * all copies or substantial portions of the Software.
15 b96e9247 Kevin Wolf
 *
16 b96e9247 Kevin Wolf
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 b96e9247 Kevin Wolf
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 b96e9247 Kevin Wolf
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 b96e9247 Kevin Wolf
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 b96e9247 Kevin Wolf
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 b96e9247 Kevin Wolf
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 b96e9247 Kevin Wolf
 * THE SOFTWARE.
23 b96e9247 Kevin Wolf
 */
24 b96e9247 Kevin Wolf
25 b96e9247 Kevin Wolf
#include "qemu-common.h"
26 737e150e Paolo Bonzini
#include "block/coroutine.h"
27 737e150e Paolo Bonzini
#include "block/coroutine_int.h"
28 1de7afc9 Paolo Bonzini
#include "qemu/queue.h"
29 b96e9247 Kevin Wolf
#include "trace.h"
30 b96e9247 Kevin Wolf
31 b96e9247 Kevin Wolf
void qemu_co_queue_init(CoQueue *queue)
32 b96e9247 Kevin Wolf
{
33 b96e9247 Kevin Wolf
    QTAILQ_INIT(&queue->entries);
34 b96e9247 Kevin Wolf
}
35 b96e9247 Kevin Wolf
36 b96e9247 Kevin Wolf
void coroutine_fn qemu_co_queue_wait(CoQueue *queue)
37 b96e9247 Kevin Wolf
{
38 b96e9247 Kevin Wolf
    Coroutine *self = qemu_coroutine_self();
39 b96e9247 Kevin Wolf
    QTAILQ_INSERT_TAIL(&queue->entries, self, co_queue_next);
40 b96e9247 Kevin Wolf
    qemu_coroutine_yield();
41 b96e9247 Kevin Wolf
    assert(qemu_in_coroutine());
42 b96e9247 Kevin Wolf
}
43 b96e9247 Kevin Wolf
44 e9e6295b Zhi Yong Wu
void coroutine_fn qemu_co_queue_wait_insert_head(CoQueue *queue)
45 e9e6295b Zhi Yong Wu
{
46 e9e6295b Zhi Yong Wu
    Coroutine *self = qemu_coroutine_self();
47 e9e6295b Zhi Yong Wu
    QTAILQ_INSERT_HEAD(&queue->entries, self, co_queue_next);
48 e9e6295b Zhi Yong Wu
    qemu_coroutine_yield();
49 e9e6295b Zhi Yong Wu
    assert(qemu_in_coroutine());
50 e9e6295b Zhi Yong Wu
}
51 e9e6295b Zhi Yong Wu
52 02ffb504 Stefan Hajnoczi
/**
53 02ffb504 Stefan Hajnoczi
 * qemu_co_queue_run_restart:
54 02ffb504 Stefan Hajnoczi
 *
55 02ffb504 Stefan Hajnoczi
 * Enter each coroutine that was previously marked for restart by
56 02ffb504 Stefan Hajnoczi
 * qemu_co_queue_next() or qemu_co_queue_restart_all().  This function is
57 02ffb504 Stefan Hajnoczi
 * invoked by the core coroutine code when the current coroutine yields or
58 02ffb504 Stefan Hajnoczi
 * terminates.
59 02ffb504 Stefan Hajnoczi
 */
60 02ffb504 Stefan Hajnoczi
void qemu_co_queue_run_restart(Coroutine *co)
61 02ffb504 Stefan Hajnoczi
{
62 02ffb504 Stefan Hajnoczi
    Coroutine *next;
63 02ffb504 Stefan Hajnoczi
64 02ffb504 Stefan Hajnoczi
    trace_qemu_co_queue_run_restart(co);
65 02ffb504 Stefan Hajnoczi
    while ((next = QTAILQ_FIRST(&co->co_queue_wakeup))) {
66 02ffb504 Stefan Hajnoczi
        QTAILQ_REMOVE(&co->co_queue_wakeup, next, co_queue_next);
67 02ffb504 Stefan Hajnoczi
        qemu_coroutine_enter(next, NULL);
68 02ffb504 Stefan Hajnoczi
    }
69 02ffb504 Stefan Hajnoczi
}
70 02ffb504 Stefan Hajnoczi
71 28f08246 Stefan Hajnoczi
static bool qemu_co_queue_do_restart(CoQueue *queue, bool single)
72 b96e9247 Kevin Wolf
{
73 02ffb504 Stefan Hajnoczi
    Coroutine *self = qemu_coroutine_self();
74 b96e9247 Kevin Wolf
    Coroutine *next;
75 28f08246 Stefan Hajnoczi
76 28f08246 Stefan Hajnoczi
    if (QTAILQ_EMPTY(&queue->entries)) {
77 28f08246 Stefan Hajnoczi
        return false;
78 28f08246 Stefan Hajnoczi
    }
79 b96e9247 Kevin Wolf
80 28f08246 Stefan Hajnoczi
    while ((next = QTAILQ_FIRST(&queue->entries)) != NULL) {
81 b96e9247 Kevin Wolf
        QTAILQ_REMOVE(&queue->entries, next, co_queue_next);
82 02ffb504 Stefan Hajnoczi
        QTAILQ_INSERT_TAIL(&self->co_queue_wakeup, next, co_queue_next);
83 b96e9247 Kevin Wolf
        trace_qemu_co_queue_next(next);
84 28f08246 Stefan Hajnoczi
        if (single) {
85 28f08246 Stefan Hajnoczi
            break;
86 28f08246 Stefan Hajnoczi
        }
87 b96e9247 Kevin Wolf
    }
88 28f08246 Stefan Hajnoczi
    return true;
89 28f08246 Stefan Hajnoczi
}
90 b96e9247 Kevin Wolf
91 28f08246 Stefan Hajnoczi
bool qemu_co_queue_next(CoQueue *queue)
92 28f08246 Stefan Hajnoczi
{
93 28f08246 Stefan Hajnoczi
    return qemu_co_queue_do_restart(queue, true);
94 b96e9247 Kevin Wolf
}
95 b96e9247 Kevin Wolf
96 e8ee5e4c Stefan Hajnoczi
void qemu_co_queue_restart_all(CoQueue *queue)
97 e8ee5e4c Stefan Hajnoczi
{
98 28f08246 Stefan Hajnoczi
    qemu_co_queue_do_restart(queue, false);
99 e8ee5e4c Stefan Hajnoczi
}
100 e8ee5e4c Stefan Hajnoczi
101 b96e9247 Kevin Wolf
bool qemu_co_queue_empty(CoQueue *queue)
102 b96e9247 Kevin Wolf
{
103 b96e9247 Kevin Wolf
    return (QTAILQ_FIRST(&queue->entries) == NULL);
104 b96e9247 Kevin Wolf
}
105 b96e9247 Kevin Wolf
106 b96e9247 Kevin Wolf
void qemu_co_mutex_init(CoMutex *mutex)
107 b96e9247 Kevin Wolf
{
108 b96e9247 Kevin Wolf
    memset(mutex, 0, sizeof(*mutex));
109 b96e9247 Kevin Wolf
    qemu_co_queue_init(&mutex->queue);
110 b96e9247 Kevin Wolf
}
111 b96e9247 Kevin Wolf
112 b96e9247 Kevin Wolf
void coroutine_fn qemu_co_mutex_lock(CoMutex *mutex)
113 b96e9247 Kevin Wolf
{
114 b96e9247 Kevin Wolf
    Coroutine *self = qemu_coroutine_self();
115 b96e9247 Kevin Wolf
116 b96e9247 Kevin Wolf
    trace_qemu_co_mutex_lock_entry(mutex, self);
117 b96e9247 Kevin Wolf
118 b96e9247 Kevin Wolf
    while (mutex->locked) {
119 b96e9247 Kevin Wolf
        qemu_co_queue_wait(&mutex->queue);
120 b96e9247 Kevin Wolf
    }
121 b96e9247 Kevin Wolf
122 b96e9247 Kevin Wolf
    mutex->locked = true;
123 b96e9247 Kevin Wolf
124 b96e9247 Kevin Wolf
    trace_qemu_co_mutex_lock_return(mutex, self);
125 b96e9247 Kevin Wolf
}
126 b96e9247 Kevin Wolf
127 b96e9247 Kevin Wolf
void coroutine_fn qemu_co_mutex_unlock(CoMutex *mutex)
128 b96e9247 Kevin Wolf
{
129 b96e9247 Kevin Wolf
    Coroutine *self = qemu_coroutine_self();
130 b96e9247 Kevin Wolf
131 b96e9247 Kevin Wolf
    trace_qemu_co_mutex_unlock_entry(mutex, self);
132 b96e9247 Kevin Wolf
133 b96e9247 Kevin Wolf
    assert(mutex->locked == true);
134 b96e9247 Kevin Wolf
    assert(qemu_in_coroutine());
135 b96e9247 Kevin Wolf
136 b96e9247 Kevin Wolf
    mutex->locked = false;
137 b96e9247 Kevin Wolf
    qemu_co_queue_next(&mutex->queue);
138 b96e9247 Kevin Wolf
139 b96e9247 Kevin Wolf
    trace_qemu_co_mutex_unlock_return(mutex, self);
140 b96e9247 Kevin Wolf
}
141 12888904 Aneesh Kumar K.V
142 12888904 Aneesh Kumar K.V
void qemu_co_rwlock_init(CoRwlock *lock)
143 12888904 Aneesh Kumar K.V
{
144 12888904 Aneesh Kumar K.V
    memset(lock, 0, sizeof(*lock));
145 12888904 Aneesh Kumar K.V
    qemu_co_queue_init(&lock->queue);
146 12888904 Aneesh Kumar K.V
}
147 12888904 Aneesh Kumar K.V
148 12888904 Aneesh Kumar K.V
void qemu_co_rwlock_rdlock(CoRwlock *lock)
149 12888904 Aneesh Kumar K.V
{
150 12888904 Aneesh Kumar K.V
    while (lock->writer) {
151 12888904 Aneesh Kumar K.V
        qemu_co_queue_wait(&lock->queue);
152 12888904 Aneesh Kumar K.V
    }
153 12888904 Aneesh Kumar K.V
    lock->reader++;
154 12888904 Aneesh Kumar K.V
}
155 12888904 Aneesh Kumar K.V
156 12888904 Aneesh Kumar K.V
void qemu_co_rwlock_unlock(CoRwlock *lock)
157 12888904 Aneesh Kumar K.V
{
158 12888904 Aneesh Kumar K.V
    assert(qemu_in_coroutine());
159 12888904 Aneesh Kumar K.V
    if (lock->writer) {
160 12888904 Aneesh Kumar K.V
        lock->writer = false;
161 e8ee5e4c Stefan Hajnoczi
        qemu_co_queue_restart_all(&lock->queue);
162 12888904 Aneesh Kumar K.V
    } else {
163 12888904 Aneesh Kumar K.V
        lock->reader--;
164 12888904 Aneesh Kumar K.V
        assert(lock->reader >= 0);
165 12888904 Aneesh Kumar K.V
        /* Wakeup only one waiting writer */
166 12888904 Aneesh Kumar K.V
        if (!lock->reader) {
167 12888904 Aneesh Kumar K.V
            qemu_co_queue_next(&lock->queue);
168 12888904 Aneesh Kumar K.V
        }
169 12888904 Aneesh Kumar K.V
    }
170 12888904 Aneesh Kumar K.V
}
171 12888904 Aneesh Kumar K.V
172 12888904 Aneesh Kumar K.V
void qemu_co_rwlock_wrlock(CoRwlock *lock)
173 12888904 Aneesh Kumar K.V
{
174 12888904 Aneesh Kumar K.V
    while (lock->writer || lock->reader) {
175 12888904 Aneesh Kumar K.V
        qemu_co_queue_wait(&lock->queue);
176 12888904 Aneesh Kumar K.V
    }
177 12888904 Aneesh Kumar K.V
    lock->writer = true;
178 12888904 Aneesh Kumar K.V
}