qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

coroutine-sigaltstack.c (8964B)


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