From 6ab7e5465a4d6188e29398fb43a30dbab1015b75 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 20 Feb 2013 15:21:09 +0000 Subject: Replace all setjmp()/longjmp() with sigsetjmp()/siglongjmp() The setjmp() function doesn't specify whether signal masks are saved and restored; on Linux they are not, but on BSD (including MacOSX) they are. We want to have consistent behaviour across platforms, so we should always use "don't save/restore signal mask" (this is also generally going to be faster). This also works around a bug in MacOSX where the signal-restoration on longjmp() affects the signal mask for a completely different thread, not just the mask for the thread which did the longjmp. The most visible effect of this was that ctrl-C was ignored on MacOSX because the CPU thread did a longjmp which resulted in its signal mask being applied to every thread, so that all threads had SIGINT and SIGTERM blocked. The POSIX-sanctioned portable way to do a jump without affecting signal masks is to siglongjmp() to a sigjmp_buf which was created by calling sigsetjmp() with a zero savemask parameter, so change all uses of setjmp()/longjmp() accordingly. [Technically POSIX allows sigsetjmp(buf, 0) to save the signal mask; however the following siglongjmp() must not restore the signal mask, so the pair can be effectively considered as "sigjmp/longjmp which don't touch the mask".] For Windows we provide a trivial sigsetjmp/siglongjmp in terms of setjmp/longjmp -- this is OK because no user will ever pass a non-zero savemask. The setjmp() uses in tests/tcg/test-i386.c and tests/tcg/linux-test.c are left untouched because these are self-contained singlethreaded test programs intended to be run under QEMU's Linux emulation, so they have neither the portability nor the multithreading issues to deal with. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Tested-by: Stefan Weil Reviewed-by: Laszlo Ersek Signed-off-by: Blue Swirl --- coroutine-sigaltstack.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'coroutine-sigaltstack.c') diff --git a/coroutine-sigaltstack.c b/coroutine-sigaltstack.c index e37ebac9c4..1fb41c9f14 100644 --- a/coroutine-sigaltstack.c +++ b/coroutine-sigaltstack.c @@ -45,7 +45,7 @@ static unsigned int pool_size; typedef struct { Coroutine base; void *stack; - jmp_buf env; + sigjmp_buf env; } CoroutineUContext; /** @@ -59,7 +59,7 @@ typedef struct { CoroutineUContext leader; /** Information for the signal handler (trampoline) */ - jmp_buf tr_reenter; + sigjmp_buf tr_reenter; volatile sig_atomic_t tr_called; void *tr_handler; } CoroutineThreadState; @@ -115,8 +115,8 @@ static void __attribute__((constructor)) coroutine_init(void) static void coroutine_bootstrap(CoroutineUContext *self, Coroutine *co) { /* Initialize longjmp environment and switch back the caller */ - if (!setjmp(self->env)) { - longjmp(*(jmp_buf *)co->entry_arg, 1); + if (!sigsetjmp(self->env, 0)) { + siglongjmp(*(sigjmp_buf *)co->entry_arg, 1); } while (true) { @@ -145,14 +145,14 @@ static void coroutine_trampoline(int signal) /* * 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 - * caller can reestablish everything and do a longjmp here again. + * caller can reestablish everything and do a siglongjmp here again. */ - if (!setjmp(coTS->tr_reenter)) { + if (!sigsetjmp(coTS->tr_reenter, 0)) { return; } /* - * Ok, the caller has longjmp'ed back to us, so now prepare + * Ok, the caller has siglongjmp'ed back to us, so now prepare * 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 @@ -179,7 +179,7 @@ static Coroutine *coroutine_new(void) /* The way to manipulate stack is with the sigaltstack function. We * prepare a stack, with it delivering a signal to ourselves and then - * put setjmp/longjmp where needed. + * put sigsetjmp/siglongjmp where needed. * 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 @@ -220,7 +220,7 @@ static Coroutine *coroutine_new(void) /* * Now transfer control onto the signal stack and set it up. - * It will return immediately via "return" after the setjmp() + * It will return immediately via "return" after the sigsetjmp() * was performed. Be careful here with race conditions. The * signal can be delivered the first time sigsuspend() is * called. @@ -261,8 +261,8 @@ static Coroutine *coroutine_new(void) * type-conversion warnings related to the `volatile' qualifier and * the fact that `jmp_buf' usually is an array type. */ - if (!setjmp(old_env)) { - longjmp(coTS->tr_reenter, 1); + if (!sigsetjmp(old_env, 0)) { + siglongjmp(coTS->tr_reenter, 1); } /* @@ -311,9 +311,9 @@ CoroutineAction qemu_coroutine_switch(Coroutine *from_, Coroutine *to_, s->current = to_; - ret = setjmp(from->env); + ret = sigsetjmp(from->env, 0); if (ret == 0) { - longjmp(to->env, action); + siglongjmp(to->env, action); } return ret; } -- cgit v1.2.1