diff options
author | Rich Felker <dalias@aerifal.cx> | 2019-02-22 02:56:10 -0500 |
---|---|---|
committer | Rich Felker <dalias@aerifal.cx> | 2019-02-22 03:25:39 -0500 |
commit | ba18c1ecc6a18203ad8496791154af86f706f632 (patch) | |
tree | d1e407e0b4f3fbe9e4463e66c960473112159981 /src/linux/membarrier.c | |
parent | 7865d569de7b29dd90b94b5680ec7a2a86ed27af (diff) | |
download | musl-ba18c1ecc6a18203ad8496791154af86f706f632.tar.gz musl-ba18c1ecc6a18203ad8496791154af86f706f632.tar.bz2 musl-ba18c1ecc6a18203ad8496791154af86f706f632.tar.xz musl-ba18c1ecc6a18203ad8496791154af86f706f632.zip |
add membarrier syscall wrapper, refactor dynamic tls install to use it
the motivation for this change is twofold. first, it gets the fallback
logic out of the dynamic linker, improving code readability and
organization. second, it provides application code that wants to use
the membarrier syscall, which depends on preregistration of intent
before the process becomes multithreaded unless unbounded latency is
acceptable, with a symbol that, when linked, ensures that this
registration happens.
Diffstat (limited to 'src/linux/membarrier.c')
-rw-r--r-- | src/linux/membarrier.c | 76 |
1 files changed, 76 insertions, 0 deletions
diff --git a/src/linux/membarrier.c b/src/linux/membarrier.c new file mode 100644 index 00000000..26d143e7 --- /dev/null +++ b/src/linux/membarrier.c @@ -0,0 +1,76 @@ +#include <sys/membarrier.h> +#include <semaphore.h> +#include <signal.h> +#include <string.h> +#include "pthread_impl.h" +#include "syscall.h" + +static void dummy_0(void) +{ +} + +static void dummy_1(pthread_t t) +{ +} + +weak_alias(dummy_0, __tl_lock); +weak_alias(dummy_0, __tl_unlock); +weak_alias(dummy_1, __tl_sync); + +static sem_t barrier_sem; + +static void bcast_barrier(int s) +{ + sem_post(&barrier_sem); +} + +int __membarrier(int cmd, int flags) +{ + int r = __syscall(SYS_membarrier, cmd, flags); + /* Emulate the private expedited command, which is needed by the + * dynamic linker for installation of dynamic TLS, for older + * kernels that lack the syscall. Unlike the syscall, this only + * synchronizes with threads of the process, not other processes + * sharing the VM, but such sharing is not a supported usage + * anyway. */ + if (r && cmd == MEMBARRIER_CMD_PRIVATE_EXPEDITED && !flags) { + pthread_t self=__pthread_self(), td; + sigset_t set; + __block_app_sigs(&set); + __tl_lock(); + sem_init(&barrier_sem, 0, 0); + struct sigaction sa = { + .sa_flags = SA_RESTART, + .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); + sem_destroy(&barrier_sem); + __tl_unlock(); + __restore_sigs(&set); + return 0; + } + return __syscall_ret(r); +} + +void __membarrier_init(void) +{ + /* If membarrier is linked, attempt to pre-register to be able to use + * the private expedited command before the process becomes multi- + * threaded, since registering later has bad, potentially unbounded + * latency. This syscall should be essentially free, and it's arguably + * a mistake in the API design that registration was even required. + * For other commands, registration may impose some cost, so it's left + * to the application to do so if desired. Unfortunately this means + * library code initialized after the process becomes multi-threaded + * cannot use these features without accepting registration latency. */ + __syscall(SYS_membarrier, MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED, 0); +} + +weak_alias(__membarrier, membarrier); |