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 (expand / 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,14 +1,14 @@ @@ -1,14 +1,14 @@
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.
@@ -36,27 +36,27 @@ @@ -36,27 +36,27 @@
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;
@@ -68,26 +68,30 @@ int _pthread_cond_has_waiters_np(pthread @@ -68,26 +68,30 @@ int _pthread_cond_has_waiters_np(pthread
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
@@ -212,29 +216,26 @@ pthread_cond_wait(pthread_cond_t *cond,  @@ -212,29 +216,26 @@ pthread_cond_wait(pthread_cond_t *cond,
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)) {
@@ -268,42 +269,42 @@ pthread__cond_wake_one(pthread_cond_t *c @@ -268,42 +269,42 @@ pthread__cond_wake_one(pthread_cond_t *c
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,
@@ -318,102 +319,119 @@ pthread__cond_wake_all(pthread_cond_t *c @@ -318,102 +319,119 @@ pthread__cond_wake_all(pthread_cond_t *c
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,