pthread_barrier_wait.c raw

   1  #include "pthread_impl.h"
   2  
   3  static int pshared_barrier_wait(pthread_barrier_t *b)
   4  {
   5  	int limit = (b->_b_limit & INT_MAX) + 1;
   6  	int ret = 0;
   7  	int v, w;
   8  
   9  	if (limit==1) return PTHREAD_BARRIER_SERIAL_THREAD;
  10  
  11  	while ((v=a_cas(&b->_b_lock, 0, limit)))
  12  		__wait(&b->_b_lock, &b->_b_waiters, v, 0);
  13  
  14  	/* Wait for <limit> threads to get to the barrier */
  15  	if (++b->_b_count == limit) {
  16  		a_store(&b->_b_count, 0);
  17  		ret = PTHREAD_BARRIER_SERIAL_THREAD;
  18  		if (b->_b_waiters2) __wake(&b->_b_count, -1, 0);
  19  	} else {
  20  		a_store(&b->_b_lock, 0);
  21  		if (b->_b_waiters) __wake(&b->_b_lock, 1, 0);
  22  		while ((v=b->_b_count)>0)
  23  			__wait(&b->_b_count, &b->_b_waiters2, v, 0);
  24  	}
  25  
  26  	__vm_lock();
  27  
  28  	/* Ensure all threads have a vm lock before proceeding */
  29  	if (a_fetch_add(&b->_b_count, -1)==1-limit) {
  30  		a_store(&b->_b_count, 0);
  31  		if (b->_b_waiters2) __wake(&b->_b_count, -1, 0);
  32  	} else {
  33  		while ((v=b->_b_count))
  34  			__wait(&b->_b_count, &b->_b_waiters2, v, 0);
  35  	}
  36  	
  37  	/* Perform a recursive unlock suitable for self-sync'd destruction */
  38  	do {
  39  		v = b->_b_lock;
  40  		w = b->_b_waiters;
  41  	} while (a_cas(&b->_b_lock, v, v==INT_MIN+1 ? 0 : v-1) != v);
  42  
  43  	/* Wake a thread waiting to reuse or destroy the barrier */
  44  	if (v==INT_MIN+1 || (v==1 && w))
  45  		__wake(&b->_b_lock, 1, 0);
  46  
  47  	__vm_unlock();
  48  
  49  	return ret;
  50  }
  51  
  52  struct instance
  53  {
  54  	volatile int count;
  55  	volatile int last;
  56  	volatile int waiters;
  57  	volatile int finished;
  58  };
  59  
  60  int pthread_barrier_wait(pthread_barrier_t *b)
  61  {
  62  	int limit = b->_b_limit;
  63  	struct instance *inst;
  64  
  65  	/* Trivial case: count was set at 1 */
  66  	if (!limit) return PTHREAD_BARRIER_SERIAL_THREAD;
  67  
  68  	/* Process-shared barriers require a separate, inefficient wait */
  69  	if (limit < 0) return pshared_barrier_wait(b);
  70  
  71  	/* Otherwise we need a lock on the barrier object */
  72  	while (a_swap(&b->_b_lock, 1))
  73  		__wait(&b->_b_lock, &b->_b_waiters, 1, 1);
  74  	inst = b->_b_inst;
  75  
  76  	/* First thread to enter the barrier becomes the "instance owner" */
  77  	if (!inst) {
  78  		struct instance new_inst = { 0 };
  79  		int spins = 200;
  80  		b->_b_inst = inst = &new_inst;
  81  		a_store(&b->_b_lock, 0);
  82  		if (b->_b_waiters) __wake(&b->_b_lock, 1, 1);
  83  		while (spins-- && !inst->finished)
  84  			a_spin();
  85  		a_inc(&inst->finished);
  86  		while (inst->finished == 1)
  87  			__syscall(SYS_futex,&inst->finished,FUTEX_WAIT|FUTEX_PRIVATE,1,0) != -ENOSYS
  88  			|| __syscall(SYS_futex,&inst->finished,FUTEX_WAIT,1,0);
  89  		return PTHREAD_BARRIER_SERIAL_THREAD;
  90  	}
  91  
  92  	/* Last thread to enter the barrier wakes all non-instance-owners */
  93  	if (++inst->count == limit) {
  94  		b->_b_inst = 0;
  95  		a_store(&b->_b_lock, 0);
  96  		if (b->_b_waiters) __wake(&b->_b_lock, 1, 1);
  97  		a_store(&inst->last, 1);
  98  		if (inst->waiters)
  99  			__wake(&inst->last, -1, 1);
 100  	} else {
 101  		a_store(&b->_b_lock, 0);
 102  		if (b->_b_waiters) __wake(&b->_b_lock, 1, 1);
 103  		__wait(&inst->last, &inst->waiters, 0, 1);
 104  	}
 105  
 106  	/* Last thread to exit the barrier wakes the instance owner */
 107  	if (a_fetch_add(&inst->count,-1)==1 && a_fetch_add(&inst->finished,1))
 108  		__wake(&inst->finished, 1, 1);
 109  
 110  	return 0;
 111  }
 112