1 /* 2 * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. 3 * Copyright (c) 2006 David Xu <yfxu@corp.netease.com>. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by John Birrell. 17 * 4. Neither the name of the author nor the names of any co-contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * $DragonFly: src/lib/libthread_xu/thread/thr_mutex.c,v 1.15 2008/05/09 16:03:27 dillon Exp $ 34 */ 35 36 #include "namespace.h" 37 #include <machine/tls.h> 38 39 #include <errno.h> 40 #include <stdlib.h> 41 #include <string.h> 42 #include <sys/queue.h> 43 #include <pthread.h> 44 #include "un-namespace.h" 45 46 #include "thr_private.h" 47 48 #if defined(_PTHREADS_INVARIANTS) 49 #define MUTEX_INIT_LINK(m) do { \ 50 (m)->m_qe.tqe_prev = NULL; \ 51 (m)->m_qe.tqe_next = NULL; \ 52 } while (0) 53 #define MUTEX_ASSERT_IS_OWNED(m) do { \ 54 if ((m)->m_qe.tqe_prev == NULL) \ 55 PANIC("mutex is not on list"); \ 56 } while (0) 57 #define MUTEX_ASSERT_NOT_OWNED(m) do { \ 58 if (((m)->m_qe.tqe_prev != NULL) || \ 59 ((m)->m_qe.tqe_next != NULL)) \ 60 PANIC("mutex is on list"); \ 61 } while (0) 62 #define THR_ASSERT_NOT_IN_SYNCQ(thr) do { \ 63 THR_ASSERT(((thr)->sflags & THR_FLAGS_IN_SYNCQ) == 0, \ 64 "thread in syncq when it shouldn't be."); \ 65 } while (0); 66 #else 67 #define MUTEX_INIT_LINK(m) 68 #define MUTEX_ASSERT_IS_OWNED(m) 69 #define MUTEX_ASSERT_NOT_OWNED(m) 70 #define THR_ASSERT_NOT_IN_SYNCQ(thr) 71 #endif 72 73 #define THR_IN_MUTEXQ(thr) (((thr)->sflags & THR_FLAGS_IN_SYNCQ) != 0) 74 #define MUTEX_DESTROY(m) do { \ 75 free(m); \ 76 } while (0) 77 78 umtx_t _mutex_static_lock; 79 80 /* 81 * Prototypes 82 */ 83 static int mutex_self_trylock(pthread_mutex_t); 84 static int mutex_self_lock(pthread_mutex_t, 85 const struct timespec *abstime); 86 static int mutex_unlock_common(pthread_mutex_t *); 87 88 int __pthread_mutex_init(pthread_mutex_t *mutex, 89 const pthread_mutexattr_t *mutex_attr); 90 int __pthread_mutex_trylock(pthread_mutex_t *mutex); 91 int __pthread_mutex_lock(pthread_mutex_t *mutex); 92 int __pthread_mutex_timedlock(pthread_mutex_t *mutex, 93 const struct timespec *abs_timeout); 94 95 static int 96 mutex_init(pthread_mutex_t *mutex, 97 const pthread_mutexattr_t *mutex_attr, int private) 98 { 99 const struct pthread_mutex_attr *attr; 100 struct pthread_mutex *pmutex; 101 102 if (mutex_attr == NULL) { 103 attr = &_pthread_mutexattr_default; 104 } else { 105 attr = *mutex_attr; 106 if (attr->m_type < PTHREAD_MUTEX_ERRORCHECK || 107 attr->m_type >= MUTEX_TYPE_MAX) 108 return (EINVAL); 109 if (attr->m_protocol < PTHREAD_PRIO_NONE || 110 attr->m_protocol > PTHREAD_PRIO_PROTECT) 111 return (EINVAL); 112 } 113 114 if ((pmutex = (pthread_mutex_t) 115 malloc(sizeof(struct pthread_mutex))) == NULL) 116 return (ENOMEM); 117 118 _thr_umtx_init(&pmutex->m_lock); 119 pmutex->m_type = attr->m_type; 120 pmutex->m_protocol = attr->m_protocol; 121 TAILQ_INIT(&pmutex->m_queue); 122 pmutex->m_owner = NULL; 123 pmutex->m_flags = attr->m_flags | MUTEX_FLAGS_INITED; 124 if (private) 125 pmutex->m_flags |= MUTEX_FLAGS_PRIVATE; 126 pmutex->m_count = 0; 127 pmutex->m_refcount = 0; 128 if (attr->m_protocol == PTHREAD_PRIO_PROTECT) 129 pmutex->m_prio = attr->m_ceiling; 130 else 131 pmutex->m_prio = -1; 132 pmutex->m_saved_prio = 0; 133 MUTEX_INIT_LINK(pmutex); 134 *mutex = pmutex; 135 return (0); 136 } 137 138 static int 139 init_static(struct pthread *thread, pthread_mutex_t *mutex) 140 { 141 int ret; 142 143 THR_LOCK_ACQUIRE(thread, &_mutex_static_lock); 144 145 if (*mutex == NULL) 146 ret = mutex_init(mutex, NULL, 0); 147 else 148 ret = 0; 149 150 THR_LOCK_RELEASE(thread, &_mutex_static_lock); 151 152 return (ret); 153 } 154 155 static int 156 init_static_private(struct pthread *thread, pthread_mutex_t *mutex) 157 { 158 int ret; 159 160 THR_LOCK_ACQUIRE(thread, &_mutex_static_lock); 161 162 if (*mutex == NULL) 163 ret = mutex_init(mutex, NULL, 1); 164 else 165 ret = 0; 166 167 THR_LOCK_RELEASE(thread, &_mutex_static_lock); 168 169 return (ret); 170 } 171 172 int 173 _pthread_mutex_init(pthread_mutex_t *mutex, 174 const pthread_mutexattr_t *mutex_attr) 175 { 176 return mutex_init(mutex, mutex_attr, 1); 177 } 178 179 int 180 __pthread_mutex_init(pthread_mutex_t *mutex, 181 const pthread_mutexattr_t *mutex_attr) 182 { 183 return mutex_init(mutex, mutex_attr, 0); 184 } 185 186 int 187 _mutex_reinit(pthread_mutex_t *mutex) 188 { 189 _thr_umtx_init(&(*mutex)->m_lock); 190 TAILQ_INIT(&(*mutex)->m_queue); 191 MUTEX_INIT_LINK(*mutex); 192 (*mutex)->m_owner = NULL; 193 (*mutex)->m_count = 0; 194 (*mutex)->m_refcount = 0; 195 (*mutex)->m_prio = 0; 196 (*mutex)->m_saved_prio = 0; 197 return (0); 198 } 199 200 void 201 _mutex_fork(struct pthread *curthread) 202 { 203 struct pthread_mutex *m; 204 205 TAILQ_FOREACH(m, &curthread->mutexq, m_qe) 206 m->m_lock = UMTX_LOCKED; 207 } 208 209 int 210 _pthread_mutex_destroy(pthread_mutex_t *mutex) 211 { 212 struct pthread *curthread = tls_get_curthread(); 213 pthread_mutex_t m; 214 int ret = 0; 215 216 if (mutex == NULL) 217 ret = EINVAL; 218 else if (*mutex == NULL) 219 ret = 0; 220 else { 221 /* 222 * Try to lock the mutex structure, we only need to 223 * try once, if failed, the mutex is in used. 224 */ 225 ret = THR_UMTX_TRYLOCK(curthread, &(*mutex)->m_lock); 226 if (ret) 227 return (ret); 228 229 /* 230 * Check mutex other fields to see if this mutex is 231 * in use. Mostly for prority mutex types, or there 232 * are condition variables referencing it. 233 */ 234 if (((*mutex)->m_owner != NULL) || 235 (TAILQ_FIRST(&(*mutex)->m_queue) != NULL) || 236 ((*mutex)->m_refcount != 0)) { 237 THR_UMTX_UNLOCK(curthread, &(*mutex)->m_lock); 238 ret = EBUSY; 239 } else { 240 /* 241 * Save a pointer to the mutex so it can be free'd 242 * and set the caller's pointer to NULL: 243 */ 244 m = *mutex; 245 *mutex = NULL; 246 247 /* Unlock the mutex structure: */ 248 THR_UMTX_UNLOCK(curthread, &m->m_lock); 249 250 /* 251 * Free the memory allocated for the mutex 252 * structure: 253 */ 254 MUTEX_ASSERT_NOT_OWNED(m); 255 MUTEX_DESTROY(m); 256 } 257 } 258 259 /* Return the completion status: */ 260 return (ret); 261 } 262 263 static int 264 mutex_trylock_common(struct pthread *curthread, pthread_mutex_t *mutex) 265 { 266 struct pthread_mutex *m; 267 int ret; 268 269 m = *mutex; 270 ret = THR_UMTX_TRYLOCK(curthread, &m->m_lock); 271 if (ret == 0) { 272 m->m_owner = curthread; 273 /* Add to the list of owned mutexes: */ 274 MUTEX_ASSERT_NOT_OWNED(m); 275 TAILQ_INSERT_TAIL(&curthread->mutexq, 276 m, m_qe); 277 } else if (m->m_owner == curthread) { 278 ret = mutex_self_trylock(m); 279 } /* else {} */ 280 281 return (ret); 282 } 283 284 int 285 __pthread_mutex_trylock(pthread_mutex_t *m) 286 { 287 struct pthread *curthread = tls_get_curthread(); 288 int ret; 289 290 if (__predict_false(m == NULL)) 291 return(EINVAL); 292 /* 293 * If the mutex is statically initialized, perform the dynamic 294 * initialization: 295 */ 296 if (__predict_false(*m == NULL)) { 297 ret = init_static(curthread, m); 298 if (__predict_false(ret != 0)) 299 return (ret); 300 } 301 return (mutex_trylock_common(curthread, m)); 302 } 303 304 int 305 _pthread_mutex_trylock(pthread_mutex_t *m) 306 { 307 struct pthread *curthread = tls_get_curthread(); 308 int ret = 0; 309 310 /* 311 * If the mutex is statically initialized, perform the dynamic 312 * initialization marking the mutex private (delete safe): 313 */ 314 if (__predict_false(*m == NULL)) { 315 ret = init_static_private(curthread, m); 316 if (__predict_false(ret != 0)) 317 return (ret); 318 } 319 return (mutex_trylock_common(curthread, m)); 320 } 321 322 static int 323 mutex_lock_common(struct pthread *curthread, pthread_mutex_t *mutex, 324 const struct timespec * abstime) 325 { 326 struct timespec ts, ts2; 327 struct pthread_mutex *m; 328 int ret = 0; 329 330 m = *mutex; 331 ret = THR_UMTX_TRYLOCK(curthread, &m->m_lock); 332 if (ret == 0) { 333 m->m_owner = curthread; 334 /* Add to the list of owned mutexes: */ 335 MUTEX_ASSERT_NOT_OWNED(m); 336 TAILQ_INSERT_TAIL(&curthread->mutexq, 337 m, m_qe); 338 } else if (m->m_owner == curthread) { 339 ret = mutex_self_lock(m, abstime); 340 } else { 341 if (abstime == NULL) { 342 THR_UMTX_LOCK(curthread, &m->m_lock); 343 ret = 0; 344 } else if (__predict_false( 345 abstime->tv_sec < 0 || abstime->tv_nsec < 0 || 346 abstime->tv_nsec >= 1000000000)) { 347 ret = EINVAL; 348 } else { 349 clock_gettime(CLOCK_REALTIME, &ts); 350 TIMESPEC_SUB(&ts2, abstime, &ts); 351 ret = THR_UMTX_TIMEDLOCK(curthread, 352 &m->m_lock, &ts2); 353 /* 354 * Timed out wait is not restarted if 355 * it was interrupted, not worth to do it. 356 */ 357 if (ret == EINTR) 358 ret = ETIMEDOUT; 359 } 360 if (ret == 0) { 361 m->m_owner = curthread; 362 /* Add to the list of owned mutexes: */ 363 MUTEX_ASSERT_NOT_OWNED(m); 364 TAILQ_INSERT_TAIL(&curthread->mutexq, 365 m, m_qe); 366 } 367 } 368 return (ret); 369 } 370 371 int 372 __pthread_mutex_lock(pthread_mutex_t *m) 373 { 374 struct pthread *curthread; 375 int ret; 376 377 if (__predict_false(m == NULL)) 378 return(EINVAL); 379 380 /* 381 * If the mutex is statically initialized, perform the dynamic 382 * initialization: 383 */ 384 curthread = tls_get_curthread(); 385 if (__predict_false(*m == NULL)) { 386 ret = init_static(curthread, m); 387 if (__predict_false(ret)) 388 return (ret); 389 } 390 return (mutex_lock_common(curthread, m, NULL)); 391 } 392 393 int 394 _pthread_mutex_lock(pthread_mutex_t *m) 395 { 396 struct pthread *curthread; 397 int ret; 398 399 if (__predict_false(m == NULL)) 400 return(EINVAL); 401 402 /* 403 * If the mutex is statically initialized, perform the dynamic 404 * initialization marking it private (delete safe): 405 */ 406 curthread = tls_get_curthread(); 407 if (__predict_false(*m == NULL)) { 408 ret = init_static_private(curthread, m); 409 if (__predict_false(ret)) 410 return (ret); 411 } 412 return (mutex_lock_common(curthread, m, NULL)); 413 } 414 415 int 416 __pthread_mutex_timedlock(pthread_mutex_t *m, 417 const struct timespec *abs_timeout) 418 { 419 struct pthread *curthread; 420 int ret; 421 422 if (__predict_false(m == NULL)) 423 return(EINVAL); 424 425 /* 426 * If the mutex is statically initialized, perform the dynamic 427 * initialization: 428 */ 429 curthread = tls_get_curthread(); 430 if (__predict_false(*m == NULL)) { 431 ret = init_static(curthread, m); 432 if (__predict_false(ret)) 433 return (ret); 434 } 435 return (mutex_lock_common(curthread, m, abs_timeout)); 436 } 437 438 int 439 _pthread_mutex_timedlock(pthread_mutex_t *m, 440 const struct timespec *abs_timeout) 441 { 442 struct pthread *curthread; 443 int ret; 444 445 if (__predict_false(m == NULL)) 446 return(EINVAL); 447 448 curthread = tls_get_curthread(); 449 450 /* 451 * If the mutex is statically initialized, perform the dynamic 452 * initialization marking it private (delete safe): 453 */ 454 if (__predict_false(*m == NULL)) { 455 ret = init_static_private(curthread, m); 456 if (__predict_false(ret)) 457 return (ret); 458 } 459 return (mutex_lock_common(curthread, m, abs_timeout)); 460 } 461 462 int 463 _pthread_mutex_unlock(pthread_mutex_t *m) 464 { 465 if (__predict_false(m == NULL)) 466 return(EINVAL); 467 return (mutex_unlock_common(m)); 468 } 469 470 static int 471 mutex_self_trylock(pthread_mutex_t m) 472 { 473 int ret; 474 475 switch (m->m_type) { 476 /* case PTHREAD_MUTEX_DEFAULT: */ 477 case PTHREAD_MUTEX_ERRORCHECK: 478 case PTHREAD_MUTEX_NORMAL: 479 ret = EBUSY; 480 break; 481 482 case PTHREAD_MUTEX_RECURSIVE: 483 /* Increment the lock count: */ 484 if (m->m_count + 1 > 0) { 485 m->m_count++; 486 ret = 0; 487 } else 488 ret = EAGAIN; 489 break; 490 491 default: 492 /* Trap invalid mutex types; */ 493 ret = EINVAL; 494 } 495 496 return (ret); 497 } 498 499 static int 500 mutex_self_lock(pthread_mutex_t m, const struct timespec *abstime) 501 { 502 struct timespec ts1, ts2; 503 int ret; 504 505 switch (m->m_type) { 506 /* case PTHREAD_MUTEX_DEFAULT: */ 507 case PTHREAD_MUTEX_ERRORCHECK: 508 if (abstime) { 509 clock_gettime(CLOCK_REALTIME, &ts1); 510 TIMESPEC_SUB(&ts2, abstime, &ts1); 511 __sys_nanosleep(&ts2, NULL); 512 ret = ETIMEDOUT; 513 } else { 514 /* 515 * POSIX specifies that mutexes should return 516 * EDEADLK if a recursive lock is detected. 517 */ 518 ret = EDEADLK; 519 } 520 break; 521 522 case PTHREAD_MUTEX_NORMAL: 523 /* 524 * What SS2 define as a 'normal' mutex. Intentionally 525 * deadlock on attempts to get a lock you already own. 526 */ 527 ret = 0; 528 if (abstime) { 529 clock_gettime(CLOCK_REALTIME, &ts1); 530 TIMESPEC_SUB(&ts2, abstime, &ts1); 531 __sys_nanosleep(&ts2, NULL); 532 ret = ETIMEDOUT; 533 } else { 534 ts1.tv_sec = 30; 535 ts1.tv_nsec = 0; 536 for (;;) 537 __sys_nanosleep(&ts1, NULL); 538 } 539 break; 540 541 case PTHREAD_MUTEX_RECURSIVE: 542 /* Increment the lock count: */ 543 if (m->m_count + 1 > 0) { 544 m->m_count++; 545 ret = 0; 546 } else 547 ret = EAGAIN; 548 break; 549 550 default: 551 /* Trap invalid mutex types; */ 552 ret = EINVAL; 553 } 554 555 return (ret); 556 } 557 558 static int 559 mutex_unlock_common(pthread_mutex_t *mutex) 560 { 561 struct pthread *curthread = tls_get_curthread(); 562 struct pthread_mutex *m; 563 564 if (__predict_false((m = *mutex)== NULL)) 565 return (EINVAL); 566 if (__predict_false(m->m_owner != curthread)) 567 return (EPERM); 568 569 if (__predict_false( 570 m->m_type == PTHREAD_MUTEX_RECURSIVE && 571 m->m_count > 0)) { 572 m->m_count--; 573 } else { 574 /* 575 * Clear the count in case this is a recursive mutex. 576 */ 577 m->m_count = 0; 578 m->m_owner = NULL; 579 /* Remove the mutex from the threads queue. */ 580 MUTEX_ASSERT_IS_OWNED(m); 581 TAILQ_REMOVE(&curthread->mutexq, m, m_qe); 582 MUTEX_INIT_LINK(m); 583 /* 584 * Hand off the mutex to the next waiting thread. 585 */ 586 THR_UMTX_UNLOCK(curthread, &m->m_lock); 587 } 588 return (0); 589 } 590 591 int 592 _mutex_cv_lock(pthread_mutex_t *m, int count) 593 { 594 int ret; 595 596 if ((ret = _pthread_mutex_lock(m)) == 0) { 597 (*m)->m_refcount--; 598 (*m)->m_count += count; 599 } 600 return (ret); 601 } 602 603 int 604 _mutex_cv_unlock(pthread_mutex_t *mutex, int *count) 605 { 606 struct pthread *curthread = tls_get_curthread(); 607 struct pthread_mutex *m; 608 609 if (__predict_false(mutex == NULL)) 610 return (EINVAL); 611 if (__predict_false((m = *mutex) == NULL)) 612 return (EINVAL); 613 if (__predict_false(m->m_owner != curthread)) 614 return (EPERM); 615 616 *count = m->m_count; 617 m->m_count = 0; 618 m->m_refcount++; 619 m->m_owner = NULL; 620 /* Remove the mutex from the threads queue. */ 621 MUTEX_ASSERT_IS_OWNED(m); 622 TAILQ_REMOVE(&curthread->mutexq, m, m_qe); 623 MUTEX_INIT_LINK(m); 624 THR_UMTX_UNLOCK(curthread, &m->m_lock); 625 return (0); 626 } 627 628 void 629 _mutex_unlock_private(pthread_t pthread) 630 { 631 struct pthread_mutex *m, *m_next; 632 633 for (m = TAILQ_FIRST(&pthread->mutexq); m != NULL; m = m_next) { 634 m_next = TAILQ_NEXT(m, m_qe); 635 if ((m->m_flags & MUTEX_FLAGS_PRIVATE) != 0) 636 _pthread_mutex_unlock(&m); 637 } 638 } 639 640 __strong_reference(__pthread_mutex_init, pthread_mutex_init); 641 __strong_reference(__pthread_mutex_lock, pthread_mutex_lock); 642 __strong_reference(__pthread_mutex_timedlock, pthread_mutex_timedlock); 643 __strong_reference(__pthread_mutex_trylock, pthread_mutex_trylock); 644 645 /* Single underscore versions provided for libc internal usage: */ 646 /* No difference between libc and application usage of these: */ 647 __strong_reference(_pthread_mutex_destroy, pthread_mutex_destroy); 648 __strong_reference(_pthread_mutex_unlock, pthread_mutex_unlock); 649