github.com/afumu/libc@v0.0.6/musl/src/linux/membarrier.c (about) 1 #include <sys/membarrier.h> 2 #include <semaphore.h> 3 #include <signal.h> 4 #include <string.h> 5 #include "pthread_impl.h" 6 #include "syscall.h" 7 8 static void dummy_0(void) 9 { 10 } 11 12 static void dummy_1(pthread_t t) 13 { 14 } 15 16 weak_alias(dummy_0, __tl_lock); 17 weak_alias(dummy_0, __tl_unlock); 18 weak_alias(dummy_1, __tl_sync); 19 20 static sem_t barrier_sem; 21 22 static void bcast_barrier(int s) 23 { 24 sem_post(&barrier_sem); 25 } 26 27 int __membarrier(int cmd, int flags) 28 { 29 int r = __syscall(SYS_membarrier, cmd, flags); 30 /* Emulate the private expedited command, which is needed by the 31 * dynamic linker for installation of dynamic TLS, for older 32 * kernels that lack the syscall. Unlike the syscall, this only 33 * synchronizes with threads of the process, not other processes 34 * sharing the VM, but such sharing is not a supported usage 35 * anyway. */ 36 if (r && cmd == MEMBARRIER_CMD_PRIVATE_EXPEDITED && !flags) { 37 pthread_t self=__pthread_self(), td; 38 sigset_t set; 39 __block_app_sigs(&set); 40 __tl_lock(); 41 sem_init(&barrier_sem, 0, 0); 42 struct sigaction sa = { 43 .sa_flags = SA_RESTART, 44 .sa_handler = bcast_barrier 45 }; 46 memset(&sa.sa_mask, -1, sizeof sa.sa_mask); 47 if (!__libc_sigaction(SIGSYNCCALL, &sa, 0)) { 48 for (td=self->next; td!=self; td=td->next) 49 __syscall(SYS_tkill, td->tid, SIGSYNCCALL); 50 for (td=self->next; td!=self; td=td->next) 51 sem_wait(&barrier_sem); 52 r = 0; 53 sa.sa_handler = SIG_IGN; 54 __libc_sigaction(SIGSYNCCALL, &sa, 0); 55 } 56 sem_destroy(&barrier_sem); 57 __tl_unlock(); 58 __restore_sigs(&set); 59 } 60 return __syscall_ret(r); 61 } 62 63 void __membarrier_init(void) 64 { 65 /* If membarrier is linked, attempt to pre-register to be able to use 66 * the private expedited command before the process becomes multi- 67 * threaded, since registering later has bad, potentially unbounded 68 * latency. This syscall should be essentially free, and it's arguably 69 * a mistake in the API design that registration was even required. 70 * For other commands, registration may impose some cost, so it's left 71 * to the application to do so if desired. Unfortunately this means 72 * library code initialized after the process becomes multi-threaded 73 * cannot use these features without accepting registration latency. */ 74 __syscall(SYS_membarrier, MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED, 0); 75 } 76 77 weak_alias(__membarrier, membarrier);