1 /* $OpenBSD: rthread.c,v 1.91 2016/05/07 19:05:22 guenther Exp $ */ 2 /* 3 * Copyright (c) 2004,2005 Ted Unangst <tedu@openbsd.org> 4 * All Rights Reserved. 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 /* 19 * The heart of rthreads. Basic functions like creating and joining 20 * threads. 21 */ 22 23 #include <sys/types.h> 24 #ifndef NO_PIC 25 #include <sys/exec_elf.h> 26 #pragma weak _DYNAMIC 27 #endif 28 29 #include <stdlib.h> 30 #include <unistd.h> 31 #include <signal.h> 32 #include <stdio.h> 33 #include <string.h> 34 #include <errno.h> 35 #include <dlfcn.h> 36 #include <tib.h> 37 38 #include <pthread.h> 39 40 #include "cancel.h" /* in libc/include */ 41 #include "rthread.h" 42 #include "rthread_cb.h" 43 44 /* 45 * Call nonstandard functions via names in the reserved namespace: 46 * dlctl() -> _dlctl() 47 * getthrid -> _thread_sys_getthrid 48 */ 49 typeof(dlctl) dlctl asm("_dlctl") __attribute__((weak)); 50 REDIRECT_SYSCALL(getthrid); 51 52 /* weak stub to be overriden by ld.so */ 53 int dlctl(void *handle, int cmd, void *data) { return 0; } 54 55 /* 56 * libc's signal wrappers hide SIGTHR; we need to call the real syscall 57 * stubs _thread_sys_* directly. 58 */ 59 REDIRECT_SYSCALL(sigaction); 60 REDIRECT_SYSCALL(sigprocmask); 61 REDIRECT_SYSCALL(thrkill); 62 63 static int concurrency_level; /* not used */ 64 65 struct _spinlock _SPINLOCK_UNLOCKED_ASSIGN = _SPINLOCK_UNLOCKED; 66 67 int _threads_ready; 68 size_t _thread_pagesize; 69 struct listhead _thread_list = LIST_HEAD_INITIALIZER(_thread_list); 70 struct _spinlock _thread_lock = _SPINLOCK_UNLOCKED; 71 static struct pthread_queue _thread_gc_list 72 = TAILQ_HEAD_INITIALIZER(_thread_gc_list); 73 static struct _spinlock _thread_gc_lock = _SPINLOCK_UNLOCKED; 74 static struct pthread _initial_thread; 75 76 struct pthread_attr _rthread_attr_default = { 77 .stack_addr = NULL, 78 .stack_size = RTHREAD_STACK_SIZE_DEF, 79 /* .guard_size set in _rthread_init */ 80 .detach_state = PTHREAD_CREATE_JOINABLE, 81 .contention_scope = PTHREAD_SCOPE_SYSTEM, 82 .sched_policy = SCHED_OTHER, 83 .sched_param = { .sched_priority = 0 }, 84 .sched_inherit = PTHREAD_INHERIT_SCHED, 85 }; 86 87 /* 88 * internal support functions 89 */ 90 void 91 _spinlock(volatile struct _spinlock *lock) 92 { 93 while (_atomic_lock(&lock->ticket)) 94 sched_yield(); 95 } 96 97 int 98 _spinlocktry(volatile struct _spinlock *lock) 99 { 100 return 0 == _atomic_lock(&lock->ticket); 101 } 102 103 void 104 _spinunlock(volatile struct _spinlock *lock) 105 { 106 lock->ticket = _ATOMIC_LOCK_UNLOCKED; 107 } 108 109 static void 110 _rthread_start(void *v) 111 { 112 pthread_t thread = v; 113 void *retval; 114 115 retval = thread->fn(thread->arg); 116 pthread_exit(retval); 117 } 118 119 static void 120 sigthr_handler(__unused int sig) 121 { 122 struct tib *tib = TIB_GET(); 123 pthread_t self = tib->tib_thread; 124 125 /* 126 * Do nothing unless 127 * 1) pthread_cancel() has been called on this thread, 128 * 2) cancelation is enabled for it, and 129 * 3) we're not already in cancelation processing 130 */ 131 if (!tib->tib_canceled || tib->tib_cantcancel) 132 return; 133 134 /* 135 * If delaying cancels inside complex ops (pthread_cond_wait, 136 * pthread_join, etc), just mark that this has happened to 137 * prevent a race with going to sleep 138 */ 139 if (tib->tib_cancel_point & CANCEL_POINT_DELAYED) { 140 self->delayed_cancel = 1; 141 return; 142 } 143 144 /* 145 * otherwise, if in a cancel point or async cancels are 146 * enabled, then exit 147 */ 148 if (tib->tib_cancel_point || 149 (tib->tib_thread_flags & TIB_THREAD_ASYNC_CANCEL)) 150 pthread_exit(PTHREAD_CANCELED); 151 } 152 153 154 /* 155 * A few basic callbacks for libc. The first couple are only used 156 * on archs where there isn't a fast TCB_GET() 157 */ 158 #ifndef TCB_HAVE_MD_GET 159 static int * 160 multi_threaded_errnoptr(void) 161 { 162 return (&TIB_GET()->tib_errno); 163 } 164 165 static void * 166 multi_threaded_tcb(void) 167 { 168 return (TCB_GET()); 169 } 170 #endif /* TCB_HAVE_MD_GET */ 171 172 void 173 _thread_canceled(void) 174 { 175 pthread_exit(PTHREAD_CANCELED); 176 } 177 178 void 179 _rthread_init(void) 180 { 181 pthread_t thread = &_initial_thread; 182 struct tib *tib; 183 struct sigaction sa; 184 185 tib = TIB_GET(); 186 tib->tib_thread = thread; 187 thread->tib = tib; 188 189 thread->donesem.lock = _SPINLOCK_UNLOCKED_ASSIGN; 190 tib->tib_thread_flags = TIB_THREAD_INITIAL_STACK; 191 thread->flags_lock = _SPINLOCK_UNLOCKED_ASSIGN; 192 strlcpy(thread->name, "Main process", sizeof(thread->name)); 193 LIST_INSERT_HEAD(&_thread_list, thread, threads); 194 _rthread_debug_init(); 195 196 _thread_pagesize = (size_t)sysconf(_SC_PAGESIZE); 197 _rthread_attr_default.guard_size = _thread_pagesize; 198 thread->attr = _rthread_attr_default; 199 200 /* get libc to start using our callbacks */ 201 { 202 struct thread_callbacks cb = { 0 }; 203 204 #ifndef TCB_HAVE_MD_GET 205 cb.tc_errnoptr = multi_threaded_errnoptr; 206 cb.tc_tcb = multi_threaded_tcb; 207 #endif 208 cb.tc_canceled = _thread_canceled; 209 cb.tc_flockfile = _thread_flockfile; 210 cb.tc_ftrylockfile = _thread_ftrylockfile; 211 cb.tc_funlockfile = _thread_funlockfile; 212 cb.tc_malloc_lock = _thread_malloc_lock; 213 cb.tc_malloc_unlock = _thread_malloc_unlock; 214 cb.tc_atexit_lock = _thread_atexit_lock; 215 cb.tc_atexit_unlock = _thread_atexit_unlock; 216 cb.tc_atfork_lock = _thread_atfork_lock; 217 cb.tc_atfork_unlock = _thread_atfork_unlock; 218 cb.tc_arc4_lock = _thread_arc4_lock; 219 cb.tc_arc4_unlock = _thread_arc4_unlock; 220 cb.tc_mutex_lock = _thread_mutex_lock; 221 cb.tc_mutex_unlock = _thread_mutex_unlock; 222 cb.tc_mutex_destroy = _thread_mutex_destroy; 223 cb.tc_tag_lock = _thread_tag_lock; 224 cb.tc_tag_unlock = _thread_tag_unlock; 225 cb.tc_tag_storage = _thread_tag_storage; 226 cb.tc_fork = _thread_fork; 227 cb.tc_vfork = _thread_vfork; 228 _thread_set_callbacks(&cb, sizeof(cb)); 229 } 230 231 #ifndef NO_PIC 232 if (_DYNAMIC) { 233 dlctl(NULL, DL_SETTHREADLCK, _rthread_dl_lock); 234 } 235 #endif 236 237 /* 238 * Set the handler on the signal used for cancelation and 239 * suspension, and make sure it's unblocked 240 */ 241 memset(&sa, 0, sizeof(sa)); 242 sigemptyset(&sa.sa_mask); 243 sa.sa_handler = sigthr_handler; 244 sigaction(SIGTHR, &sa, NULL); 245 sigaddset(&sa.sa_mask, SIGTHR); 246 sigprocmask(SIG_UNBLOCK, &sa.sa_mask, NULL); 247 248 _threads_ready = 1; 249 250 _rthread_debug(1, "rthread init\n"); 251 } 252 253 static void 254 _rthread_free(pthread_t thread) 255 { 256 _spinlock(&_thread_gc_lock); 257 TAILQ_INSERT_TAIL(&_thread_gc_list, thread, waiting); 258 _spinunlock(&_thread_gc_lock); 259 } 260 261 /* 262 * real pthread functions 263 */ 264 pthread_t 265 pthread_self(void) 266 { 267 if (!_threads_ready) 268 _rthread_init(); 269 270 return (TIB_GET()->tib_thread); 271 } 272 DEF_STD(pthread_self); 273 274 static void 275 _rthread_reaper(void) 276 { 277 pthread_t thread; 278 279 restart: 280 _spinlock(&_thread_gc_lock); 281 TAILQ_FOREACH(thread, &_thread_gc_list, waiting) { 282 if (thread->tib->tib_tid != 0) 283 continue; 284 TAILQ_REMOVE(&_thread_gc_list, thread, waiting); 285 _spinunlock(&_thread_gc_lock); 286 if (thread != &_initial_thread) { 287 _rthread_debug(3, "rthread reaping %p stack %p\n", 288 (void *)thread, (void *)thread->stack); 289 _rthread_free_stack(thread->stack); 290 _dl_free_tib(thread->tib, sizeof(*thread)); 291 } else { 292 /* initial thread isn't part of TIB allocation */ 293 _rthread_debug(3, "rthread reaping %p (initial)\n", 294 (void *)thread); 295 _dl_free_tib(thread->tib, 0); 296 } 297 goto restart; 298 } 299 _spinunlock(&_thread_gc_lock); 300 } 301 302 void 303 pthread_exit(void *retval) 304 { 305 struct rthread_cleanup_fn *clfn; 306 struct tib *tib = TIB_GET(); 307 pthread_t thread; 308 309 if (!_threads_ready) 310 _rthread_init(); 311 thread = tib->tib_thread; 312 313 if (tib->tib_cantcancel & CANCEL_DYING) { 314 /* 315 * Called pthread_exit() from destructor or cancelation 316 * handler: blow up. XXX write something to stderr? 317 */ 318 abort(); 319 //_exit(42); 320 } 321 322 tib->tib_cantcancel |= CANCEL_DYING; 323 324 thread->retval = retval; 325 326 for (clfn = thread->cleanup_fns; clfn; ) { 327 struct rthread_cleanup_fn *oclfn = clfn; 328 clfn = clfn->next; 329 oclfn->fn(oclfn->arg); 330 free(oclfn); 331 } 332 _rthread_tls_destructors(thread); 333 _spinlock(&_thread_lock); 334 LIST_REMOVE(thread, threads); 335 _spinunlock(&_thread_lock); 336 337 _spinlock(&thread->flags_lock); 338 if (thread->flags & THREAD_DETACHED) { 339 _spinunlock(&thread->flags_lock); 340 _rthread_free(thread); 341 } else { 342 thread->flags |= THREAD_DONE; 343 _spinunlock(&thread->flags_lock); 344 _sem_post(&thread->donesem); 345 } 346 347 __threxit(&tib->tib_tid); 348 for(;;); 349 } 350 DEF_STD(pthread_exit); 351 352 int 353 pthread_join(pthread_t thread, void **retval) 354 { 355 int e; 356 struct tib *tib = TIB_GET(); 357 pthread_t self; 358 PREP_CANCEL_POINT(tib); 359 360 if (!_threads_ready) 361 _rthread_init(); 362 self = tib->tib_thread; 363 364 e = 0; 365 ENTER_DELAYED_CANCEL_POINT(tib, self); 366 if (thread == NULL) 367 e = EINVAL; 368 else if (thread == self) 369 e = EDEADLK; 370 else if (thread->flags & THREAD_DETACHED) 371 e = EINVAL; 372 else if ((e = _sem_wait(&thread->donesem, 0, NULL, 373 &self->delayed_cancel)) == 0) { 374 if (retval) 375 *retval = thread->retval; 376 377 /* 378 * We should be the last having a ref to this thread, 379 * but someone stupid or evil might haved detached it; 380 * in that case the thread will clean up itself 381 */ 382 if ((thread->flags & THREAD_DETACHED) == 0) 383 _rthread_free(thread); 384 } 385 386 LEAVE_CANCEL_POINT_INNER(tib, e); 387 _rthread_reaper(); 388 return (e); 389 } 390 391 int 392 pthread_detach(pthread_t thread) 393 { 394 int rc = 0; 395 396 _spinlock(&thread->flags_lock); 397 if (thread->flags & THREAD_DETACHED) { 398 rc = EINVAL; 399 _spinunlock(&thread->flags_lock); 400 } else if (thread->flags & THREAD_DONE) { 401 _spinunlock(&thread->flags_lock); 402 _rthread_free(thread); 403 } else { 404 thread->flags |= THREAD_DETACHED; 405 _spinunlock(&thread->flags_lock); 406 } 407 _rthread_reaper(); 408 return (rc); 409 } 410 411 int 412 pthread_create(pthread_t *threadp, const pthread_attr_t *attr, 413 void *(*start_routine)(void *), void *arg) 414 { 415 extern int __isthreaded; 416 struct tib *tib; 417 pthread_t thread; 418 struct __tfork param; 419 int rc; 420 421 if (!_threads_ready) 422 _rthread_init(); 423 424 _rthread_reaper(); 425 426 tib = _dl_allocate_tib(sizeof(*thread)); 427 if (tib == NULL) 428 return (ENOMEM); 429 thread = tib->tib_thread; 430 memset(thread, 0, sizeof(*thread)); 431 thread->tib = tib; 432 thread->donesem.lock = _SPINLOCK_UNLOCKED_ASSIGN; 433 thread->flags_lock = _SPINLOCK_UNLOCKED_ASSIGN; 434 thread->fn = start_routine; 435 thread->arg = arg; 436 tib->tib_tid = -1; 437 438 thread->attr = attr != NULL ? *(*attr) : _rthread_attr_default; 439 if (thread->attr.sched_inherit == PTHREAD_INHERIT_SCHED) { 440 pthread_t self = pthread_self(); 441 442 thread->attr.sched_policy = self->attr.sched_policy; 443 thread->attr.sched_param = self->attr.sched_param; 444 } 445 if (thread->attr.detach_state == PTHREAD_CREATE_DETACHED) 446 thread->flags |= THREAD_DETACHED; 447 448 thread->stack = _rthread_alloc_stack(thread); 449 if (!thread->stack) { 450 rc = errno; 451 goto fail1; 452 } 453 454 param.tf_tcb = TIB_TO_TCB(tib); 455 param.tf_tid = &tib->tib_tid; 456 param.tf_stack = thread->stack->sp; 457 458 _spinlock(&_thread_lock); 459 LIST_INSERT_HEAD(&_thread_list, thread, threads); 460 _spinunlock(&_thread_lock); 461 462 /* we're going to be multi-threaded real soon now */ 463 __isthreaded = 1; 464 rc = __tfork_thread(¶m, sizeof(param), _rthread_start, thread); 465 if (rc != -1) { 466 /* success */ 467 *threadp = thread; 468 return (0); 469 } 470 471 rc = errno; 472 473 _spinlock(&_thread_lock); 474 LIST_REMOVE(thread, threads); 475 _spinunlock(&_thread_lock); 476 _rthread_free_stack(thread->stack); 477 fail1: 478 _dl_free_tib(tib, sizeof(*thread)); 479 480 return (rc); 481 } 482 483 int 484 pthread_kill(pthread_t thread, int sig) 485 { 486 struct tib *tib = thread->tib; 487 488 if (sig == SIGTHR) 489 return (EINVAL); 490 if (thrkill(tib->tib_tid, sig, TIB_TO_TCB(tib))) 491 return (errno); 492 return (0); 493 } 494 495 int 496 pthread_equal(pthread_t t1, pthread_t t2) 497 { 498 return (t1 == t2); 499 } 500 501 int 502 pthread_cancel(pthread_t thread) 503 { 504 struct tib *tib = thread->tib; 505 pid_t tid = tib->tib_tid; 506 507 if (tib->tib_canceled == 0 && tid != 0 && 508 (tib->tib_cantcancel & CANCEL_DYING) == 0) { 509 tib->tib_canceled = 1; 510 511 if ((tib->tib_cantcancel & CANCEL_DISABLED) == 0) { 512 thrkill(tid, SIGTHR, TIB_TO_TCB(tib)); 513 return (0); 514 } 515 } 516 return (0); 517 } 518 519 void 520 pthread_testcancel(void) 521 { 522 struct tib *tib = TIB_GET(); 523 524 if (tib->tib_canceled && (tib->tib_cantcancel & CANCEL_DISABLED) == 0) 525 pthread_exit(PTHREAD_CANCELED); 526 } 527 528 int 529 pthread_setcancelstate(int state, int *oldstatep) 530 { 531 struct tib *tib = TIB_GET(); 532 int oldstate; 533 534 oldstate = tib->tib_cantcancel & CANCEL_DISABLED ? 535 PTHREAD_CANCEL_DISABLE : PTHREAD_CANCEL_ENABLE; 536 if (state == PTHREAD_CANCEL_ENABLE) { 537 tib->tib_cantcancel &= ~CANCEL_DISABLED; 538 } else if (state == PTHREAD_CANCEL_DISABLE) { 539 tib->tib_cantcancel |= CANCEL_DISABLED; 540 } else { 541 return (EINVAL); 542 } 543 if (oldstatep) 544 *oldstatep = oldstate; 545 546 return (0); 547 } 548 DEF_STD(pthread_setcancelstate); 549 550 int 551 pthread_setcanceltype(int type, int *oldtypep) 552 { 553 struct tib *tib = TIB_GET(); 554 int oldtype; 555 556 oldtype = tib->tib_thread_flags & TIB_THREAD_ASYNC_CANCEL ? 557 PTHREAD_CANCEL_ASYNCHRONOUS : PTHREAD_CANCEL_DEFERRED; 558 if (type == PTHREAD_CANCEL_DEFERRED) { 559 tib->tib_thread_flags &=~ TIB_THREAD_ASYNC_CANCEL; 560 } else if (type == PTHREAD_CANCEL_ASYNCHRONOUS) { 561 tib->tib_thread_flags |= TIB_THREAD_ASYNC_CANCEL; 562 } else { 563 return (EINVAL); 564 } 565 if (oldtypep) 566 *oldtypep = oldtype; 567 568 return (0); 569 } 570 571 void 572 pthread_cleanup_push(void (*fn)(void *), void *arg) 573 { 574 struct rthread_cleanup_fn *clfn; 575 pthread_t self = pthread_self(); 576 577 clfn = calloc(1, sizeof(*clfn)); 578 if (!clfn) 579 return; 580 clfn->fn = fn; 581 clfn->arg = arg; 582 clfn->next = self->cleanup_fns; 583 self->cleanup_fns = clfn; 584 } 585 586 void 587 pthread_cleanup_pop(int execute) 588 { 589 struct rthread_cleanup_fn *clfn; 590 pthread_t self = pthread_self(); 591 592 clfn = self->cleanup_fns; 593 if (clfn) { 594 self->cleanup_fns = clfn->next; 595 if (execute) 596 clfn->fn(clfn->arg); 597 free(clfn); 598 } 599 } 600 601 int 602 pthread_getconcurrency(void) 603 { 604 return (concurrency_level); 605 } 606 607 int 608 pthread_setconcurrency(int new_level) 609 { 610 if (new_level < 0) 611 return (EINVAL); 612 concurrency_level = new_level; 613 return (0); 614 } 615 616 /* 617 * compat debug stuff 618 */ 619 void 620 _thread_dump_info(void) 621 { 622 pthread_t thread; 623 624 _spinlock(&_thread_lock); 625 LIST_FOREACH(thread, &_thread_list, threads) 626 printf("thread %d flags 0x%x name %s\n", thread->tib->tib_tid, 627 thread->tib->tib_thread_flags, thread->name); 628 _spinunlock(&_thread_lock); 629 } 630 631 #ifndef NO_PIC 632 /* 633 * _rthread_dl_lock() provides the locking for dlopen(), dlclose(), and 634 * the function called via atexit() to invoke all destructors. The latter 635 * two call shared-object destructors, which may need to call dlclose(), 636 * so this lock needs to permit recursive locking. 637 * The specific code here was extracted from _rthread_mutex_lock() and 638 * pthread_mutex_unlock() and simplified to use the static variables. 639 */ 640 void 641 _rthread_dl_lock(int what) 642 { 643 static struct _spinlock lock = _SPINLOCK_UNLOCKED; 644 static pthread_t owner = NULL; 645 static struct pthread_queue lockers = TAILQ_HEAD_INITIALIZER(lockers); 646 static int count = 0; 647 648 if (what == 0) { 649 pthread_t self = pthread_self(); 650 651 /* lock, possibly recursive */ 652 _spinlock(&lock); 653 if (owner == NULL) { 654 owner = self; 655 } else if (owner != self) { 656 TAILQ_INSERT_TAIL(&lockers, self, waiting); 657 while (owner != self) { 658 __thrsleep(self, 0 | _USING_TICKETS, NULL, 659 &lock.ticket, NULL); 660 _spinlock(&lock); 661 } 662 } 663 count++; 664 _spinunlock(&lock); 665 } else if (what == 1) { 666 /* unlock, possibly recursive */ 667 if (--count == 0) { 668 pthread_t next; 669 670 _spinlock(&lock); 671 owner = next = TAILQ_FIRST(&lockers); 672 if (next != NULL) 673 TAILQ_REMOVE(&lockers, next, waiting); 674 _spinunlock(&lock); 675 if (next != NULL) 676 __thrwakeup(next, 1); 677 } 678 } else { 679 /* reinit: used in child after fork to clear the queue */ 680 lock = _SPINLOCK_UNLOCKED_ASSIGN; 681 if (--count == 0) 682 owner = NULL; 683 TAILQ_INIT(&lockers); 684 } 685 } 686 #endif 687