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);
26 #ifdef __wasilibc_unmodified_upstream /* WASI does not understand processes or locking between them. */
30 /* Ensure all threads have a vm lock before proceeding */
31 if (a_fetch_add(&b
->_b_count
, -1)==1-limit
) {
32 a_store(&b
->_b_count
, 0);
33 if (b
->_b_waiters2
) __wake(&b
->_b_count
, -1, 0);
35 while ((v
=b
->_b_count
))
36 __wait(&b
->_b_count
, &b
->_b_waiters2
, v
, 0);
39 /* Perform a recursive unlock suitable for self-sync'd destruction */
43 } while (a_cas(&b
->_b_lock
, v
, v
==INT_MIN
+1 ? 0 : v
-1) != v
);
45 /* Wake a thread waiting to reuse or destroy the barrier */
46 if (v
==INT_MIN
+1 || (v
==1 && w
))
47 __wake(&b
->_b_lock
, 1, 0);
49 #ifdef __wasilibc_unmodified_upstream /* WASI does not understand processes or locking between them. */
61 volatile int finished
;
64 int pthread_barrier_wait(pthread_barrier_t
*b
)
66 int limit
= b
->_b_limit
;
67 struct instance
*inst
;
69 /* Trivial case: count was set at 1 */
70 if (!limit
) return PTHREAD_BARRIER_SERIAL_THREAD
;
72 /* Process-shared barriers require a separate, inefficient wait */
73 if (limit
< 0) return pshared_barrier_wait(b
);
75 /* Otherwise we need a lock on the barrier object */
76 while (a_swap(&b
->_b_lock
, 1))
77 __wait(&b
->_b_lock
, &b
->_b_waiters
, 1, 1);
80 /* First thread to enter the barrier becomes the "instance owner" */
82 struct instance new_inst
= { 0 };
84 b
->_b_inst
= inst
= &new_inst
;
85 a_store(&b
->_b_lock
, 0);
86 if (b
->_b_waiters
) __wake(&b
->_b_lock
, 1, 1);
87 while (spins
-- && !inst
->finished
)
89 a_inc(&inst
->finished
);
90 while (inst
->finished
== 1)
91 #ifdef __wasilibc_unmodified_upstream
92 __syscall(SYS_futex
,&inst
->finished
,FUTEX_WAIT
|FUTEX_PRIVATE
,1,0) != -ENOSYS
93 || __syscall(SYS_futex
,&inst
->finished
,FUTEX_WAIT
,1,0);
95 __futexwait(&inst
->finished
, 1, 0);
97 return PTHREAD_BARRIER_SERIAL_THREAD
;
100 /* Last thread to enter the barrier wakes all non-instance-owners */
101 if (++inst
->count
== limit
) {
103 a_store(&b
->_b_lock
, 0);
104 if (b
->_b_waiters
) __wake(&b
->_b_lock
, 1, 1);
105 a_store(&inst
->last
, 1);
107 __wake(&inst
->last
, -1, 1);
109 a_store(&b
->_b_lock
, 0);
110 if (b
->_b_waiters
) __wake(&b
->_b_lock
, 1, 1);
111 __wait(&inst
->last
, &inst
->waiters
, 0, 1);
114 /* Last thread to exit the barrier wakes the instance owner */
115 if (a_fetch_add(&inst
->count
,-1)==1 && a_fetch_add(&inst
->finished
,1))
116 __wake(&inst
->finished
, 1, 1);