]>
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 | 35 | |
3194c8ce AB |
36 | typedef struct { |
37 | Coroutine base; | |
38 | void *stack; | |
6ab7e546 | 39 | sigjmp_buf env; |
3194c8ce AB |
40 | } CoroutineUContext; |
41 | ||
42 | /** | |
43 | * Per-thread coroutine bookkeeping | |
44 | */ | |
45 | typedef struct { | |
46 | /** Currently executing coroutine */ | |
47 | Coroutine *current; | |
48 | ||
49 | /** The default coroutine */ | |
50 | CoroutineUContext leader; | |
51 | ||
52 | /** Information for the signal handler (trampoline) */ | |
6ab7e546 | 53 | sigjmp_buf tr_reenter; |
3194c8ce AB |
54 | volatile sig_atomic_t tr_called; |
55 | void *tr_handler; | |
56 | } CoroutineThreadState; | |
57 | ||
58 | static pthread_key_t thread_state_key; | |
59 | ||
60 | static CoroutineThreadState *coroutine_get_thread_state(void) | |
61 | { | |
62 | CoroutineThreadState *s = pthread_getspecific(thread_state_key); | |
63 | ||
64 | if (!s) { | |
65 | s = g_malloc0(sizeof(*s)); | |
66 | s->current = &s->leader.base; | |
67 | pthread_setspecific(thread_state_key, s); | |
68 | } | |
69 | return s; | |
70 | } | |
71 | ||
72 | static void qemu_coroutine_thread_cleanup(void *opaque) | |
73 | { | |
74 | CoroutineThreadState *s = opaque; | |
75 | ||
76 | g_free(s); | |
77 | } | |
78 | ||
3194c8ce AB |
79 | static void __attribute__((constructor)) coroutine_init(void) |
80 | { | |
81 | int ret; | |
82 | ||
83 | ret = pthread_key_create(&thread_state_key, qemu_coroutine_thread_cleanup); | |
84 | if (ret != 0) { | |
85 | fprintf(stderr, "unable to create leader key: %s\n", strerror(errno)); | |
86 | abort(); | |
87 | } | |
88 | } | |
89 | ||
90 | /* "boot" function | |
91 | * This is what starts the coroutine, is called from the trampoline | |
92 | * (from the signal handler when it is not signal handling, read ahead | |
93 | * for more information). | |
94 | */ | |
95 | static void coroutine_bootstrap(CoroutineUContext *self, Coroutine *co) | |
96 | { | |
97 | /* Initialize longjmp environment and switch back the caller */ | |
6ab7e546 PM |
98 | if (!sigsetjmp(self->env, 0)) { |
99 | siglongjmp(*(sigjmp_buf *)co->entry_arg, 1); | |
3194c8ce AB |
100 | } |
101 | ||
102 | while (true) { | |
103 | co->entry(co->entry_arg); | |
104 | qemu_coroutine_switch(co, co->caller, COROUTINE_TERMINATE); | |
105 | } | |
106 | } | |
107 | ||
108 | /* | |
109 | * This is used as the signal handler. This is called with the brand new stack | |
110 | * (thanks to sigaltstack). We have to return, given that this is a signal | |
111 | * handler and the sigmask and some other things are changed. | |
112 | */ | |
113 | static void coroutine_trampoline(int signal) | |
114 | { | |
115 | CoroutineUContext *self; | |
116 | Coroutine *co; | |
117 | CoroutineThreadState *coTS; | |
118 | ||
119 | /* Get the thread specific information */ | |
120 | coTS = coroutine_get_thread_state(); | |
121 | self = coTS->tr_handler; | |
122 | coTS->tr_called = 1; | |
123 | co = &self->base; | |
124 | ||
125 | /* | |
126 | * Here we have to do a bit of a ping pong between the caller, given that | |
127 | * this is a signal handler and we have to do a return "soon". Then the | |
6ab7e546 | 128 | * caller can reestablish everything and do a siglongjmp here again. |
3194c8ce | 129 | */ |
6ab7e546 | 130 | if (!sigsetjmp(coTS->tr_reenter, 0)) { |
3194c8ce AB |
131 | return; |
132 | } | |
133 | ||
134 | /* | |
6ab7e546 | 135 | * Ok, the caller has siglongjmp'ed back to us, so now prepare |
3194c8ce AB |
136 | * us for the real machine state switching. We have to jump |
137 | * into another function here to get a new stack context for | |
138 | * the auto variables (which have to be auto-variables | |
139 | * because the start of the thread happens later). Else with | |
140 | * PIC (i.e. Position Independent Code which is used when PTH | |
141 | * is built as a shared library) most platforms would | |
142 | * horrible core dump as experience showed. | |
143 | */ | |
144 | coroutine_bootstrap(self, co); | |
145 | } | |
146 | ||
40239784 | 147 | Coroutine *qemu_coroutine_new(void) |
3194c8ce AB |
148 | { |
149 | const size_t stack_size = 1 << 20; | |
150 | CoroutineUContext *co; | |
151 | CoroutineThreadState *coTS; | |
152 | struct sigaction sa; | |
153 | struct sigaction osa; | |
2ad2210a PM |
154 | stack_t ss; |
155 | stack_t oss; | |
3194c8ce AB |
156 | sigset_t sigs; |
157 | sigset_t osigs; | |
158 | jmp_buf old_env; | |
159 | ||
160 | /* The way to manipulate stack is with the sigaltstack function. We | |
161 | * prepare a stack, with it delivering a signal to ourselves and then | |
6ab7e546 | 162 | * put sigsetjmp/siglongjmp where needed. |
3194c8ce AB |
163 | * This has been done keeping coroutine-ucontext as a model and with the |
164 | * pth ideas (GNU Portable Threads). See coroutine-ucontext for the basics | |
165 | * of the coroutines and see pth_mctx.c (from the pth project) for the | |
166 | * sigaltstack way of manipulating stacks. | |
167 | */ | |
168 | ||
169 | co = g_malloc0(sizeof(*co)); | |
170 | co->stack = g_malloc(stack_size); | |
171 | co->base.entry_arg = &old_env; /* stash away our jmp_buf */ | |
172 | ||
173 | coTS = coroutine_get_thread_state(); | |
174 | coTS->tr_handler = co; | |
175 | ||
176 | /* | |
177 | * Preserve the SIGUSR2 signal state, block SIGUSR2, | |
178 | * and establish our signal handler. The signal will | |
179 | * later transfer control onto the signal stack. | |
180 | */ | |
181 | sigemptyset(&sigs); | |
182 | sigaddset(&sigs, SIGUSR2); | |
183 | pthread_sigmask(SIG_BLOCK, &sigs, &osigs); | |
184 | sa.sa_handler = coroutine_trampoline; | |
185 | sigfillset(&sa.sa_mask); | |
186 | sa.sa_flags = SA_ONSTACK; | |
187 | if (sigaction(SIGUSR2, &sa, &osa) != 0) { | |
188 | abort(); | |
189 | } | |
190 | ||
191 | /* | |
192 | * Set the new stack. | |
193 | */ | |
194 | ss.ss_sp = co->stack; | |
195 | ss.ss_size = stack_size; | |
196 | ss.ss_flags = 0; | |
197 | if (sigaltstack(&ss, &oss) < 0) { | |
198 | abort(); | |
199 | } | |
200 | ||
201 | /* | |
202 | * Now transfer control onto the signal stack and set it up. | |
6ab7e546 | 203 | * It will return immediately via "return" after the sigsetjmp() |
3194c8ce AB |
204 | * was performed. Be careful here with race conditions. The |
205 | * signal can be delivered the first time sigsuspend() is | |
206 | * called. | |
207 | */ | |
208 | coTS->tr_called = 0; | |
99b5beba | 209 | pthread_kill(pthread_self(), SIGUSR2); |
3194c8ce AB |
210 | sigfillset(&sigs); |
211 | sigdelset(&sigs, SIGUSR2); | |
212 | while (!coTS->tr_called) { | |
213 | sigsuspend(&sigs); | |
214 | } | |
215 | ||
216 | /* | |
217 | * Inform the system that we are back off the signal stack by | |
218 | * removing the alternative signal stack. Be careful here: It | |
219 | * first has to be disabled, before it can be removed. | |
220 | */ | |
221 | sigaltstack(NULL, &ss); | |
222 | ss.ss_flags = SS_DISABLE; | |
223 | if (sigaltstack(&ss, NULL) < 0) { | |
224 | abort(); | |
225 | } | |
226 | sigaltstack(NULL, &ss); | |
227 | if (!(oss.ss_flags & SS_DISABLE)) { | |
228 | sigaltstack(&oss, NULL); | |
229 | } | |
230 | ||
231 | /* | |
232 | * Restore the old SIGUSR2 signal handler and mask | |
233 | */ | |
234 | sigaction(SIGUSR2, &osa, NULL); | |
235 | pthread_sigmask(SIG_SETMASK, &osigs, NULL); | |
236 | ||
237 | /* | |
238 | * Now enter the trampoline again, but this time not as a signal | |
239 | * handler. Instead we jump into it directly. The functionally | |
a31f0531 | 240 | * redundant ping-pong pointer arithmetic is necessary to avoid |
3194c8ce AB |
241 | * type-conversion warnings related to the `volatile' qualifier and |
242 | * the fact that `jmp_buf' usually is an array type. | |
243 | */ | |
6ab7e546 PM |
244 | if (!sigsetjmp(old_env, 0)) { |
245 | siglongjmp(coTS->tr_reenter, 1); | |
3194c8ce AB |
246 | } |
247 | ||
248 | /* | |
249 | * Ok, we returned again, so now we're finished | |
250 | */ | |
251 | ||
252 | return &co->base; | |
253 | } | |
254 | ||
3194c8ce AB |
255 | void qemu_coroutine_delete(Coroutine *co_) |
256 | { | |
257 | CoroutineUContext *co = DO_UPCAST(CoroutineUContext, base, co_); | |
258 | ||
3194c8ce AB |
259 | g_free(co->stack); |
260 | g_free(co); | |
261 | } | |
262 | ||
263 | CoroutineAction qemu_coroutine_switch(Coroutine *from_, Coroutine *to_, | |
264 | CoroutineAction action) | |
265 | { | |
266 | CoroutineUContext *from = DO_UPCAST(CoroutineUContext, base, from_); | |
267 | CoroutineUContext *to = DO_UPCAST(CoroutineUContext, base, to_); | |
268 | CoroutineThreadState *s = coroutine_get_thread_state(); | |
269 | int ret; | |
270 | ||
271 | s->current = to_; | |
272 | ||
6ab7e546 | 273 | ret = sigsetjmp(from->env, 0); |
3194c8ce | 274 | if (ret == 0) { |
6ab7e546 | 275 | siglongjmp(to->env, action); |
3194c8ce AB |
276 | } |
277 | return ret; | |
278 | } | |
279 | ||
280 | Coroutine *qemu_coroutine_self(void) | |
281 | { | |
282 | CoroutineThreadState *s = coroutine_get_thread_state(); | |
283 | ||
284 | return s->current; | |
285 | } | |
286 | ||
287 | bool qemu_in_coroutine(void) | |
288 | { | |
289 | CoroutineThreadState *s = pthread_getspecific(thread_state_key); | |
290 | ||
291 | return s && s->current->caller; | |
292 | } | |
293 |