membarrier.c raw

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