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);