1 #include "pthread_impl.h"
3 static int pshared_barrier_wait(pthread_barrier_t *b)
5 int limit = (b->_b_limit & INT_MAX) + 1;
9 if (limit==1) return PTHREAD_BARRIER_SERIAL_THREAD;
11 while ((v=a_cas(&b->_b_lock, 0, limit)))
12 __wait(&b->_b_lock, &b->_b_waiters, v, 0);
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);
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);
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);
33 while ((v=b->_b_count))
34 __wait(&b->_b_count, &b->_b_waiters2, v, 0);
37 /* Perform a recursive unlock suitable for self-sync'd destruction */
41 } while (a_cas(&b->_b_lock, v, v==INT_MIN+1 ? 0 : v-1) != v);
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);
57 volatile int finished;
60 int pthread_barrier_wait(pthread_barrier_t *b)
62 int limit = b->_b_limit;
63 struct instance *inst;
65 /* Trivial case: count was set at 1 */
66 if (!limit) return PTHREAD_BARRIER_SERIAL_THREAD;
68 /* Process-shared barriers require a separate, inefficient wait */
69 if (limit < 0) return pshared_barrier_wait(b);
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);
76 /* First thread to enter the barrier becomes the "instance owner" */
78 struct instance new_inst = { 0 };
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)
85 a_inc(&inst->finished);
86 while (inst->finished == 1)
87 __syscall(SYS_futex,&inst->finished,FUTEX_WAIT|128,1,0) != -ENOSYS
88 || __syscall(SYS_futex,&inst->finished,FUTEX_WAIT,1,0);
89 return PTHREAD_BARRIER_SERIAL_THREAD;
92 /* Last thread to enter the barrier wakes all non-instance-owners */
93 if (++inst->count == limit) {
95 a_store(&b->_b_lock, 0);
96 if (b->_b_waiters) __wake(&b->_b_lock, 1, 1);
97 a_store(&inst->last, 1);
99 __wake(&inst->last, -1, 1);
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);
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);