dns response handling: ignore presence of wrong-type RRs
[musl] / src / thread / pthread_barrier_wait.c
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 }