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