Statistics
| Branch: | Revision:

root / coroutine-sigaltstack.c @ feature-archipelago

History | View | Annotate | Download (8.3 kB)

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

    
36
typedef struct {
37
    Coroutine base;
38
    void *stack;
39
    sigjmp_buf env;
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) */
53
    sigjmp_buf tr_reenter;
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

    
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 */
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
 */
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
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

    
147
Coroutine *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

    
255
void 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

    
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

    
273
    ret = sigsetjmp(from->env, 0);
274
    if (ret == 0) {
275
        siglongjmp(to->env, action);
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