qemu/coroutine-sigaltstack.c
<<
>>
Prefs
   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 <stdlib.h>
  29#include <setjmp.h>
  30#include <stdint.h>
  31#include <pthread.h>
  32#include <signal.h>
  33#include "qemu-common.h"
  34#include "block/coroutine_int.h"
  35
  36typedef struct {
  37    Coroutine base;
  38    void *stack;
  39    sigjmp_buf env;
  40} CoroutineUContext;
  41
  42/**
  43 * Per-thread coroutine bookkeeping
  44 */
  45typedef struct {
  46    /** Currently executing coroutine */
  47    Coroutine *current;
  48
  49    /** The default coroutine */
  50    CoroutineUContext leader;
  51
  52    /** Information for the signal handler (trampoline) */
  53    sigjmp_buf tr_reenter;
  54    volatile sig_atomic_t tr_called;
  55    void *tr_handler;
  56} CoroutineThreadState;
  57
  58static pthread_key_t thread_state_key;
  59
  60static 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
  72static void qemu_coroutine_thread_cleanup(void *opaque)
  73{
  74    CoroutineThreadState *s = opaque;
  75
  76    g_free(s);
  77}
  78
  79static 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 */
  95static void coroutine_bootstrap(CoroutineUContext *self, Coroutine *co)
  96{
  97    /* Initialize longjmp environment and switch back the caller */
  98    if (!sigsetjmp(self->env, 0)) {
  99        siglongjmp(*(sigjmp_buf *)co->entry_arg, 1);
 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 */
 113static 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
 128     * caller can reestablish everything and do a siglongjmp here again.
 129     */
 130    if (!sigsetjmp(coTS->tr_reenter, 0)) {
 131        return;
 132    }
 133
 134    /*
 135     * Ok, the caller has siglongjmp'ed back to us, so now prepare
 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
 147Coroutine *qemu_coroutine_new(void)
 148{
 149    const size_t stack_size = 1 << 20;
 150    CoroutineUContext *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    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
 162     * put sigsetjmp/siglongjmp where needed.
 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.
 203     * It will return immediately via "return" after the sigsetjmp()
 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;
 209    pthread_kill(pthread_self(), SIGUSR2);
 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
 240     * redundant ping-pong pointer arithmetic is necessary to avoid
 241     * type-conversion warnings related to the `volatile' qualifier and
 242     * the fact that `jmp_buf' usually is an array type.
 243     */
 244    if (!sigsetjmp(old_env, 0)) {
 245        siglongjmp(coTS->tr_reenter, 1);
 246    }
 247
 248    /*
 249     * Ok, we returned again, so now we're finished
 250     */
 251
 252    return &co->base;
 253}
 254
 255void qemu_coroutine_delete(Coroutine *co_)
 256{
 257    CoroutineUContext *co = DO_UPCAST(CoroutineUContext, base, co_);
 258
 259    g_free(co->stack);
 260    g_free(co);
 261}
 262
 263CoroutineAction 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
 273    ret = sigsetjmp(from->env, 0);
 274    if (ret == 0) {
 275        siglongjmp(to->env, action);
 276    }
 277    return ret;
 278}
 279
 280Coroutine *qemu_coroutine_self(void)
 281{
 282    CoroutineThreadState *s = coroutine_get_thread_state();
 283
 284    return s->current;
 285}
 286
 287bool qemu_in_coroutine(void)
 288{
 289    CoroutineThreadState *s = pthread_getspecific(thread_state_key);
 290
 291    return s && s->current->caller;
 292}
 293
 294