1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20: #include <endian.h>
21: #include <errno.h>
22: #include <sysdep.h>
23: #include <lowlevellock.h>
24: #include <pthread.h>
25: #include <pthreadP.h>
26:
27: #include <shlib-compat.h>
28:
29:
30: struct _condvar_cleanup_buffer
31: {
32: int oldtype;
33: pthread_cond_t *cond;
34: pthread_mutex_t *mutex;
35: unsigned int bc_seq;
36: };
37:
38:
39: void
40: __attribute__ ((visibility ("hidden")))
41: __condvar_cleanup (void *arg)
42: {
43: struct _condvar_cleanup_buffer *cbuffer =
44: (struct _condvar_cleanup_buffer *) arg;
45: unsigned int destroying;
46: int pshared = (cbuffer->cond->__data.__mutex == (void *) ~0l)
47: ? LLL_SHARED : LLL_PRIVATE;
48:
49:
50: lll_lock (cbuffer->cond->__data.__lock, pshared);
51:
52: if (cbuffer->bc_seq == cbuffer->cond->__data.__broadcast_seq)
53: {
54:
55:
56:
57:
58: if (cbuffer->cond->__data.__wakeup_seq
59: < cbuffer->cond->__data.__total_seq)
60: {
61: ++cbuffer->cond->__data.__wakeup_seq;
62: ++cbuffer->cond->__data.__futex;
63: }
64: ++cbuffer->cond->__data.__woken_seq;
65: }
66:
67: cbuffer->cond->__data.__nwaiters -= 1 << COND_NWAITERS_SHIFT;
68:
69:
70:
71:
72: destroying = 0;
73: if (cbuffer->cond->__data.__total_seq == -1ULL
74: && cbuffer->cond->__data.__nwaiters < (1 << COND_NWAITERS_SHIFT))
75: {
76: lll_futex_wake (&cbuffer->cond->__data.__nwaiters, 1, pshared);
77: destroying = 1;
78: }
79:
80:
81: lll_unlock (cbuffer->cond->__data.__lock, pshared);
82:
83:
84: if (! destroying)
85: lll_futex_wake (&cbuffer->cond->__data.__futex, INT_MAX, pshared);
86:
87:
88:
89: __pthread_mutex_cond_lock (cbuffer->mutex);
90: }
91:
92:
93: int
94: __pthread_cond_wait (cond, mutex)
95: pthread_cond_t *cond;
96: pthread_mutex_t *mutex;
97: {
98: struct _pthread_cleanup_buffer buffer;
99: struct _condvar_cleanup_buffer cbuffer;
100: int err;
101: int pshared = (cond->__data.__mutex == (void *) ~0l)
102: ? LLL_SHARED : LLL_PRIVATE;
103:
104:
105: lll_lock (cond->__data.__lock, pshared);
106:
107:
108: err = __pthread_mutex_unlock_usercnt (mutex, 0);
109: if (__builtin_expect (err, 0))
110: {
111: lll_unlock (cond->__data.__lock, pshared);
112: return err;
113: }
114:
115:
116: ++cond->__data.__total_seq;
117: ++cond->__data.__futex;
118: cond->__data.__nwaiters += 1 << COND_NWAITERS_SHIFT;
119:
120:
121:
122:
123: if (cond->__data.__mutex != (void *) ~0l)
124: cond->__data.__mutex = mutex;
125:
126:
127: cbuffer.cond = cond;
128: cbuffer.mutex = mutex;
129:
130:
131:
132: __pthread_cleanup_push (&buffer, __condvar_cleanup, &cbuffer);
133:
134:
135:
136: unsigned long long int val;
137: unsigned long long int seq;
138: val = seq = cond->__data.__wakeup_seq;
139:
140: cbuffer.bc_seq = cond->__data.__broadcast_seq;
141:
142: do
143: {
144: unsigned int futex_val = cond->__data.__futex;
145:
146:
147: lll_unlock (cond->__data.__lock, pshared);
148:
149:
150: cbuffer.oldtype = __pthread_enable_asynccancel ();
151:
152:
153: lll_futex_wait (&cond->__data.__futex, futex_val, pshared);
154:
155:
156: __pthread_disable_asynccancel (cbuffer.oldtype);
157:
158:
159: lll_lock (cond->__data.__lock, pshared);
160:
161:
162: if (cbuffer.bc_seq != cond->__data.__broadcast_seq)
163: goto bc_out;
164:
165:
166: val = cond->__data.__wakeup_seq;
167: }
168: while (val == seq || cond->__data.__woken_seq == val);
169:
170:
171: ++cond->__data.__woken_seq;
172:
173: bc_out:
174:
175: cond->__data.__nwaiters -= 1 << COND_NWAITERS_SHIFT;
176:
177:
178:
179:
180: if (cond->__data.__total_seq == -1ULL
181: && cond->__data.__nwaiters < (1 << COND_NWAITERS_SHIFT))
182: lll_futex_wake (&cond->__data.__nwaiters, 1, pshared);
183:
184:
185: lll_unlock (cond->__data.__lock, pshared);
186:
187:
188: __pthread_cleanup_pop (&buffer, 0);
189:
190:
191: return __pthread_mutex_cond_lock (mutex);
192: }
193:
194: versioned_symbol (libpthread, __pthread_cond_wait, pthread_cond_wait,
195: GLIBC_2_3_2);