github.com/afumu/libc@v0.0.6/musl/src/thread/pthread_barrier_wait.c (about)

     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  }