Wed Jan 29 15:07:46 2020 UTC ()
Use pthread_condattr_t and pthread_cond_t magic fields

Validate _PT_CONDATTR_MAGIC and _PT_COND_MAGIC respectively.


(kamil)
diff -r1.66 -r1.67 src/lib/libpthread/pthread_cond.c

cvs diff -r1.66 -r1.67 src/lib/libpthread/pthread_cond.c (switch to unified diff)

--- src/lib/libpthread/pthread_cond.c 2020/01/13 18:22:56 1.66
+++ src/lib/libpthread/pthread_cond.c 2020/01/29 15:07:46 1.67
@@ -1,450 +1,468 @@ @@ -1,450 +1,468 @@
1/* $NetBSD: pthread_cond.c,v 1.66 2020/01/13 18:22:56 ad Exp $ */ 1/* $NetBSD: pthread_cond.c,v 1.67 2020/01/29 15:07:46 kamil Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 2001, 2006, 2007, 2008 The NetBSD Foundation, Inc. 4 * Copyright (c) 2001, 2006, 2007, 2008 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to The NetBSD Foundation 7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Nathan J. Williams and Andrew Doran. 8 * by Nathan J. Williams and Andrew Doran.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright 15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the 16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution. 17 * documentation and/or other materials provided with the distribution.
18 * 18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE. 29 * POSSIBILITY OF SUCH DAMAGE.
30 */ 30 */
31 31
32/* 32/*
33 * We assume that there will be no contention on pthread_cond_t::ptc_lock 33 * We assume that there will be no contention on pthread_cond_t::ptc_lock
34 * because functioning applications must call both the wait and wakeup 34 * because functioning applications must call both the wait and wakeup
35 * functions while holding the same application provided mutex. The 35 * functions while holding the same application provided mutex. The
36 * spinlock is present only to prevent libpthread causing the application 36 * spinlock is present only to prevent libpthread causing the application
37 * to crash or malfunction as a result of corrupted data structures, in 37 * to crash or malfunction as a result of corrupted data structures, in
38 * the event that the application is buggy. 38 * the event that the application is buggy.
39 * 39 *
40 * If there is contention on spinlock when real-time threads are in use, 40 * If there is contention on spinlock when real-time threads are in use,
41 * it could cause a deadlock due to priority inversion: the thread holding 41 * it could cause a deadlock due to priority inversion: the thread holding
42 * the spinlock may not get CPU time to make forward progress and release 42 * the spinlock may not get CPU time to make forward progress and release
43 * the spinlock to a higher priority thread that is waiting for it. 43 * the spinlock to a higher priority thread that is waiting for it.
44 * Contention on the spinlock will only occur with buggy applications, 44 * Contention on the spinlock will only occur with buggy applications,
45 * so at the time of writing it's not considered a major bug in libpthread. 45 * so at the time of writing it's not considered a major bug in libpthread.
46 */ 46 */
47 47
48#include <sys/cdefs.h> 48#include <sys/cdefs.h>
49__RCSID("$NetBSD: pthread_cond.c,v 1.66 2020/01/13 18:22:56 ad Exp $"); 49__RCSID("$NetBSD: pthread_cond.c,v 1.67 2020/01/29 15:07:46 kamil Exp $");
50 50
51#include <stdlib.h> 51#include <stdlib.h>
52#include <errno.h> 52#include <errno.h>
53#include <sys/time.h> 53#include <sys/time.h>
54#include <sys/types.h> 54#include <sys/types.h>
55 55
56#include "pthread.h" 56#include "pthread.h"
57#include "pthread_int.h" 57#include "pthread_int.h"
58#include "reentrant.h" 58#include "reentrant.h"
59 59
60int _sys___nanosleep50(const struct timespec *, struct timespec *); 60int _sys___nanosleep50(const struct timespec *, struct timespec *);
61 61
62extern int pthread__started; 62extern int pthread__started;
63 63
64static int pthread_cond_wait_nothread(pthread_t, pthread_mutex_t *, 64static int pthread_cond_wait_nothread(pthread_t, pthread_mutex_t *,
65 pthread_cond_t *, const struct timespec *); 65 pthread_cond_t *, const struct timespec *);
66 66
67int _pthread_cond_has_waiters_np(pthread_cond_t *); 67int _pthread_cond_has_waiters_np(pthread_cond_t *);
68 68
69__weak_alias(pthread_cond_has_waiters_np,_pthread_cond_has_waiters_np) 69__weak_alias(pthread_cond_has_waiters_np,_pthread_cond_has_waiters_np)
70 70
71__strong_alias(__libc_cond_init,pthread_cond_init) 71__strong_alias(__libc_cond_init,pthread_cond_init)
72__strong_alias(__libc_cond_signal,pthread_cond_signal) 72__strong_alias(__libc_cond_signal,pthread_cond_signal)
73__strong_alias(__libc_cond_broadcast,pthread_cond_broadcast) 73__strong_alias(__libc_cond_broadcast,pthread_cond_broadcast)
74__strong_alias(__libc_cond_wait,pthread_cond_wait) 74__strong_alias(__libc_cond_wait,pthread_cond_wait)
75__strong_alias(__libc_cond_timedwait,pthread_cond_timedwait) 75__strong_alias(__libc_cond_timedwait,pthread_cond_timedwait)
76__strong_alias(__libc_cond_destroy,pthread_cond_destroy) 76__strong_alias(__libc_cond_destroy,pthread_cond_destroy)
77 77
78static clockid_t 78static clockid_t
79pthread_cond_getclock(const pthread_cond_t *cond) 79pthread_cond_getclock(const pthread_cond_t *cond)
80{ 80{
 81
 82 pthread__error(EINVAL, "Invalid condition variable",
 83 cond->ptc_magic == _PT_COND_MAGIC);
 84
81 return cond->ptc_private ?  85 return cond->ptc_private ?
82 *(clockid_t *)cond->ptc_private : CLOCK_REALTIME; 86 *(clockid_t *)cond->ptc_private : CLOCK_REALTIME;
83} 87}
84 88
85int 89int
86pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr) 90pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
87{ 91{
88 if (__predict_false(__uselibcstub)) 92 if (__predict_false(__uselibcstub))
89 return __libc_cond_init_stub(cond, attr); 93 return __libc_cond_init_stub(cond, attr);
90 94
91 pthread__error(EINVAL, "Invalid condition variable attribute", 95 pthread__error(EINVAL, "Invalid condition variable attribute",
92 (attr == NULL) || (attr->ptca_magic == _PT_CONDATTR_MAGIC)); 96 (attr == NULL) || (attr->ptca_magic == _PT_CONDATTR_MAGIC));
93 97
94 cond->ptc_magic = _PT_COND_MAGIC; 98 cond->ptc_magic = _PT_COND_MAGIC;
95 pthread_lockinit(&cond->ptc_lock); 99 pthread_lockinit(&cond->ptc_lock);
96 PTQ_INIT(&cond->ptc_waiters); 100 PTQ_INIT(&cond->ptc_waiters);
97 cond->ptc_mutex = NULL; 101 cond->ptc_mutex = NULL;
98 if (attr && attr->ptca_private) { 102 if (attr && attr->ptca_private) {
99 cond->ptc_private = malloc(sizeof(clockid_t)); 103 cond->ptc_private = malloc(sizeof(clockid_t));
100 if (cond->ptc_private == NULL) 104 if (cond->ptc_private == NULL)
101 return errno; 105 return errno;
102 *(clockid_t *)cond->ptc_private = 106 *(clockid_t *)cond->ptc_private =
103 *(clockid_t *)attr->ptca_private; 107 *(clockid_t *)attr->ptca_private;
104 } else 108 } else
105 cond->ptc_private = NULL; 109 cond->ptc_private = NULL;
106 110
107 return 0; 111 return 0;
108} 112}
109 113
110 114
111int 115int
112pthread_cond_destroy(pthread_cond_t *cond) 116pthread_cond_destroy(pthread_cond_t *cond)
113{ 117{
114 if (__predict_false(__uselibcstub)) 118 if (__predict_false(__uselibcstub))
115 return __libc_cond_destroy_stub(cond); 119 return __libc_cond_destroy_stub(cond);
116 120
117 pthread__error(EINVAL, "Invalid condition variable", 121 pthread__error(EINVAL, "Invalid condition variable",
118 cond->ptc_magic == _PT_COND_MAGIC); 122 cond->ptc_magic == _PT_COND_MAGIC);
119 pthread__error(EBUSY, "Destroying condition variable in use", 123 pthread__error(EBUSY, "Destroying condition variable in use",
120 cond->ptc_mutex == NULL); 124 cond->ptc_mutex == NULL);
121 125
122 cond->ptc_magic = _PT_COND_DEAD; 126 cond->ptc_magic = _PT_COND_DEAD;
123 free(cond->ptc_private); 127 free(cond->ptc_private);
124 128
125 return 0; 129 return 0;
126} 130}
127 131
128int 132int
129pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, 133pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
130 const struct timespec *abstime) 134 const struct timespec *abstime)
131{ 135{
132 pthread_t self; 136 pthread_t self;
133 int retval; 137 int retval;
134 clockid_t clkid = pthread_cond_getclock(cond); 138 clockid_t clkid = pthread_cond_getclock(cond);
135 139
136 if (__predict_false(__uselibcstub)) 140 if (__predict_false(__uselibcstub))
137 return __libc_cond_timedwait_stub(cond, mutex, abstime); 141 return __libc_cond_timedwait_stub(cond, mutex, abstime);
138 142
139 pthread__error(EINVAL, "Invalid condition variable", 143 pthread__error(EINVAL, "Invalid condition variable",
140 cond->ptc_magic == _PT_COND_MAGIC); 144 cond->ptc_magic == _PT_COND_MAGIC);
141 pthread__error(EINVAL, "Invalid mutex", 145 pthread__error(EINVAL, "Invalid mutex",
142 mutex->ptm_magic == _PT_MUTEX_MAGIC); 146 mutex->ptm_magic == _PT_MUTEX_MAGIC);
143 pthread__error(EPERM, "Mutex not locked in condition wait", 147 pthread__error(EPERM, "Mutex not locked in condition wait",
144 mutex->ptm_owner != NULL); 148 mutex->ptm_owner != NULL);
145 149
146 self = pthread__self(); 150 self = pthread__self();
147 151
148 /* Just hang out for a while if threads aren't running yet. */ 152 /* Just hang out for a while if threads aren't running yet. */
149 if (__predict_false(pthread__started == 0)) { 153 if (__predict_false(pthread__started == 0)) {
150 return pthread_cond_wait_nothread(self, mutex, cond, abstime); 154 return pthread_cond_wait_nothread(self, mutex, cond, abstime);
151 } 155 }
152 if (__predict_false(self->pt_cancel)) { 156 if (__predict_false(self->pt_cancel)) {
153 pthread__cancelled(); 157 pthread__cancelled();
154 } 158 }
155 159
156 /* Note this thread as waiting on the CV. */ 160 /* Note this thread as waiting on the CV. */
157 pthread__spinlock(self, &cond->ptc_lock); 161 pthread__spinlock(self, &cond->ptc_lock);
158 cond->ptc_mutex = mutex; 162 cond->ptc_mutex = mutex;
159 PTQ_INSERT_HEAD(&cond->ptc_waiters, self, pt_sleep); 163 PTQ_INSERT_HEAD(&cond->ptc_waiters, self, pt_sleep);
160 self->pt_sleepobj = cond; 164 self->pt_sleepobj = cond;
161 pthread__spinunlock(self, &cond->ptc_lock); 165 pthread__spinunlock(self, &cond->ptc_lock);
162 166
163 do { 167 do {
164 self->pt_willpark = 1; 168 self->pt_willpark = 1;
165 pthread_mutex_unlock(mutex); 169 pthread_mutex_unlock(mutex);
166 self->pt_willpark = 0; 170 self->pt_willpark = 0;
167 do { 171 do {
168 retval = _lwp_park(clkid, TIMER_ABSTIME, 172 retval = _lwp_park(clkid, TIMER_ABSTIME,
169 __UNCONST(abstime), self->pt_unpark, 173 __UNCONST(abstime), self->pt_unpark,
170 __UNVOLATILE(&mutex->ptm_waiters), 174 __UNVOLATILE(&mutex->ptm_waiters),
171 __UNVOLATILE(&mutex->ptm_waiters)); 175 __UNVOLATILE(&mutex->ptm_waiters));
172 self->pt_unpark = 0; 176 self->pt_unpark = 0;
173 } while (retval == -1 && errno == ESRCH); 177 } while (retval == -1 && errno == ESRCH);
174 pthread_mutex_lock(mutex); 178 pthread_mutex_lock(mutex);
175 179
176 /* 180 /*
177 * If we have cancelled then exit. POSIX dictates that 181 * If we have cancelled then exit. POSIX dictates that
178 * the mutex must be held when we action the cancellation. 182 * the mutex must be held when we action the cancellation.
179 * 183 *
180 * If we absorbed a pthread_cond_signal() and cannot take 184 * If we absorbed a pthread_cond_signal() and cannot take
181 * the wakeup, we must ensure that another thread does. 185 * the wakeup, we must ensure that another thread does.
182 * 186 *
183 * If awoke early, we may still be on the sleep queue and 187 * If awoke early, we may still be on the sleep queue and
184 * must remove ourself. 188 * must remove ourself.
185 */ 189 */
186 if (__predict_false(retval != 0)) { 190 if (__predict_false(retval != 0)) {
187 switch (errno) { 191 switch (errno) {
188 case EINTR: 192 case EINTR:
189 case EALREADY: 193 case EALREADY:
190 retval = 0; 194 retval = 0;
191 break; 195 break;
192 default: 196 default:
193 retval = errno; 197 retval = errno;
194 break; 198 break;
195 } 199 }
196 } 200 }
197 if (__predict_false(self->pt_cancel | retval)) { 201 if (__predict_false(self->pt_cancel | retval)) {
198 pthread_cond_signal(cond); 202 pthread_cond_signal(cond);
199 if (self->pt_cancel) { 203 if (self->pt_cancel) {
200 pthread__cancelled(); 204 pthread__cancelled();
201 } 205 }
202 break; 206 break;
203 } 207 }
204 } while (self->pt_sleepobj != NULL); 208 } while (self->pt_sleepobj != NULL);
205 209
206 return retval; 210 return retval;
207} 211}
208 212
209int 213int
210pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) 214pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
211{ 215{
212 if (__predict_false(__uselibcstub)) 216 if (__predict_false(__uselibcstub))
213 return __libc_cond_wait_stub(cond, mutex); 217 return __libc_cond_wait_stub(cond, mutex);
214 218
215 return pthread_cond_timedwait(cond, mutex, NULL); 219 return pthread_cond_timedwait(cond, mutex, NULL);
216} 220}
217 221
218static int __noinline 222static int __noinline
219pthread__cond_wake_one(pthread_cond_t *cond) 223pthread__cond_wake_one(pthread_cond_t *cond)
220{ 224{
221 pthread_t self, signaled; 225 pthread_t self, signaled;
222 pthread_mutex_t *mutex; 226 pthread_mutex_t *mutex;
223 lwpid_t lid; 227 lwpid_t lid;
224 228
225 pthread__error(EINVAL, "Invalid condition variable", 
226 cond->ptc_magic == _PT_COND_MAGIC); 
227 
228 /* 229 /*
229 * Pull the first thread off the queue. If the current thread 230 * Pull the first thread off the queue. If the current thread
230 * is associated with the condition variable, remove it without 231 * is associated with the condition variable, remove it without
231 * awakening (error case in pthread_cond_timedwait()). 232 * awakening (error case in pthread_cond_timedwait()).
232 */ 233 */
233 self = pthread__self(); 234 self = pthread__self();
234 pthread__spinlock(self, &cond->ptc_lock); 235 pthread__spinlock(self, &cond->ptc_lock);
235 if (self->pt_sleepobj == cond) { 236 if (self->pt_sleepobj == cond) {
236 PTQ_REMOVE(&cond->ptc_waiters, self, pt_sleep); 237 PTQ_REMOVE(&cond->ptc_waiters, self, pt_sleep);
237 self->pt_sleepobj = NULL; 238 self->pt_sleepobj = NULL;
238 } 239 }
239 signaled = PTQ_FIRST(&cond->ptc_waiters); 240 signaled = PTQ_FIRST(&cond->ptc_waiters);
240 if (__predict_false(signaled == NULL)) { 241 if (__predict_false(signaled == NULL)) {
241 cond->ptc_mutex = NULL; 242 cond->ptc_mutex = NULL;
242 pthread__spinunlock(self, &cond->ptc_lock); 243 pthread__spinunlock(self, &cond->ptc_lock);
243 return 0; 244 return 0;
244 } 245 }
245 mutex = cond->ptc_mutex; 246 mutex = cond->ptc_mutex;
246 if (PTQ_NEXT(signaled, pt_sleep) == NULL) { 247 if (PTQ_NEXT(signaled, pt_sleep) == NULL) {
247 cond->ptc_mutex = NULL; 248 cond->ptc_mutex = NULL;
248 PTQ_INIT(&cond->ptc_waiters); 249 PTQ_INIT(&cond->ptc_waiters);
249 } else { 250 } else {
250 PTQ_REMOVE(&cond->ptc_waiters, signaled, pt_sleep); 251 PTQ_REMOVE(&cond->ptc_waiters, signaled, pt_sleep);
251 } 252 }
252 signaled->pt_sleepobj = NULL; 253 signaled->pt_sleepobj = NULL;
253 lid = signaled->pt_lid; 254 lid = signaled->pt_lid;
254 pthread__spinunlock(self, &cond->ptc_lock); 255 pthread__spinunlock(self, &cond->ptc_lock);
255 256
256 /* 257 /*
257 * For all valid uses of pthread_cond_signal(), the caller will 258 * For all valid uses of pthread_cond_signal(), the caller will
258 * hold the mutex that the target is using to synchronize with. 259 * hold the mutex that the target is using to synchronize with.
259 * To avoid the target awakening and immediately blocking on the 260 * To avoid the target awakening and immediately blocking on the
260 * mutex, transfer the thread to be awoken to the current thread's 261 * mutex, transfer the thread to be awoken to the current thread's
261 * deferred wakeup list. The waiter will be set running when the 262 * deferred wakeup list. The waiter will be set running when the
262 * caller (this thread) releases the mutex. 263 * caller (this thread) releases the mutex.
263 */ 264 */
264 if (__predict_false(self->pt_nwaiters == (size_t)pthread__unpark_max)) { 265 if (__predict_false(self->pt_nwaiters == (size_t)pthread__unpark_max)) {
265 (void)_lwp_unpark_all(self->pt_waiters, self->pt_nwaiters, 266 (void)_lwp_unpark_all(self->pt_waiters, self->pt_nwaiters,
266 __UNVOLATILE(&mutex->ptm_waiters)); 267 __UNVOLATILE(&mutex->ptm_waiters));
267 self->pt_nwaiters = 0; 268 self->pt_nwaiters = 0;
268 } 269 }
269 self->pt_waiters[self->pt_nwaiters++] = lid; 270 self->pt_waiters[self->pt_nwaiters++] = lid;
270 pthread__mutex_deferwake(self, mutex); 271 pthread__mutex_deferwake(self, mutex);
271 return 0; 272 return 0;
272} 273}
273 274
274int 275int
275pthread_cond_signal(pthread_cond_t *cond) 276pthread_cond_signal(pthread_cond_t *cond)
276{ 277{
277 278
278 if (__predict_false(__uselibcstub)) 279 if (__predict_false(__uselibcstub))
279 return __libc_cond_signal_stub(cond); 280 return __libc_cond_signal_stub(cond);
280 281
 282 pthread__error(EINVAL, "Invalid condition variable",
 283 cond->ptc_magic == _PT_COND_MAGIC);
 284
281 if (__predict_true(PTQ_EMPTY(&cond->ptc_waiters))) 285 if (__predict_true(PTQ_EMPTY(&cond->ptc_waiters)))
282 return 0; 286 return 0;
283 return pthread__cond_wake_one(cond); 287 return pthread__cond_wake_one(cond);
284} 288}
285 289
286static int __noinline 290static int __noinline
287pthread__cond_wake_all(pthread_cond_t *cond) 291pthread__cond_wake_all(pthread_cond_t *cond)
288{ 292{
289 pthread_t self, signaled; 293 pthread_t self, signaled;
290 pthread_mutex_t *mutex; 294 pthread_mutex_t *mutex;
291 u_int max; 295 u_int max;
292 size_t nwaiters; 296 size_t nwaiters;
293 297
294 pthread__error(EINVAL, "Invalid condition variable", 
295 cond->ptc_magic == _PT_COND_MAGIC); 
296 
297 /* 298 /*
298 * Try to defer waking threads (see pthread_cond_signal()). 299 * Try to defer waking threads (see pthread_cond_signal()).
299 * Only transfer waiters for which there is no pending wakeup. 300 * Only transfer waiters for which there is no pending wakeup.
300 */ 301 */
301 self = pthread__self(); 302 self = pthread__self();
302 pthread__spinlock(self, &cond->ptc_lock); 303 pthread__spinlock(self, &cond->ptc_lock);
303 max = pthread__unpark_max; 304 max = pthread__unpark_max;
304 mutex = cond->ptc_mutex; 305 mutex = cond->ptc_mutex;
305 nwaiters = self->pt_nwaiters; 306 nwaiters = self->pt_nwaiters;
306 PTQ_FOREACH(signaled, &cond->ptc_waiters, pt_sleep) { 307 PTQ_FOREACH(signaled, &cond->ptc_waiters, pt_sleep) {
307 if (__predict_false(nwaiters == max)) { 308 if (__predict_false(nwaiters == max)) {
308 /* Overflow. */ 309 /* Overflow. */
309 (void)_lwp_unpark_all(self->pt_waiters, 310 (void)_lwp_unpark_all(self->pt_waiters,
310 nwaiters, __UNVOLATILE(&mutex->ptm_waiters)); 311 nwaiters, __UNVOLATILE(&mutex->ptm_waiters));
311 nwaiters = 0; 312 nwaiters = 0;
312 } 313 }
313 signaled->pt_sleepobj = NULL; 314 signaled->pt_sleepobj = NULL;
314 self->pt_waiters[nwaiters++] = signaled->pt_lid; 315 self->pt_waiters[nwaiters++] = signaled->pt_lid;
315 } 316 }
316 PTQ_INIT(&cond->ptc_waiters); 317 PTQ_INIT(&cond->ptc_waiters);
317 self->pt_nwaiters = nwaiters; 318 self->pt_nwaiters = nwaiters;
318 cond->ptc_mutex = NULL; 319 cond->ptc_mutex = NULL;
319 pthread__spinunlock(self, &cond->ptc_lock); 320 pthread__spinunlock(self, &cond->ptc_lock);
320 pthread__mutex_deferwake(self, mutex); 321 pthread__mutex_deferwake(self, mutex);
321 322
322 return 0; 323 return 0;
323} 324}
324 325
325int 326int
326pthread_cond_broadcast(pthread_cond_t *cond) 327pthread_cond_broadcast(pthread_cond_t *cond)
327{ 328{
328 if (__predict_false(__uselibcstub)) 329 if (__predict_false(__uselibcstub))
329 return __libc_cond_broadcast_stub(cond); 330 return __libc_cond_broadcast_stub(cond);
330 331
 332 pthread__error(EINVAL, "Invalid condition variable",
 333 cond->ptc_magic == _PT_COND_MAGIC);
 334
331 if (__predict_true(PTQ_EMPTY(&cond->ptc_waiters))) 335 if (__predict_true(PTQ_EMPTY(&cond->ptc_waiters)))
332 return 0; 336 return 0;
333 return pthread__cond_wake_all(cond); 337 return pthread__cond_wake_all(cond);
334} 338}
335 339
336int 340int
337_pthread_cond_has_waiters_np(pthread_cond_t *cond) 341_pthread_cond_has_waiters_np(pthread_cond_t *cond)
338{ 342{
339 343
340 return !PTQ_EMPTY(&cond->ptc_waiters); 344 return !PTQ_EMPTY(&cond->ptc_waiters);
341} 345}
342 346
343int 347int
344pthread_condattr_init(pthread_condattr_t *attr) 348pthread_condattr_init(pthread_condattr_t *attr)
345{ 349{
346 350
347 attr->ptca_magic = _PT_CONDATTR_MAGIC; 351 attr->ptca_magic = _PT_CONDATTR_MAGIC;
348 attr->ptca_private = NULL; 352 attr->ptca_private = NULL;
349 353
350 return 0; 354 return 0;
351} 355}
352 356
353int 357int
354pthread_condattr_setclock(pthread_condattr_t *attr, clockid_t clck) 358pthread_condattr_setclock(pthread_condattr_t *attr, clockid_t clck)
355{ 359{
 360
 361 pthread__error(EINVAL, "Invalid condition variable attribute",
 362 attr->ptca_magic == _PT_CONDATTR_MAGIC);
 363
356 switch (clck) { 364 switch (clck) {
357 case CLOCK_MONOTONIC: 365 case CLOCK_MONOTONIC:
358 case CLOCK_REALTIME: 366 case CLOCK_REALTIME:
359 if (attr->ptca_private == NULL) 367 if (attr->ptca_private == NULL)
360 attr->ptca_private = malloc(sizeof(clockid_t)); 368 attr->ptca_private = malloc(sizeof(clockid_t));
361 if (attr->ptca_private == NULL) 369 if (attr->ptca_private == NULL)
362 return errno; 370 return errno;
363 *(clockid_t *)attr->ptca_private = clck; 371 *(clockid_t *)attr->ptca_private = clck;
364 return 0; 372 return 0;
365 default: 373 default:
366 return EINVAL; 374 return EINVAL;
367 } 375 }
368} 376}
369 377
370int 378int
371pthread_condattr_getclock(const pthread_condattr_t *__restrict attr, 379pthread_condattr_getclock(const pthread_condattr_t *__restrict attr,
372 clockid_t *__restrict clock_id) 380 clockid_t *__restrict clock_id)
373{ 381{
 382
 383 pthread__error(EINVAL, "Invalid condition variable attribute",
 384 attr->ptca_magic == _PT_CONDATTR_MAGIC);
 385
374 if (attr == NULL || attr->ptca_private == NULL) 386 if (attr == NULL || attr->ptca_private == NULL)
375 return EINVAL; 387 return EINVAL;
376 *clock_id = *(clockid_t *)attr->ptca_private; 388 *clock_id = *(clockid_t *)attr->ptca_private;
377 return 0; 389 return 0;
378} 390}
379 391
380int 392int
381pthread_condattr_destroy(pthread_condattr_t *attr) 393pthread_condattr_destroy(pthread_condattr_t *attr)
382{ 394{
383 395
384 pthread__error(EINVAL, "Invalid condition variable attribute", 396 pthread__error(EINVAL, "Invalid condition variable attribute",
385 attr->ptca_magic == _PT_CONDATTR_MAGIC); 397 attr->ptca_magic == _PT_CONDATTR_MAGIC);
386 398
387 attr->ptca_magic = _PT_CONDATTR_DEAD; 399 attr->ptca_magic = _PT_CONDATTR_DEAD;
388 free(attr->ptca_private); 400 free(attr->ptca_private);
389 401
390 return 0; 402 return 0;
391} 403}
392 404
393#ifdef _PTHREAD_PSHARED 405#ifdef _PTHREAD_PSHARED
394int 406int
395pthread_condattr_getpshared(const pthread_condattr_t * __restrict attr, 407pthread_condattr_getpshared(const pthread_condattr_t * __restrict attr,
396 int * __restrict pshared) 408 int * __restrict pshared)
397{ 409{
398 410
 411 pthread__error(EINVAL, "Invalid condition variable attribute",
 412 attr->ptca_magic == _PT_CONDATTR_MAGIC);
 413
399 *pshared = PTHREAD_PROCESS_PRIVATE; 414 *pshared = PTHREAD_PROCESS_PRIVATE;
400 return 0; 415 return 0;
401} 416}
402 417
403int 418int
404pthread_condattr_setpshared(pthread_condattr_t *attr, int pshared) 419pthread_condattr_setpshared(pthread_condattr_t *attr, int pshared)
405{ 420{
406 421
 422 pthread__error(EINVAL, "Invalid condition variable attribute",
 423 attr->ptca_magic == _PT_CONDATTR_MAGIC);
 424
407 switch(pshared) { 425 switch(pshared) {
408 case PTHREAD_PROCESS_PRIVATE: 426 case PTHREAD_PROCESS_PRIVATE:
409 return 0; 427 return 0;
410 case PTHREAD_PROCESS_SHARED: 428 case PTHREAD_PROCESS_SHARED:
411 return ENOSYS; 429 return ENOSYS;
412 } 430 }
413 return EINVAL; 431 return EINVAL;
414} 432}
415#endif 433#endif
416 434
417/* Utility routine to hang out for a while if threads haven't started yet. */ 435/* Utility routine to hang out for a while if threads haven't started yet. */
418static int 436static int
419pthread_cond_wait_nothread(pthread_t self, pthread_mutex_t *mutex, 437pthread_cond_wait_nothread(pthread_t self, pthread_mutex_t *mutex,
420 pthread_cond_t *cond, const struct timespec *abstime) 438 pthread_cond_t *cond, const struct timespec *abstime)
421{ 439{
422 struct timespec now, diff; 440 struct timespec now, diff;
423 int retval; 441 int retval;
424 442
425 if (abstime == NULL) { 443 if (abstime == NULL) {
426 diff.tv_sec = 99999999; 444 diff.tv_sec = 99999999;
427 diff.tv_nsec = 0; 445 diff.tv_nsec = 0;
428 } else { 446 } else {
429 clockid_t clck = pthread_cond_getclock(cond); 447 clockid_t clck = pthread_cond_getclock(cond);
430 clock_gettime(clck, &now); 448 clock_gettime(clck, &now);
431 if (timespeccmp(abstime, &now, <)) 449 if (timespeccmp(abstime, &now, <))
432 timespecclear(&diff); 450 timespecclear(&diff);
433 else 451 else
434 timespecsub(abstime, &now, &diff); 452 timespecsub(abstime, &now, &diff);
435 } 453 }
436 454
437 do { 455 do {
438 pthread__testcancel(self); 456 pthread__testcancel(self);
439 pthread_mutex_unlock(mutex); 457 pthread_mutex_unlock(mutex);
440 retval = _sys___nanosleep50(&diff, NULL); 458 retval = _sys___nanosleep50(&diff, NULL);
441 pthread_mutex_lock(mutex); 459 pthread_mutex_lock(mutex);
442 } while (abstime == NULL && retval == 0); 460 } while (abstime == NULL && retval == 0);
443 pthread__testcancel(self); 461 pthread__testcancel(self);
444 462
445 if (retval == 0) 463 if (retval == 0)
446 return ETIMEDOUT; 464 return ETIMEDOUT;
447 else 465 else
448 /* spurious wakeup */ 466 /* spurious wakeup */
449 return 0; 467 return 0;
450} 468}