| 
									
										
										
										
											2012-02-28 12:25:49 +01:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * sigaltstack coroutine initialization code | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright (C) 2006  Anthony Liguori <anthony@codemonkey.ws> | 
					
						
							|  |  |  |  * Copyright (C) 2011  Kevin Wolf <kwolf@redhat.com> | 
					
						
							|  |  |  |  * Copyright (C) 2012  Alex Barcelo <abarcelo@ac.upc.edu> | 
					
						
							|  |  |  | ** This file is partly based on pth_mctx.c, from the GNU Portable Threads | 
					
						
							|  |  |  | **  Copyright (c) 1999-2006 Ralf S. Engelschall <rse@engelschall.com> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This library is free software; you can redistribute it and/or | 
					
						
							|  |  |  |  * modify it under the terms of the GNU Lesser General Public | 
					
						
							|  |  |  |  * License as published by the Free Software Foundation; either | 
					
						
							|  |  |  |  * version 2.1 of the License, or (at your option) any later version. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This library is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
					
						
							|  |  |  |  * Lesser General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * You should have received a copy of the GNU Lesser General Public | 
					
						
							|  |  |  |  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* XXX Is there a nicer way to disable glibc's stack check for longjmp? */ | 
					
						
							|  |  |  | #ifdef _FORTIFY_SOURCE
 | 
					
						
							|  |  |  | #undef _FORTIFY_SOURCE
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2016-01-29 17:49:55 +00:00
										 |  |  | #include "qemu/osdep.h"
 | 
					
						
							| 
									
										
										
										
											2012-02-28 12:25:49 +01:00
										 |  |  | #include <pthread.h>
 | 
					
						
							|  |  |  | #include "qemu-common.h"
 | 
					
						
							| 
									
										
										
										
											2015-09-01 14:48:02 +01:00
										 |  |  | #include "qemu/coroutine_int.h"
 | 
					
						
							| 
									
										
										
										
											2012-02-28 12:25:49 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | typedef struct { | 
					
						
							|  |  |  |     Coroutine base; | 
					
						
							|  |  |  |     void *stack; | 
					
						
							| 
									
										
										
										
											2016-09-27 11:58:44 +02:00
										 |  |  |     size_t stack_size; | 
					
						
							| 
									
										
										
										
											2013-02-20 15:21:09 +00:00
										 |  |  |     sigjmp_buf env; | 
					
						
							| 
									
										
										
										
											2016-09-27 11:58:41 +02:00
										 |  |  | } CoroutineSigAltStack; | 
					
						
							| 
									
										
										
										
											2012-02-28 12:25:49 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * Per-thread coroutine bookkeeping | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | typedef struct { | 
					
						
							|  |  |  |     /** Currently executing coroutine */ | 
					
						
							|  |  |  |     Coroutine *current; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** The default coroutine */ | 
					
						
							| 
									
										
										
										
											2016-09-27 11:58:41 +02:00
										 |  |  |     CoroutineSigAltStack leader; | 
					
						
							| 
									
										
										
										
											2012-02-28 12:25:49 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /** Information for the signal handler (trampoline) */ | 
					
						
							| 
									
										
										
										
											2013-02-20 15:21:09 +00:00
										 |  |  |     sigjmp_buf tr_reenter; | 
					
						
							| 
									
										
										
										
											2012-02-28 12:25:49 +01:00
										 |  |  |     volatile sig_atomic_t tr_called; | 
					
						
							|  |  |  |     void *tr_handler; | 
					
						
							|  |  |  | } CoroutineThreadState; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static pthread_key_t thread_state_key; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static CoroutineThreadState *coroutine_get_thread_state(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     CoroutineThreadState *s = pthread_getspecific(thread_state_key); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!s) { | 
					
						
							|  |  |  |         s = g_malloc0(sizeof(*s)); | 
					
						
							|  |  |  |         s->current = &s->leader.base; | 
					
						
							|  |  |  |         pthread_setspecific(thread_state_key, s); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return s; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void qemu_coroutine_thread_cleanup(void *opaque) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     CoroutineThreadState *s = opaque; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     g_free(s); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void __attribute__((constructor)) coroutine_init(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ret = pthread_key_create(&thread_state_key, qemu_coroutine_thread_cleanup); | 
					
						
							|  |  |  |     if (ret != 0) { | 
					
						
							|  |  |  |         fprintf(stderr, "unable to create leader key: %s\n", strerror(errno)); | 
					
						
							|  |  |  |         abort(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* "boot" function
 | 
					
						
							|  |  |  |  * This is what starts the coroutine, is called from the trampoline | 
					
						
							|  |  |  |  * (from the signal handler when it is not signal handling, read ahead | 
					
						
							|  |  |  |  * for more information). | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2016-09-27 11:58:41 +02:00
										 |  |  | static void coroutine_bootstrap(CoroutineSigAltStack *self, Coroutine *co) | 
					
						
							| 
									
										
										
										
											2012-02-28 12:25:49 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     /* Initialize longjmp environment and switch back the caller */ | 
					
						
							| 
									
										
										
										
											2013-02-20 15:21:09 +00:00
										 |  |  |     if (!sigsetjmp(self->env, 0)) { | 
					
						
							|  |  |  |         siglongjmp(*(sigjmp_buf *)co->entry_arg, 1); | 
					
						
							| 
									
										
										
										
											2012-02-28 12:25:49 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     while (true) { | 
					
						
							|  |  |  |         co->entry(co->entry_arg); | 
					
						
							|  |  |  |         qemu_coroutine_switch(co, co->caller, COROUTINE_TERMINATE); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * This is used as the signal handler. This is called with the brand new stack | 
					
						
							|  |  |  |  * (thanks to sigaltstack). We have to return, given that this is a signal | 
					
						
							|  |  |  |  * handler and the sigmask and some other things are changed. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void coroutine_trampoline(int signal) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-09-27 11:58:41 +02:00
										 |  |  |     CoroutineSigAltStack *self; | 
					
						
							| 
									
										
										
										
											2012-02-28 12:25:49 +01:00
										 |  |  |     Coroutine *co; | 
					
						
							|  |  |  |     CoroutineThreadState *coTS; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Get the thread specific information */ | 
					
						
							|  |  |  |     coTS = coroutine_get_thread_state(); | 
					
						
							|  |  |  |     self = coTS->tr_handler; | 
					
						
							|  |  |  |     coTS->tr_called = 1; | 
					
						
							|  |  |  |     co = &self->base; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Here we have to do a bit of a ping pong between the caller, given that | 
					
						
							|  |  |  |      * this is a signal handler and we have to do a return "soon". Then the | 
					
						
							| 
									
										
										
										
											2013-02-20 15:21:09 +00:00
										 |  |  |      * caller can reestablish everything and do a siglongjmp here again. | 
					
						
							| 
									
										
										
										
											2012-02-28 12:25:49 +01:00
										 |  |  |      */ | 
					
						
							| 
									
										
										
										
											2013-02-20 15:21:09 +00:00
										 |  |  |     if (!sigsetjmp(coTS->tr_reenter, 0)) { | 
					
						
							| 
									
										
										
										
											2012-02-28 12:25:49 +01:00
										 |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							| 
									
										
										
										
											2013-02-20 15:21:09 +00:00
										 |  |  |      * Ok, the caller has siglongjmp'ed back to us, so now prepare | 
					
						
							| 
									
										
										
										
											2012-02-28 12:25:49 +01:00
										 |  |  |      * us for the real machine state switching. We have to jump | 
					
						
							|  |  |  |      * into another function here to get a new stack context for | 
					
						
							|  |  |  |      * the auto variables (which have to be auto-variables | 
					
						
							|  |  |  |      * because the start of the thread happens later). Else with | 
					
						
							|  |  |  |      * PIC (i.e. Position Independent Code which is used when PTH | 
					
						
							|  |  |  |      * is built as a shared library) most platforms would | 
					
						
							|  |  |  |      * horrible core dump as experience showed. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     coroutine_bootstrap(self, co); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-19 11:59:09 +01:00
										 |  |  | Coroutine *qemu_coroutine_new(void) | 
					
						
							| 
									
										
										
										
											2012-02-28 12:25:49 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-09-27 11:58:41 +02:00
										 |  |  |     CoroutineSigAltStack *co; | 
					
						
							| 
									
										
										
										
											2012-02-28 12:25:49 +01:00
										 |  |  |     CoroutineThreadState *coTS; | 
					
						
							|  |  |  |     struct sigaction sa; | 
					
						
							|  |  |  |     struct sigaction osa; | 
					
						
							| 
									
										
										
										
											2012-11-10 21:47:52 +00:00
										 |  |  |     stack_t ss; | 
					
						
							|  |  |  |     stack_t oss; | 
					
						
							| 
									
										
										
										
											2012-02-28 12:25:49 +01:00
										 |  |  |     sigset_t sigs; | 
					
						
							|  |  |  |     sigset_t osigs; | 
					
						
							| 
									
										
										
										
											2014-11-07 19:51:59 -08:00
										 |  |  |     sigjmp_buf old_env; | 
					
						
							| 
									
										
										
										
											2012-02-28 12:25:49 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* The way to manipulate stack is with the sigaltstack function. We
 | 
					
						
							|  |  |  |      * prepare a stack, with it delivering a signal to ourselves and then | 
					
						
							| 
									
										
										
										
											2013-02-20 15:21:09 +00:00
										 |  |  |      * put sigsetjmp/siglongjmp where needed. | 
					
						
							| 
									
										
										
										
											2012-02-28 12:25:49 +01:00
										 |  |  |      * This has been done keeping coroutine-ucontext as a model and with the | 
					
						
							|  |  |  |      * pth ideas (GNU Portable Threads). See coroutine-ucontext for the basics | 
					
						
							|  |  |  |      * of the coroutines and see pth_mctx.c (from the pth project) for the | 
					
						
							|  |  |  |      * sigaltstack way of manipulating stacks. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     co = g_malloc0(sizeof(*co)); | 
					
						
							| 
									
										
										
										
											2016-09-27 11:58:44 +02:00
										 |  |  |     co->stack_size = COROUTINE_STACK_SIZE; | 
					
						
							|  |  |  |     co->stack = qemu_alloc_stack(&co->stack_size); | 
					
						
							| 
									
										
										
										
											2012-02-28 12:25:49 +01:00
										 |  |  |     co->base.entry_arg = &old_env; /* stash away our jmp_buf */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     coTS = coroutine_get_thread_state(); | 
					
						
							|  |  |  |     coTS->tr_handler = co; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Preserve the SIGUSR2 signal state, block SIGUSR2, | 
					
						
							|  |  |  |      * and establish our signal handler. The signal will | 
					
						
							|  |  |  |      * later transfer control onto the signal stack. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     sigemptyset(&sigs); | 
					
						
							|  |  |  |     sigaddset(&sigs, SIGUSR2); | 
					
						
							|  |  |  |     pthread_sigmask(SIG_BLOCK, &sigs, &osigs); | 
					
						
							|  |  |  |     sa.sa_handler = coroutine_trampoline; | 
					
						
							|  |  |  |     sigfillset(&sa.sa_mask); | 
					
						
							|  |  |  |     sa.sa_flags = SA_ONSTACK; | 
					
						
							|  |  |  |     if (sigaction(SIGUSR2, &sa, &osa) != 0) { | 
					
						
							|  |  |  |         abort(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Set the new stack. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     ss.ss_sp = co->stack; | 
					
						
							| 
									
										
										
										
											2016-09-27 11:58:44 +02:00
										 |  |  |     ss.ss_size = co->stack_size; | 
					
						
							| 
									
										
										
										
											2012-02-28 12:25:49 +01:00
										 |  |  |     ss.ss_flags = 0; | 
					
						
							|  |  |  |     if (sigaltstack(&ss, &oss) < 0) { | 
					
						
							|  |  |  |         abort(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Now transfer control onto the signal stack and set it up. | 
					
						
							| 
									
										
										
										
											2013-02-20 15:21:09 +00:00
										 |  |  |      * It will return immediately via "return" after the sigsetjmp() | 
					
						
							| 
									
										
										
										
											2012-02-28 12:25:49 +01:00
										 |  |  |      * was performed. Be careful here with race conditions.  The | 
					
						
							|  |  |  |      * signal can be delivered the first time sigsuspend() is | 
					
						
							|  |  |  |      * called. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     coTS->tr_called = 0; | 
					
						
							| 
									
										
										
										
											2012-05-09 14:23:27 -03:00
										 |  |  |     pthread_kill(pthread_self(), SIGUSR2); | 
					
						
							| 
									
										
										
										
											2012-02-28 12:25:49 +01:00
										 |  |  |     sigfillset(&sigs); | 
					
						
							|  |  |  |     sigdelset(&sigs, SIGUSR2); | 
					
						
							|  |  |  |     while (!coTS->tr_called) { | 
					
						
							|  |  |  |         sigsuspend(&sigs); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Inform the system that we are back off the signal stack by | 
					
						
							|  |  |  |      * removing the alternative signal stack. Be careful here: It | 
					
						
							|  |  |  |      * first has to be disabled, before it can be removed. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     sigaltstack(NULL, &ss); | 
					
						
							|  |  |  |     ss.ss_flags = SS_DISABLE; | 
					
						
							|  |  |  |     if (sigaltstack(&ss, NULL) < 0) { | 
					
						
							|  |  |  |         abort(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     sigaltstack(NULL, &ss); | 
					
						
							|  |  |  |     if (!(oss.ss_flags & SS_DISABLE)) { | 
					
						
							|  |  |  |         sigaltstack(&oss, NULL); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Restore the old SIGUSR2 signal handler and mask | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     sigaction(SIGUSR2, &osa, NULL); | 
					
						
							|  |  |  |     pthread_sigmask(SIG_SETMASK, &osigs, NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Now enter the trampoline again, but this time not as a signal | 
					
						
							|  |  |  |      * handler. Instead we jump into it directly. The functionally | 
					
						
							| 
									
										
										
										
											2012-05-09 05:12:04 +00:00
										 |  |  |      * redundant ping-pong pointer arithmetic is necessary to avoid | 
					
						
							| 
									
										
										
										
											2012-02-28 12:25:49 +01:00
										 |  |  |      * type-conversion warnings related to the `volatile' qualifier and | 
					
						
							|  |  |  |      * the fact that `jmp_buf' usually is an array type. | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2013-02-20 15:21:09 +00:00
										 |  |  |     if (!sigsetjmp(old_env, 0)) { | 
					
						
							|  |  |  |         siglongjmp(coTS->tr_reenter, 1); | 
					
						
							| 
									
										
										
										
											2012-02-28 12:25:49 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Ok, we returned again, so now we're finished | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return &co->base; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void qemu_coroutine_delete(Coroutine *co_) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-09-27 11:58:41 +02:00
										 |  |  |     CoroutineSigAltStack *co = DO_UPCAST(CoroutineSigAltStack, base, co_); | 
					
						
							| 
									
										
										
										
											2012-02-28 12:25:49 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-27 11:58:44 +02:00
										 |  |  |     qemu_free_stack(co->stack, co->stack_size); | 
					
						
							| 
									
										
										
										
											2012-02-28 12:25:49 +01:00
										 |  |  |     g_free(co); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | CoroutineAction qemu_coroutine_switch(Coroutine *from_, Coroutine *to_, | 
					
						
							|  |  |  |                                       CoroutineAction action) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-09-27 11:58:41 +02:00
										 |  |  |     CoroutineSigAltStack *from = DO_UPCAST(CoroutineSigAltStack, base, from_); | 
					
						
							|  |  |  |     CoroutineSigAltStack *to = DO_UPCAST(CoroutineSigAltStack, base, to_); | 
					
						
							| 
									
										
										
										
											2012-02-28 12:25:49 +01:00
										 |  |  |     CoroutineThreadState *s = coroutine_get_thread_state(); | 
					
						
							|  |  |  |     int ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     s->current = to_; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-20 15:21:09 +00:00
										 |  |  |     ret = sigsetjmp(from->env, 0); | 
					
						
							| 
									
										
										
										
											2012-02-28 12:25:49 +01:00
										 |  |  |     if (ret == 0) { | 
					
						
							| 
									
										
										
										
											2013-02-20 15:21:09 +00:00
										 |  |  |         siglongjmp(to->env, action); | 
					
						
							| 
									
										
										
										
											2012-02-28 12:25:49 +01:00
										 |  |  |     } | 
					
						
							|  |  |  |     return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Coroutine *qemu_coroutine_self(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     CoroutineThreadState *s = coroutine_get_thread_state(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return s->current; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool qemu_in_coroutine(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     CoroutineThreadState *s = pthread_getspecific(thread_state_key); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return s && s->current->caller; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 |