1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25#include "qemu-common.h"
26#include "qemu-coroutine.h"
27#include "qemu-coroutine-int.h"
28#include "qemu-queue.h"
29#include "qemu-aio.h"
30#include "trace.h"
31
32static QTAILQ_HEAD(, Coroutine) unlock_bh_queue =
33 QTAILQ_HEAD_INITIALIZER(unlock_bh_queue);
34static QEMUBH* unlock_bh;
35
36static void qemu_co_queue_next_bh(void *opaque)
37{
38 Coroutine *next;
39
40 trace_qemu_co_queue_next_bh();
41 while ((next = QTAILQ_FIRST(&unlock_bh_queue))) {
42 QTAILQ_REMOVE(&unlock_bh_queue, next, co_queue_next);
43 qemu_coroutine_enter(next, NULL);
44 }
45}
46
47void qemu_co_queue_init(CoQueue *queue)
48{
49 QTAILQ_INIT(&queue->entries);
50
51 if (!unlock_bh) {
52 unlock_bh = qemu_bh_new(qemu_co_queue_next_bh, NULL);
53 }
54}
55
56void coroutine_fn qemu_co_queue_wait(CoQueue *queue)
57{
58 Coroutine *self = qemu_coroutine_self();
59 QTAILQ_INSERT_TAIL(&queue->entries, self, co_queue_next);
60 qemu_coroutine_yield();
61 assert(qemu_in_coroutine());
62}
63
64void coroutine_fn qemu_co_queue_wait_insert_head(CoQueue *queue)
65{
66 Coroutine *self = qemu_coroutine_self();
67 QTAILQ_INSERT_HEAD(&queue->entries, self, co_queue_next);
68 qemu_coroutine_yield();
69 assert(qemu_in_coroutine());
70}
71
72bool qemu_co_queue_next(CoQueue *queue)
73{
74 Coroutine *next;
75
76 next = QTAILQ_FIRST(&queue->entries);
77 if (next) {
78 QTAILQ_REMOVE(&queue->entries, next, co_queue_next);
79 QTAILQ_INSERT_TAIL(&unlock_bh_queue, next, co_queue_next);
80 trace_qemu_co_queue_next(next);
81 qemu_bh_schedule(unlock_bh);
82 }
83
84 return (next != NULL);
85}
86
87void qemu_co_queue_restart_all(CoQueue *queue)
88{
89 while (qemu_co_queue_next(queue)) {
90
91 }
92}
93
94bool qemu_co_queue_empty(CoQueue *queue)
95{
96 return (QTAILQ_FIRST(&queue->entries) == NULL);
97}
98
99void qemu_co_mutex_init(CoMutex *mutex)
100{
101 memset(mutex, 0, sizeof(*mutex));
102 qemu_co_queue_init(&mutex->queue);
103}
104
105void coroutine_fn qemu_co_mutex_lock(CoMutex *mutex)
106{
107 Coroutine *self = qemu_coroutine_self();
108
109 trace_qemu_co_mutex_lock_entry(mutex, self);
110
111 while (mutex->locked) {
112 qemu_co_queue_wait(&mutex->queue);
113 }
114
115 mutex->locked = true;
116
117 trace_qemu_co_mutex_lock_return(mutex, self);
118}
119
120void coroutine_fn qemu_co_mutex_unlock(CoMutex *mutex)
121{
122 Coroutine *self = qemu_coroutine_self();
123
124 trace_qemu_co_mutex_unlock_entry(mutex, self);
125
126 assert(mutex->locked == true);
127 assert(qemu_in_coroutine());
128
129 mutex->locked = false;
130 qemu_co_queue_next(&mutex->queue);
131
132 trace_qemu_co_mutex_unlock_return(mutex, self);
133}
134
135void qemu_co_rwlock_init(CoRwlock *lock)
136{
137 memset(lock, 0, sizeof(*lock));
138 qemu_co_queue_init(&lock->queue);
139}
140
141void qemu_co_rwlock_rdlock(CoRwlock *lock)
142{
143 while (lock->writer) {
144 qemu_co_queue_wait(&lock->queue);
145 }
146 lock->reader++;
147}
148
149void qemu_co_rwlock_unlock(CoRwlock *lock)
150{
151 assert(qemu_in_coroutine());
152 if (lock->writer) {
153 lock->writer = false;
154 qemu_co_queue_restart_all(&lock->queue);
155 } else {
156 lock->reader--;
157 assert(lock->reader >= 0);
158
159 if (!lock->reader) {
160 qemu_co_queue_next(&lock->queue);
161 }
162 }
163}
164
165void qemu_co_rwlock_wrlock(CoRwlock *lock)
166{
167 while (lock->writer || lock->reader) {
168 qemu_co_queue_wait(&lock->queue);
169 }
170 lock->writer = true;
171}
172