>From 08d4bb6a98fa731025683f20afe1381291d26031 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Wed, 20 Jan 2021 16:59:40 +0100 Subject: [RFC] coroutine-sigaltstack: Add SIGUSR2 mutex Modifying signal handlers or the signal handling stack is a process-global operation. When two threads run coroutine-sigaltstack's qemu_coroutine_new() concurrently, thay may interfere with each other, e.g.: - One of the threads may revert the SIGUSR2 handler back to the default between the other thread setting up coroutine_trampoline() as the handler and raising SIGUSR2. That SIGUSR2 will then lead to the process exiting. - Both threads may set up their coroutine stack with sigaltstack() simultaneously, so that only one of them sticks. Both then raise SIGUSR2, which goes to each of the threads separately, but both signal handler invocations will then use the same stack, which cannot work. We have to ensure that only one thread at a time can modify the process-global SIGUSR2 handler and the signal handling stack. To do so, wrap the whole section where that is done in a mutex. Signed-off-by: Max Reitz --- util/coroutine-sigaltstack.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/util/coroutine-sigaltstack.c b/util/coroutine-sigaltstack.c index aade82afb8..1e48ec4461 100644 --- a/util/coroutine-sigaltstack.c +++ b/util/coroutine-sigaltstack.c @@ -157,6 +157,7 @@ Coroutine *qemu_coroutine_new(void) sigset_t sigs; sigset_t osigs; sigjmp_buf old_env; + static pthread_mutex_t sigusr2_mutex = PTHREAD_MUTEX_INITIALIZER; /* The way to manipulate stack is with the sigaltstack function. We * prepare a stack, with it delivering a signal to ourselves and then @@ -186,6 +187,13 @@ Coroutine *qemu_coroutine_new(void) sa.sa_handler = coroutine_trampoline; sigfillset(&sa.sa_mask); sa.sa_flags = SA_ONSTACK; + + /* + * Modifying signal handlers and the signal handling stack are + * process-global operations. We must not run this code in + * multiple threads at once. + */ + pthread_mutex_lock(&sigusr2_mutex); if (sigaction(SIGUSR2, &sa, &osa) != 0) { abort(); } @@ -234,6 +242,8 @@ Coroutine *qemu_coroutine_new(void) * Restore the old SIGUSR2 signal handler and mask */ sigaction(SIGUSR2, &osa, NULL); + pthread_mutex_unlock(&sigusr2_mutex); + pthread_sigmask(SIG_SETMASK, &osigs, NULL); /* -- 2.29.2