1 /* 2 * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by John Birrell. 16 * 4. Neither the name of the author nor the names of any co-contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * $FreeBSD$ 33 */ 34 #include <stdlib.h> 35 #include <errno.h> 36 #include <string.h> 37 #include <pthread.h> 38 #include "thr_private.h" 39 40 /* 41 * Proctect two different threads calling a pthread_cond_* function 42 * from accidentally initializing the condition variable twice. 43 */ 44 static spinlock_t static_cond_lock = _SPINLOCK_INITIALIZER; 45 46 /* 47 * Prototypes 48 */ 49 static inline int cond_init(pthread_cond_t *); 50 static pthread_t cond_queue_deq(pthread_cond_t); 51 static void cond_queue_remove(pthread_cond_t, pthread_t); 52 static void cond_queue_enq(pthread_cond_t, pthread_t); 53 static int cond_signal(pthread_cond_t *, int); 54 static int cond_wait_common(pthread_cond_t *, 55 pthread_mutex_t *, const struct timespec *); 56 57 __weak_reference(_pthread_cond_init, pthread_cond_init); 58 __weak_reference(_pthread_cond_destroy, pthread_cond_destroy); 59 __weak_reference(_pthread_cond_wait, pthread_cond_wait); 60 __weak_reference(_pthread_cond_timedwait, pthread_cond_timedwait); 61 __weak_reference(_pthread_cond_signal, pthread_cond_signal); 62 __weak_reference(_pthread_cond_broadcast, pthread_cond_broadcast); 63 64 #define COND_LOCK(c) \ 65 do { \ 66 if (umtx_lock(&(c)->c_lock, curthread->thr_id)) \ 67 abort(); \ 68 } while (0) 69 70 #define COND_UNLOCK(c) \ 71 do { \ 72 if (umtx_unlock(&(c)->c_lock, curthread->thr_id)) \ 73 abort(); \ 74 } while (0) 75 76 77 /* Reinitialize a condition variable to defaults. */ 78 int 79 _cond_reinit(pthread_cond_t *cond) 80 { 81 if (cond == NULL) 82 return (EINVAL); 83 84 if (*cond == NULL) 85 return (pthread_cond_init(cond, NULL)); 86 87 /* 88 * Initialize the condition variable structure: 89 */ 90 TAILQ_INIT(&(*cond)->c_queue); 91 (*cond)->c_flags = COND_FLAGS_INITED; 92 (*cond)->c_type = COND_TYPE_FAST; 93 (*cond)->c_mutex = NULL; 94 (*cond)->c_seqno = 0; 95 bzero(&(*cond)->c_lock, sizeof((*cond)->c_lock)); 96 97 return (0); 98 } 99 100 int 101 _pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr) 102 { 103 enum pthread_cond_type type; 104 pthread_cond_t pcond; 105 106 if (cond == NULL) 107 return (EINVAL); 108 109 /* 110 * Check if a pointer to a condition variable attribute 111 * structure was passed by the caller: 112 */ 113 if (cond_attr != NULL && *cond_attr != NULL) 114 type = (*cond_attr)->c_type; 115 else 116 /* Default to a fast condition variable: */ 117 type = COND_TYPE_FAST; 118 119 /* Process according to condition variable type: */ 120 switch (type) { 121 case COND_TYPE_FAST: 122 break; 123 default: 124 return (EINVAL); 125 break; 126 } 127 128 if ((pcond = (pthread_cond_t) 129 malloc(sizeof(struct pthread_cond))) == NULL) 130 return (ENOMEM); 131 /* 132 * Initialise the condition variable 133 * structure: 134 */ 135 TAILQ_INIT(&pcond->c_queue); 136 pcond->c_flags |= COND_FLAGS_INITED; 137 pcond->c_type = type; 138 pcond->c_mutex = NULL; 139 pcond->c_seqno = 0; 140 bzero(&pcond->c_lock, sizeof(pcond->c_lock)); 141 142 *cond = pcond; 143 144 return (0); 145 } 146 147 int 148 _pthread_cond_destroy(pthread_cond_t *cond) 149 { 150 /* 151 * Short circuit for a statically initialized condvar 152 * that is being destroyed without having been used. 153 */ 154 if (*cond == PTHREAD_COND_INITIALIZER) 155 return (0); 156 157 COND_LOCK(*cond); 158 159 /* 160 * Free the memory allocated for the condition 161 * variable structure: 162 */ 163 free(*cond); 164 165 /* 166 * NULL the caller's pointer now that the condition 167 * variable has been destroyed: 168 */ 169 *cond = NULL; 170 171 return (0); 172 } 173 174 int 175 _pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) 176 { 177 int rval; 178 179 rval = cond_wait_common(cond, mutex, NULL); 180 181 /* This should never happen. */ 182 if (rval == ETIMEDOUT) 183 abort(); 184 185 return (rval); 186 } 187 188 int 189 _pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex, 190 const struct timespec * abstime) 191 { 192 if (abstime == NULL || abstime->tv_nsec >= 1000000000) 193 return (EINVAL); 194 195 return (cond_wait_common(cond, mutex, abstime)); 196 } 197 198 static int 199 cond_wait_common(pthread_cond_t * cond, pthread_mutex_t * mutex, 200 const struct timespec * abstime) 201 { 202 int rval = 0; 203 int done = 0; 204 int seqno; 205 int mtxrval; 206 207 208 _thread_enter_cancellation_point(); 209 210 if (cond == NULL) 211 return (EINVAL); 212 /* 213 * If the condition variable is statically initialized, perform dynamic 214 * initialization. 215 */ 216 if (*cond == PTHREAD_COND_INITIALIZER && (rval = cond_init(cond)) != 0) 217 return (rval); 218 219 220 COND_LOCK(*cond); 221 222 /* 223 * If the condvar was statically allocated, properly 224 * initialize the tail queue. 225 */ 226 if (((*cond)->c_flags & COND_FLAGS_INITED) == 0) { 227 TAILQ_INIT(&(*cond)->c_queue); 228 (*cond)->c_flags |= COND_FLAGS_INITED; 229 } 230 231 /* Process according to condition variable type. */ 232 233 switch ((*cond)->c_type) { 234 /* Fast condition variable: */ 235 case COND_TYPE_FAST: 236 if ((mutex == NULL) || (((*cond)->c_mutex != NULL) && 237 ((*cond)->c_mutex != *mutex))) { 238 COND_UNLOCK(*cond); 239 rval = EINVAL; 240 break; 241 } 242 /* Remember the mutex */ 243 (*cond)->c_mutex = *mutex; 244 245 if ((rval = _mutex_cv_unlock(mutex)) != 0) { 246 if (rval == -1){ 247 printf("foo"); 248 fflush(stdout); 249 abort(); 250 } 251 252 COND_UNLOCK(*cond); 253 break; 254 } 255 256 /* 257 * We need to protect the queue operations. It also 258 * protects c_seqno and the pthread flag fields. This is 259 * dropped before calling _thread_suspend() and reaquired 260 * when we return. 261 */ 262 263 _thread_critical_enter(curthread); 264 /* 265 * c_seqno is protected. 266 */ 267 seqno = (*cond)->c_seqno; 268 269 do { 270 /* 271 * Queue the running thread on the condition 272 * variable. 273 */ 274 cond_queue_enq(*cond, curthread); 275 276 if (curthread->cancelflags & PTHREAD_CANCELLING) { 277 /* 278 * POSIX Says that we must relock the mutex 279 * even if we're being canceled. 280 */ 281 _thread_critical_exit(curthread); 282 COND_UNLOCK(*cond); 283 _mutex_cv_lock(mutex); 284 pthread_testcancel(); 285 PANIC("Shouldn't have come back."); 286 } 287 288 PTHREAD_SET_STATE(curthread, PS_COND_WAIT); 289 _thread_critical_exit(curthread); 290 COND_UNLOCK(*cond); 291 rval = _thread_suspend(curthread, (struct timespec *)abstime); 292 if (rval != 0 && rval != ETIMEDOUT && rval != EINTR) { 293 printf("foo"); 294 fflush(stdout); 295 abort(); 296 } 297 COND_LOCK(*cond); 298 _thread_critical_enter(curthread); 299 300 done = (seqno != (*cond)->c_seqno); 301 302 /* 303 * If we timed out, this will remove us from the 304 * queue. Otherwise, if we were signaled it does 305 * nothing because this thread won't be on the queue. 306 */ 307 cond_queue_remove(*cond, curthread); 308 309 } while ((done == 0) && (rval == 0)); 310 /* 311 * If we timed out someone still may have signaled us 312 * before we got a chance to run again. We check for 313 * this by looking to see if our state is RUNNING. 314 */ 315 if (rval == ETIMEDOUT) { 316 if (curthread->state != PS_RUNNING) { 317 PTHREAD_SET_STATE(curthread, PS_RUNNING); 318 } else 319 rval = 0; 320 } 321 _thread_critical_exit(curthread); 322 COND_UNLOCK(*cond); 323 324 mtxrval = _mutex_cv_lock(mutex); 325 326 /* 327 * If the mutex failed return that error, otherwise we're 328 * returning ETIMEDOUT. 329 */ 330 if (mtxrval == -1) { 331 printf("foo"); 332 fflush(stdout); 333 abort(); 334 } 335 if (mtxrval != 0) 336 rval = mtxrval; 337 338 break; 339 340 /* Trap invalid condition variable types: */ 341 default: 342 COND_UNLOCK(*cond); 343 rval = EINVAL; 344 break; 345 } 346 347 _thread_leave_cancellation_point(); 348 349 return (rval); 350 } 351 352 int 353 _pthread_cond_signal(pthread_cond_t * cond) 354 { 355 return (cond_signal(cond, 0)); 356 } 357 358 int 359 _pthread_cond_broadcast(pthread_cond_t * cond) 360 { 361 return (cond_signal(cond, 1)); 362 } 363 364 static int 365 cond_signal(pthread_cond_t * cond, int broadcast) 366 { 367 int rval = 0; 368 pthread_t pthread; 369 370 if (cond == NULL) 371 return (EINVAL); 372 /* 373 * If the condition variable is statically initialized, perform dynamic 374 * initialization. 375 */ 376 if (*cond == PTHREAD_COND_INITIALIZER && (rval = cond_init(cond)) != 0) 377 return (rval); 378 379 COND_LOCK(*cond); 380 381 /* Process according to condition variable type: */ 382 switch ((*cond)->c_type) { 383 /* Fast condition variable: */ 384 case COND_TYPE_FAST: 385 (*cond)->c_seqno++; 386 387 /* 388 * Enter a loop to bring all (or only one) threads off the 389 * condition queue: 390 */ 391 do { 392 /* 393 * Wake up the signaled thread. It will be returned 394 * to us locked, and with signals disabled. 395 */ 396 if ((pthread = cond_queue_deq(*cond)) != NULL) { 397 PTHREAD_NEW_STATE(pthread, PS_RUNNING); 398 _thread_critical_exit(pthread); 399 } 400 } while (broadcast && pthread != NULL); 401 402 break; 403 404 /* Trap invalid condition variable types: */ 405 default: 406 rval = EINVAL; 407 break; 408 } 409 410 COND_UNLOCK(*cond); 411 412 413 return (rval); 414 } 415 416 void 417 _cond_wait_backout(pthread_t pthread) 418 { 419 pthread_cond_t cond; 420 421 cond = pthread->data.cond; 422 if (cond == NULL) 423 return; 424 425 /* Process according to condition variable type: */ 426 switch (cond->c_type) { 427 /* Fast condition variable: */ 428 case COND_TYPE_FAST: 429 cond_queue_remove(cond, pthread); 430 break; 431 default: 432 break; 433 } 434 } 435 436 /* 437 * Dequeue a waiting thread from the head of a condition queue in 438 * descending priority order. 439 */ 440 static pthread_t 441 cond_queue_deq(pthread_cond_t cond) 442 { 443 pthread_t pthread; 444 445 while ((pthread = TAILQ_FIRST(&cond->c_queue)) != NULL) { 446 _thread_critical_enter(pthread); 447 TAILQ_REMOVE(&cond->c_queue, pthread, sqe); 448 cond_queue_remove(cond, pthread); 449 if ((pthread->cancelflags & PTHREAD_CANCELLING) == 0 && 450 pthread->state == PS_COND_WAIT) 451 /* 452 * Only exit the loop when we find a thread 453 * that hasn't timed out or been canceled; 454 * those threads are already running and don't 455 * need their run state changed. 456 */ 457 break; 458 else 459 _thread_critical_exit(pthread); 460 } 461 462 return(pthread); 463 } 464 465 /* 466 * Remove a waiting thread from a condition queue in descending priority 467 * order. 468 */ 469 static void 470 cond_queue_remove(pthread_cond_t cond, pthread_t pthread) 471 { 472 /* 473 * Because pthread_cond_timedwait() can timeout as well 474 * as be signaled by another thread, it is necessary to 475 * guard against removing the thread from the queue if 476 * it isn't in the queue. 477 */ 478 if (pthread->flags & PTHREAD_FLAGS_IN_CONDQ) { 479 TAILQ_REMOVE(&cond->c_queue, pthread, sqe); 480 pthread->flags &= ~PTHREAD_FLAGS_IN_CONDQ; 481 } 482 /* Check for no more waiters. */ 483 if (TAILQ_FIRST(&cond->c_queue) == NULL) 484 cond->c_mutex = NULL; 485 } 486 487 /* 488 * Enqueue a waiting thread to a condition queue in descending priority 489 * order. 490 */ 491 static void 492 cond_queue_enq(pthread_cond_t cond, pthread_t pthread) 493 { 494 pthread_t tid = TAILQ_LAST(&cond->c_queue, cond_head); 495 char *name; 496 497 name = pthread->name ? pthread->name : "unknown"; 498 if ((pthread->flags & PTHREAD_FLAGS_IN_CONDQ) != 0) 499 _thread_printf(2, "Thread (%s:%u) already on condq\n", 500 pthread->name, pthread->uniqueid); 501 if ((pthread->flags & PTHREAD_FLAGS_IN_MUTEXQ) != 0) 502 _thread_printf(2, "Thread (%s:%u) already on mutexq\n", 503 pthread->name, pthread->uniqueid); 504 PTHREAD_ASSERT_NOT_IN_SYNCQ(pthread); 505 506 /* 507 * For the common case of all threads having equal priority, 508 * we perform a quick check against the priority of the thread 509 * at the tail of the queue. 510 */ 511 if ((tid == NULL) || (pthread->active_priority <= tid->active_priority)) 512 TAILQ_INSERT_TAIL(&cond->c_queue, pthread, sqe); 513 else { 514 tid = TAILQ_FIRST(&cond->c_queue); 515 while (pthread->active_priority <= tid->active_priority) 516 tid = TAILQ_NEXT(tid, sqe); 517 TAILQ_INSERT_BEFORE(tid, pthread, sqe); 518 } 519 pthread->flags |= PTHREAD_FLAGS_IN_CONDQ; 520 pthread->data.cond = cond; 521 } 522 523 static inline int 524 cond_init(pthread_cond_t *cond) 525 { 526 int error = 0; 527 _SPINLOCK(&static_cond_lock); 528 if (*cond == PTHREAD_COND_INITIALIZER) 529 error = _pthread_cond_init(cond, NULL); 530 _SPINUNLOCK(&static_cond_lock); 531 return (error); 532 } 533 534