summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2019-04-09 17:51:54 -0400
committerRich Felker <dalias@aerifal.cx>2019-04-09 17:51:54 -0400
commita01ff71f7c43693ad4954d4ae7863df159cf4073 (patch)
tree08677f7822b7de58016b1c2b5dade67a8e5b7270 /src
parent77846800722914eeba170505c2e7f89e12a6beff (diff)
downloadmusl-a01ff71f7c43693ad4954d4ae7863df159cf4073.tar.gz
musl-a01ff71f7c43693ad4954d4ae7863df159cf4073.tar.bz2
musl-a01ff71f7c43693ad4954d4ae7863df159cf4073.tar.xz
musl-a01ff71f7c43693ad4954d4ae7863df159cf4073.zip
in membarrier fallback, allow for possibility that sigaction fails
this is a workaround to avoid a crashing regression on qemu-user when dynamic TLS is installed at dlopen time. the sigaction syscall should not be able to fail, but it does fail for implementation-internal signals under qemu user-level emulation if the host libc qemu is running under reserves the same signals for implementation-internal use, since qemu makes no provision to redirect/emulate them. after sigaction fails, the subsequent tkill would terminate the process abnormally as the default action. no provision to account for membarrier failing is made in the dynamic linker code that installs new TLS. at the formal level, the missing barrier in this case is incorrect, and perhaps we should fail the dlopen operation, but in practice all the archs we support (and probably all real-world archs except alpha, which isn't yet supported) should give the right behavior with no barrier at all as a consequence of consume-order properties. in the long term, this workaround should be supplemented or replaced by something better -- a different fallback approach to ensuring memory consistency, or dynamic allocation of implementation-internal signals. the latter is appealing in that it would allow cancellation to work under qemu-user too, and would even allow many levels of nested emulation.
Diffstat (limited to 'src')
-rw-r--r--src/linux/membarrier.c17
1 files changed, 9 insertions, 8 deletions
diff --git a/src/linux/membarrier.c b/src/linux/membarrier.c
index 26d143e7..9ebe906e 100644
--- a/src/linux/membarrier.c
+++ b/src/linux/membarrier.c
@@ -44,17 +44,18 @@ int __membarrier(int cmd, int flags)
.sa_handler = bcast_barrier
};
memset(&sa.sa_mask, -1, sizeof sa.sa_mask);
- __libc_sigaction(SIGSYNCCALL, &sa, 0);
- for (td=self->next; td!=self; td=td->next)
- __syscall(SYS_tkill, td->tid, SIGSYNCCALL);
- for (td=self->next; td!=self; td=td->next)
- sem_wait(&barrier_sem);
- sa.sa_handler = SIG_IGN;
- __libc_sigaction(SIGSYNCCALL, &sa, 0);
+ if (!__libc_sigaction(SIGSYNCCALL, &sa, 0)) {
+ for (td=self->next; td!=self; td=td->next)
+ __syscall(SYS_tkill, td->tid, SIGSYNCCALL);
+ for (td=self->next; td!=self; td=td->next)
+ sem_wait(&barrier_sem);
+ r = 0;
+ sa.sa_handler = SIG_IGN;
+ __libc_sigaction(SIGSYNCCALL, &sa, 0);
+ }
sem_destroy(&barrier_sem);
__tl_unlock();
__restore_sigs(&set);
- return 0;
}
return __syscall_ret(r);
}