]>
Commit | Line | Data |
---|---|---|
3194c8ce AB |
1 | /* |
2 | * sigaltstack coroutine initialization code | |
3 | * | |
4 | * Copyright (C) 2006 Anthony Liguori <[email protected]> | |
5 | * Copyright (C) 2011 Kevin Wolf <[email protected]> | |
6 | * Copyright (C) 2012 Alex Barcelo <[email protected]> | |
7 | ** This file is partly based on pth_mctx.c, from the GNU Portable Threads | |
8 | ** Copyright (c) 1999-2006 Ralf S. Engelschall <[email protected]> | |
9 | * | |
10 | * This library is free software; you can redistribute it and/or | |
11 | * modify it under the terms of the GNU Lesser General Public | |
12 | * License as published by the Free Software Foundation; either | |
13 | * version 2.1 of the License, or (at your option) any later version. | |
14 | * | |
15 | * This library is distributed in the hope that it will be useful, | |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
18 | * Lesser General Public License for more details. | |
19 | * | |
20 | * You should have received a copy of the GNU Lesser General Public | |
21 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. | |
22 | */ | |
23 | ||
24 | /* XXX Is there a nicer way to disable glibc's stack check for longjmp? */ | |
25 | #ifdef _FORTIFY_SOURCE | |
26 | #undef _FORTIFY_SOURCE | |
27 | #endif | |
28 | #include <stdlib.h> | |
29 | #include <setjmp.h> | |
30 | #include <stdint.h> | |
31 | #include <pthread.h> | |
32 | #include <signal.h> | |
33 | #include "qemu-common.h" | |
737e150e | 34 | #include "block/coroutine_int.h" |
3194c8ce AB |
35 | |
36 | enum { | |
37 | /* Maximum free pool size prevents holding too many freed coroutines */ | |
38 | POOL_MAX_SIZE = 64, | |
39 | }; | |
40 | ||
41 | /** Free list to speed up creation */ | |
42 | static QSLIST_HEAD(, Coroutine) pool = QSLIST_HEAD_INITIALIZER(pool); | |
43 | static unsigned int pool_size; | |
44 | ||
45 | typedef struct { | |
46 | Coroutine base; | |
47 | void *stack; | |
48 | jmp_buf env; | |
49 | } CoroutineUContext; | |
50 | ||
51 | /** | |
52 | * Per-thread coroutine bookkeeping | |
53 | */ | |
54 | typedef struct { | |
55 | /** Currently executing coroutine */ | |
56 | Coroutine *current; | |
57 | ||
58 | /** The default coroutine */ | |
59 | CoroutineUContext leader; | |
60 | ||
61 | /** Information for the signal handler (trampoline) */ | |
62 | jmp_buf tr_reenter; | |
63 | volatile sig_atomic_t tr_called; | |
64 | void *tr_handler; | |
65 | } CoroutineThreadState; | |
66 | ||
67 | static pthread_key_t thread_state_key; | |
68 | ||
69 | static CoroutineThreadState *coroutine_get_thread_state(void) | |
70 | { | |
71 | CoroutineThreadState *s = pthread_getspecific(thread_state_key); | |
72 | ||
73 | if (!s) { | |
74 | s = g_malloc0(sizeof(*s)); | |
75 | s->current = &s->leader.base; | |
76 | pthread_setspecific(thread_state_key, s); | |
77 | } | |
78 | return s; | |
79 | } | |
80 | ||
81 | static void qemu_coroutine_thread_cleanup(void *opaque) | |
82 | { | |
83 | CoroutineThreadState *s = opaque; | |
84 | ||
85 | g_free(s); | |
86 | } | |
87 | ||
88 | static void __attribute__((destructor)) coroutine_cleanup(void) | |
89 | { | |
90 | Coroutine *co; | |
91 | Coroutine *tmp; | |
92 | ||
93 | QSLIST_FOREACH_SAFE(co, &pool, pool_next, tmp) { | |
94 | g_free(DO_UPCAST(CoroutineUContext, base, co)->stack); | |
95 | g_free(co); | |
96 | } | |
97 | } | |
98 | ||
99 | static void __attribute__((constructor)) coroutine_init(void) | |
100 | { | |
101 | int ret; | |
102 | ||
103 | ret = pthread_key_create(&thread_state_key, qemu_coroutine_thread_cleanup); | |
104 | if (ret != 0) { | |
105 | fprintf(stderr, "unable to create leader key: %s\n", strerror(errno)); | |
106 | abort(); | |
107 | } | |
108 | } | |
109 | ||
110 | /* "boot" function | |
111 | * This is what starts the coroutine, is called from the trampoline | |
112 | * (from the signal handler when it is not signal handling, read ahead | |
113 | * for more information). | |
114 | */ | |
115 | static void coroutine_bootstrap(CoroutineUContext *self, Coroutine *co) | |
116 | { | |
117 | /* Initialize longjmp environment and switch back the caller */ | |
118 | if (!setjmp(self->env)) { | |
119 | longjmp(*(jmp_buf *)co->entry_arg, 1); | |
120 | } | |
121 | ||
122 | while (true) { | |
123 | co->entry(co->entry_arg); | |
124 | qemu_coroutine_switch(co, co->caller, COROUTINE_TERMINATE); | |
125 | } | |
126 | } | |
127 | ||
128 | /* | |
129 | * This is used as the signal handler. This is called with the brand new stack | |
130 | * (thanks to sigaltstack). We have to return, given that this is a signal | |
131 | * handler and the sigmask and some other things are changed. | |
132 | */ | |
133 | static void coroutine_trampoline(int signal) | |
134 | { | |
135 | CoroutineUContext *self; | |
136 | Coroutine *co; | |
137 | CoroutineThreadState *coTS; | |
138 | ||
139 | /* Get the thread specific information */ | |
140 | coTS = coroutine_get_thread_state(); | |
141 | self = coTS->tr_handler; | |
142 | coTS->tr_called = 1; | |
143 | co = &self->base; | |
144 | ||
145 | /* | |
146 | * Here we have to do a bit of a ping pong between the caller, given that | |
147 | * this is a signal handler and we have to do a return "soon". Then the | |
148 | * caller can reestablish everything and do a longjmp here again. | |
149 | */ | |
150 | if (!setjmp(coTS->tr_reenter)) { | |
151 | return; | |
152 | } | |
153 | ||
154 | /* | |
155 | * Ok, the caller has longjmp'ed back to us, so now prepare | |
156 | * us for the real machine state switching. We have to jump | |
157 | * into another function here to get a new stack context for | |
158 | * the auto variables (which have to be auto-variables | |
159 | * because the start of the thread happens later). Else with | |
160 | * PIC (i.e. Position Independent Code which is used when PTH | |
161 | * is built as a shared library) most platforms would | |
162 | * horrible core dump as experience showed. | |
163 | */ | |
164 | coroutine_bootstrap(self, co); | |
165 | } | |
166 | ||
167 | static Coroutine *coroutine_new(void) | |
168 | { | |
169 | const size_t stack_size = 1 << 20; | |
170 | CoroutineUContext *co; | |
171 | CoroutineThreadState *coTS; | |
172 | struct sigaction sa; | |
173 | struct sigaction osa; | |
2ad2210a PM |
174 | stack_t ss; |
175 | stack_t oss; | |
3194c8ce AB |
176 | sigset_t sigs; |
177 | sigset_t osigs; | |
178 | jmp_buf old_env; | |
179 | ||
180 | /* The way to manipulate stack is with the sigaltstack function. We | |
181 | * prepare a stack, with it delivering a signal to ourselves and then | |
182 | * put setjmp/longjmp where needed. | |
183 | * This has been done keeping coroutine-ucontext as a model and with the | |
184 | * pth ideas (GNU Portable Threads). See coroutine-ucontext for the basics | |
185 | * of the coroutines and see pth_mctx.c (from the pth project) for the | |
186 | * sigaltstack way of manipulating stacks. | |
187 | */ | |
188 | ||
189 | co = g_malloc0(sizeof(*co)); | |
190 | co->stack = g_malloc(stack_size); | |
191 | co->base.entry_arg = &old_env; /* stash away our jmp_buf */ | |
192 | ||
193 | coTS = coroutine_get_thread_state(); | |
194 | coTS->tr_handler = co; | |
195 | ||
196 | /* | |
197 | * Preserve the SIGUSR2 signal state, block SIGUSR2, | |
198 | * and establish our signal handler. The signal will | |
199 | * later transfer control onto the signal stack. | |
200 | */ | |
201 | sigemptyset(&sigs); | |
202 | sigaddset(&sigs, SIGUSR2); | |
203 | pthread_sigmask(SIG_BLOCK, &sigs, &osigs); | |
204 | sa.sa_handler = coroutine_trampoline; | |
205 | sigfillset(&sa.sa_mask); | |
206 | sa.sa_flags = SA_ONSTACK; | |
207 | if (sigaction(SIGUSR2, &sa, &osa) != 0) { | |
208 | abort(); | |
209 | } | |
210 | ||
211 | /* | |
212 | * Set the new stack. | |
213 | */ | |
214 | ss.ss_sp = co->stack; | |
215 | ss.ss_size = stack_size; | |
216 | ss.ss_flags = 0; | |
217 | if (sigaltstack(&ss, &oss) < 0) { | |
218 | abort(); | |
219 | } | |
220 | ||
221 | /* | |
222 | * Now transfer control onto the signal stack and set it up. | |
223 | * It will return immediately via "return" after the setjmp() | |
224 | * was performed. Be careful here with race conditions. The | |
225 | * signal can be delivered the first time sigsuspend() is | |
226 | * called. | |
227 | */ | |
228 | coTS->tr_called = 0; | |
99b5beba | 229 | pthread_kill(pthread_self(), SIGUSR2); |
3194c8ce AB |
230 | sigfillset(&sigs); |
231 | sigdelset(&sigs, SIGUSR2); | |
232 | while (!coTS->tr_called) { | |
233 | sigsuspend(&sigs); | |
234 | } | |
235 | ||
236 | /* | |
237 | * Inform the system that we are back off the signal stack by | |
238 | * removing the alternative signal stack. Be careful here: It | |
239 | * first has to be disabled, before it can be removed. | |
240 | */ | |
241 | sigaltstack(NULL, &ss); | |
242 | ss.ss_flags = SS_DISABLE; | |
243 | if (sigaltstack(&ss, NULL) < 0) { | |
244 | abort(); | |
245 | } | |
246 | sigaltstack(NULL, &ss); | |
247 | if (!(oss.ss_flags & SS_DISABLE)) { | |
248 | sigaltstack(&oss, NULL); | |
249 | } | |
250 | ||
251 | /* | |
252 | * Restore the old SIGUSR2 signal handler and mask | |
253 | */ | |
254 | sigaction(SIGUSR2, &osa, NULL); | |
255 | pthread_sigmask(SIG_SETMASK, &osigs, NULL); | |
256 | ||
257 | /* | |
258 | * Now enter the trampoline again, but this time not as a signal | |
259 | * handler. Instead we jump into it directly. The functionally | |
a31f0531 | 260 | * redundant ping-pong pointer arithmetic is necessary to avoid |
3194c8ce AB |
261 | * type-conversion warnings related to the `volatile' qualifier and |
262 | * the fact that `jmp_buf' usually is an array type. | |
263 | */ | |
264 | if (!setjmp(old_env)) { | |
265 | longjmp(coTS->tr_reenter, 1); | |
266 | } | |
267 | ||
268 | /* | |
269 | * Ok, we returned again, so now we're finished | |
270 | */ | |
271 | ||
272 | return &co->base; | |
273 | } | |
274 | ||
275 | Coroutine *qemu_coroutine_new(void) | |
276 | { | |
277 | Coroutine *co; | |
278 | ||
279 | co = QSLIST_FIRST(&pool); | |
280 | if (co) { | |
281 | QSLIST_REMOVE_HEAD(&pool, pool_next); | |
282 | pool_size--; | |
283 | } else { | |
284 | co = coroutine_new(); | |
285 | } | |
286 | return co; | |
287 | } | |
288 | ||
289 | void qemu_coroutine_delete(Coroutine *co_) | |
290 | { | |
291 | CoroutineUContext *co = DO_UPCAST(CoroutineUContext, base, co_); | |
292 | ||
293 | if (pool_size < POOL_MAX_SIZE) { | |
294 | QSLIST_INSERT_HEAD(&pool, &co->base, pool_next); | |
295 | co->base.caller = NULL; | |
296 | pool_size++; | |
297 | return; | |
298 | } | |
299 | ||
300 | g_free(co->stack); | |
301 | g_free(co); | |
302 | } | |
303 | ||
304 | CoroutineAction qemu_coroutine_switch(Coroutine *from_, Coroutine *to_, | |
305 | CoroutineAction action) | |
306 | { | |
307 | CoroutineUContext *from = DO_UPCAST(CoroutineUContext, base, from_); | |
308 | CoroutineUContext *to = DO_UPCAST(CoroutineUContext, base, to_); | |
309 | CoroutineThreadState *s = coroutine_get_thread_state(); | |
310 | int ret; | |
311 | ||
312 | s->current = to_; | |
313 | ||
314 | ret = setjmp(from->env); | |
315 | if (ret == 0) { | |
316 | longjmp(to->env, action); | |
317 | } | |
318 | return ret; | |
319 | } | |
320 | ||
321 | Coroutine *qemu_coroutine_self(void) | |
322 | { | |
323 | CoroutineThreadState *s = coroutine_get_thread_state(); | |
324 | ||
325 | return s->current; | |
326 | } | |
327 | ||
328 | bool qemu_in_coroutine(void) | |
329 | { | |
330 | CoroutineThreadState *s = pthread_getspecific(thread_state_key); | |
331 | ||
332 | return s && s->current->caller; | |
333 | } | |
334 |