Annotation of src/lib/libpthread/pthread.c, Revision 1.71.2.2
1.71.2.2! ad 1: /* $NetBSD: pthread.c,v 1.71 2007/08/04 18:54:12 ad Exp $ */
! 2:
! 3: /*-
! 4: * Copyright (c) 2001, 2002, 2003, 2006, 2007 The NetBSD Foundation, Inc.
! 5: * All rights reserved.
! 6: *
! 7: * This code is derived from software contributed to The NetBSD Foundation
! 8: * by Nathan J. Williams and Andrew Doran.
! 9: *
! 10: * Redistribution and use in source and binary forms, with or without
! 11: * modification, are permitted provided that the following conditions
! 12: * are met:
! 13: * 1. Redistributions of source code must retain the above copyright
! 14: * notice, this list of conditions and the following disclaimer.
! 15: * 2. Redistributions in binary form must reproduce the above copyright
! 16: * notice, this list of conditions and the following disclaimer in the
! 17: * documentation and/or other materials provided with the distribution.
! 18: * 3. All advertising materials mentioning features or use of this software
! 19: * must display the following acknowledgement:
! 20: * This product includes software developed by the NetBSD
! 21: * Foundation, Inc. and its contributors.
! 22: * 4. Neither the name of The NetBSD Foundation nor the names of its
! 23: * contributors may be used to endorse or promote products derived
! 24: * from this software without specific prior written permission.
! 25: *
! 26: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
! 27: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 28: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 29: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
! 30: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 31: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 32: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 33: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 34: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 35: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 36: * POSSIBILITY OF SUCH DAMAGE.
! 37: */
! 38:
! 39: #include <sys/cdefs.h>
! 40: __RCSID("$NetBSD: pthread.c,v 1.71 2007/08/04 18:54:12 ad Exp $");
! 41:
! 42: #include <err.h>
! 43: #include <errno.h>
! 44: #include <lwp.h>
! 45: #include <signal.h>
! 46: #include <stdio.h>
! 47: #include <stdlib.h>
! 48: #include <string.h>
! 49: #include <syslog.h>
! 50: #include <ucontext.h>
! 51: #include <unistd.h>
! 52: #include <sys/param.h>
! 53: #include <sys/sysctl.h>
! 54:
! 55: #include <sched.h>
! 56: #include "pthread.h"
! 57: #include "pthread_int.h"
! 58:
! 59: #ifdef PTHREAD_MAIN_DEBUG
! 60: #define SDPRINTF(x) DPRINTF(x)
! 61: #else
! 62: #define SDPRINTF(x)
! 63: #endif
! 64:
! 65: /* Maximum number of LWPs to unpark in one operation. */
! 66: #define PTHREAD__UNPARK_MAX 128
! 67:
! 68: /* How many times to try acquiring spin locks on MP systems. */
! 69: #define PTHREAD__NSPINS 1024
! 70:
! 71: static void pthread__create_tramp(void *(*)(void *), void *);
! 72: static void pthread__initthread(pthread_t);
! 73:
! 74: int pthread__started;
! 75:
! 76: pthread_spin_t pthread__queue_lock = __SIMPLELOCK_UNLOCKED;
! 77: pthread_queue_t pthread__allqueue;
! 78: pthread_queue_t pthread__deadqueue;
! 79:
! 80: static pthread_attr_t pthread_default_attr;
! 81:
! 82: enum {
! 83: DIAGASSERT_ABORT = 1<<0,
! 84: DIAGASSERT_STDERR = 1<<1,
! 85: DIAGASSERT_SYSLOG = 1<<2
! 86: };
! 87:
! 88: static int pthread__diagassert = DIAGASSERT_ABORT | DIAGASSERT_STDERR;
! 89:
! 90: int pthread__concurrency, pthread__maxconcurrency, pthread__nspins;
! 91: int pthread__unpark_max = PTHREAD__UNPARK_MAX;
! 92:
! 93: int _sys___sigprocmask14(int, const sigset_t *, sigset_t *);
! 94:
! 95: __strong_alias(__libc_thr_self,pthread_self)
! 96: __strong_alias(__libc_thr_create,pthread_create)
! 97: __strong_alias(__libc_thr_exit,pthread_exit)
! 98: __strong_alias(__libc_thr_errno,pthread__errno)
! 99: __strong_alias(__libc_thr_setcancelstate,pthread_setcancelstate)
! 100:
! 101: /*
! 102: * Static library kludge. Place a reference to a symbol any library
! 103: * file which does not already have a reference here.
! 104: */
! 105: extern int pthread__cancel_stub_binder;
! 106:
! 107: void *pthread__static_lib_binder[] = {
! 108: &pthread__cancel_stub_binder,
! 109: pthread_cond_init,
! 110: pthread_mutex_init,
! 111: pthread_rwlock_init,
! 112: pthread_barrier_init,
! 113: pthread_key_create,
! 114: pthread_setspecific,
! 115: };
! 116:
! 117: /*
! 118: * This needs to be started by the library loading code, before main()
! 119: * gets to run, for various things that use the state of the initial thread
! 120: * to work properly (thread-specific data is an application-visible example;
! 121: * spinlock counts for mutexes is an internal example).
! 122: */
! 123: void
! 124: pthread_init(void)
! 125: {
! 126: pthread_t first;
! 127: char *p;
! 128: int i, mib[2], ncpu;
! 129: size_t len;
! 130: extern int __isthreaded;
! 131:
! 132: mib[0] = CTL_HW;
! 133: mib[1] = HW_NCPU;
! 134:
! 135: len = sizeof(ncpu);
! 136: if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == -1)
! 137: err(1, "sysctl(hw.ncpu");
! 138:
! 139: /* Initialize locks first; they're needed elsewhere. */
! 140: pthread__lockprim_init(ncpu);
! 141:
! 142: /*
! 143: * Get number of CPUs, and maximum number of LWPs that can be
! 144: * unparked at once.
! 145: */
! 146: if ((pthread__concurrency = ncpu) > 1)
! 147: pthread__nspins = PTHREAD__NSPINS;
! 148: else
! 149: pthread__nspins = 1;
! 150: if ((p = getenv("PTHREAD_NSPINS")) != NULL)
! 151: pthread__nspins = atoi(p);
! 152: i = (int)_lwp_unpark_all(NULL, 0, NULL);
! 153: if (i == -1)
! 154: err(1, "_lwp_unpark_all");
! 155: if (i < pthread__unpark_max)
! 156: pthread__unpark_max = i;
! 157:
! 158: /* Basic data structure setup */
! 159: pthread_attr_init(&pthread_default_attr);
! 160: PTQ_INIT(&pthread__allqueue);
! 161: PTQ_INIT(&pthread__deadqueue);
! 162: /* Create the thread structure corresponding to main() */
! 163: pthread__initmain(&first);
! 164: pthread__initthread(first);
! 165:
! 166: first->pt_state = PT_STATE_RUNNING;
! 167: first->pt_lid = _lwp_self();
! 168: PTQ_INSERT_HEAD(&pthread__allqueue, first, pt_allq);
! 169:
! 170: /* Start subsystems */
! 171: PTHREAD_MD_INIT
! 172: #ifdef PTHREAD__DEBUG
! 173: pthread__debug_init(ncpu);
! 174: #endif
! 175:
! 176: for (p = getenv("PTHREAD_DIAGASSERT"); p && *p; p++) {
! 177: switch (*p) {
! 178: case 'a':
! 179: pthread__diagassert |= DIAGASSERT_ABORT;
! 180: break;
! 181: case 'A':
! 182: pthread__diagassert &= ~DIAGASSERT_ABORT;
! 183: break;
! 184: case 'e':
! 185: pthread__diagassert |= DIAGASSERT_STDERR;
! 186: break;
! 187: case 'E':
! 188: pthread__diagassert &= ~DIAGASSERT_STDERR;
! 189: break;
! 190: case 'l':
! 191: pthread__diagassert |= DIAGASSERT_SYSLOG;
! 192: break;
! 193: case 'L':
! 194: pthread__diagassert &= ~DIAGASSERT_SYSLOG;
! 195: break;
! 196: }
! 197: }
! 198:
! 199:
! 200: /* Tell libc that we're here and it should role-play accordingly. */
! 201: __isthreaded = 1;
! 202: }
! 203:
! 204: static void
! 205: pthread__child_callback(void)
! 206: {
! 207: /*
! 208: * Clean up data structures that a forked child process might
! 209: * trip over. Note that if threads have been created (causing
! 210: * this handler to be registered) the standards say that the
! 211: * child will trigger undefined behavior if it makes any
! 212: * pthread_* calls (or any other calls that aren't
! 213: * async-signal-safe), so we don't really have to clean up
! 214: * much. Anything that permits some pthread_* calls to work is
! 215: * merely being polite.
! 216: */
! 217: pthread__started = 0;
! 218: }
! 219:
! 220: static void
! 221: pthread__start(void)
! 222: {
! 223: pthread_t self;
! 224:
! 225: self = pthread__self(); /* should be the "main()" thread */
! 226:
! 227: /*
! 228: * Per-process timers are cleared by fork(); despite the
! 229: * various restrictions on fork() and threads, it's legal to
! 230: * fork() before creating any threads.
! 231: */
! 232: pthread_atfork(NULL, NULL, pthread__child_callback);
! 233: SDPRINTF(("(pthread__start %p) Started.\n", self));
! 234: }
! 235:
! 236:
! 237: /* General-purpose thread data structure sanitization. */
! 238: /* ARGSUSED */
! 239: static void
! 240: pthread__initthread(pthread_t t)
! 241: {
! 242:
! 243: t->pt_magic = PT_MAGIC;
! 244: t->pt_spinlocks = 0;
! 245: t->pt_exitval = NULL;
! 246: t->pt_flags = 0;
! 247: t->pt_cancel = 0;
! 248: t->pt_errno = 0;
! 249: t->pt_state = PT_STATE_RUNNING;
! 250:
! 251: pthread_lockinit(&t->pt_lock);
! 252: PTQ_INIT(&t->pt_cleanup_stack);
! 253: PTQ_INIT(&t->pt_joiners);
! 254: memset(&t->pt_specific, 0, sizeof(int) * PTHREAD_KEYS_MAX);
! 255: t->pt_name = NULL;
! 256: }
! 257:
! 258:
! 259: int
! 260: pthread_create(pthread_t *thread, const pthread_attr_t *attr,
! 261: void *(*startfunc)(void *), void *arg)
! 262: {
! 263: pthread_t self, newthread;
! 264: pthread_attr_t nattr;
! 265: struct pthread_attr_private *p;
! 266: char * volatile name;
! 267: int ret, flag;
! 268:
! 269: PTHREADD_ADD(PTHREADD_CREATE);
! 270:
! 271: /*
! 272: * It's okay to check this without a lock because there can
! 273: * only be one thread before it becomes true.
! 274: */
! 275: if (pthread__started == 0) {
! 276: pthread__start();
! 277: pthread__started = 1;
! 278: }
! 279:
! 280: if (attr == NULL)
! 281: nattr = pthread_default_attr;
! 282: else if (attr->pta_magic == PT_ATTR_MAGIC)
! 283: nattr = *attr;
! 284: else
! 285: return EINVAL;
! 286:
! 287: /* Fetch misc. attributes from the attr structure. */
! 288: name = NULL;
! 289: if ((p = nattr.pta_private) != NULL)
! 290: if (p->ptap_name[0] != '\0')
! 291: if ((name = strdup(p->ptap_name)) == NULL)
! 292: return ENOMEM;
! 293:
! 294: self = pthread__self();
! 295: newthread = NULL;
! 296:
! 297: if (!PTQ_EMPTY(&pthread__deadqueue)) {
! 298: pthread_spinlock(self, &pthread__queue_lock);
! 299: newthread = PTQ_FIRST(&pthread__deadqueue);
! 300: if (newthread != NULL) {
! 301: PTQ_REMOVE(&pthread__deadqueue, newthread, pt_allq);
! 302: pthread_spinunlock(self, &pthread__queue_lock);
! 303: if ((newthread->pt_flags & PT_FLAG_DETACHED) != 0) {
! 304: /* Still running? */
! 305: if (_lwp_kill(newthread->pt_lid, 0) == 0 ||
! 306: errno != ESRCH) {
! 307: pthread_spinlock(self,
! 308: &pthread__queue_lock);
! 309: PTQ_INSERT_TAIL(&pthread__deadqueue,
! 310: newthread, pt_allq);
! 311: pthread_spinunlock(self,
! 312: &pthread__queue_lock);
! 313: newthread = NULL;
! 314: }
! 315: }
! 316: } else
! 317: pthread_spinunlock(self, &pthread__queue_lock);
! 318: }
! 319:
! 320: if (newthread == NULL) {
! 321: /* Set up a stack and allocate space for a pthread_st. */
! 322: ret = pthread__stackalloc(&newthread);
! 323: if (ret != 0) {
! 324: if (name)
! 325: free(name);
! 326: return ret;
! 327: }
! 328: }
! 329:
! 330: /* 2. Set up state. */
! 331: pthread__initthread(newthread);
! 332: newthread->pt_flags = nattr.pta_flags;
! 333:
! 334: /* 3. Set up misc. attributes. */
! 335: newthread->pt_name = name;
! 336:
! 337: /*
! 338: * 4. Set up context.
! 339: *
! 340: * The pt_uc pointer points to a location safely below the
! 341: * stack start; this is arranged by pthread__stackalloc().
! 342: */
! 343: _INITCONTEXT_U(newthread->pt_uc);
! 344: #ifdef PTHREAD_MACHINE_HAS_ID_REGISTER
! 345: pthread__uc_id(newthread->pt_uc) = newthread;
! 346: #endif
! 347: newthread->pt_uc->uc_stack = newthread->pt_stack;
! 348: newthread->pt_uc->uc_link = NULL;
! 349: makecontext(newthread->pt_uc, pthread__create_tramp, 2,
! 350: startfunc, arg);
! 351:
! 352: /* 5. Add to list of all threads. */
! 353: pthread_spinlock(self, &pthread__queue_lock);
! 354: PTQ_INSERT_HEAD(&pthread__allqueue, newthread, pt_allq);
! 355: pthread_spinunlock(self, &pthread__queue_lock);
! 356:
! 357: /* 5a. Create the new LWP. */
! 358: newthread->pt_sleeponq = 0;
! 359: flag = 0;
! 360: if ((newthread->pt_flags & PT_FLAG_SUSPENDED) != 0)
! 361: flag |= LWP_SUSPENDED;
! 362: if ((newthread->pt_flags & PT_FLAG_DETACHED) != 0)
! 363: flag |= LWP_DETACHED;
! 364: ret = _lwp_create(newthread->pt_uc, (u_long)flag, &newthread->pt_lid);
! 365: if (ret != 0) {
! 366: SDPRINTF(("(pthread_create %p) _lwp_create: %s\n",
! 367: strerror(errno)));
! 368: free(name);
! 369: pthread_spinlock(self, &pthread__queue_lock);
! 370: PTQ_REMOVE(&pthread__allqueue, newthread, pt_allq);
! 371: PTQ_INSERT_HEAD(&pthread__deadqueue, newthread, pt_allq);
! 372: pthread_spinunlock(self, &pthread__queue_lock);
! 373: return ret;
! 374: }
! 375:
! 376: /* XXX must die */
! 377: newthread->pt_num = newthread->pt_lid;
! 378:
! 379: SDPRINTF(("(pthread_create %p) new thread %p (name %p, lid %d).\n",
! 380: self, newthread, newthread->pt_name,
! 381: (int)newthread->pt_lid));
! 382:
! 383: *thread = newthread;
! 384:
! 385: return 0;
! 386: }
! 387:
! 388:
! 389: static void
! 390: pthread__create_tramp(void *(*start)(void *), void *arg)
! 391: {
! 392: void *retval;
! 393:
! 394: /*
! 395: * Throw away some stack in a feeble attempt to reduce cache
! 396: * thrash. May help for SMT processors. XXX We should not
! 397: * be allocating stacks on fixed 2MB boundaries. Needs a
! 398: * thread register or decent thread local storage.
! 399: */
! 400: (void)alloca(((unsigned)pthread__self()->pt_lid & 7) << 8);
! 401:
! 402: retval = (*start)(arg);
! 403:
! 404: pthread_exit(retval);
! 405:
! 406: /*NOTREACHED*/
! 407: pthread__abort();
! 408: }
! 409:
! 410: int
! 411: pthread_suspend_np(pthread_t thread)
! 412: {
! 413: pthread_t self;
! 414:
! 415: self = pthread__self();
! 416: if (self == thread) {
! 417: return EDEADLK;
! 418: }
! 419: #ifdef ERRORCHECK
! 420: if (pthread__find(self, thread) != 0)
! 421: return ESRCH;
! 422: #endif
! 423: SDPRINTF(("(pthread_suspend_np %p) Suspend thread %p.\n",
! 424: self, thread));
! 425: return _lwp_suspend(thread->pt_lid);
! 426: }
! 427:
! 428: int
! 429: pthread_resume_np(pthread_t thread)
! 430: {
! 431: pthread_t self;
! 432:
! 433: self = pthread__self();
! 434: #ifdef ERRORCHECK
! 435: if (pthread__find(self, thread) != 0)
! 436: return ESRCH;
! 437: #endif
! 438: SDPRINTF(("(pthread_resume_np %p) Resume thread %p.\n",
! 439: self, thread));
! 440: return _lwp_continue(thread->pt_lid);
! 441: }
! 442:
! 443: void
! 444: pthread_exit(void *retval)
! 445: {
! 446: pthread_t self;
! 447: struct pt_clean_t *cleanup;
! 448: char *name;
! 449:
! 450: self = pthread__self();
! 451: SDPRINTF(("(pthread_exit %p) status %p, flags %x, cancel %d\n",
! 452: self, retval, self->pt_flags, self->pt_cancel));
! 453:
! 454: /* Disable cancellability. */
! 455: pthread_spinlock(self, &self->pt_lock);
! 456: self->pt_flags |= PT_FLAG_CS_DISABLED;
! 457: self->pt_cancel = 0;
! 458: pthread_spinunlock(self, &self->pt_lock);
! 459:
! 460: /* Call any cancellation cleanup handlers */
! 461: while (!PTQ_EMPTY(&self->pt_cleanup_stack)) {
! 462: cleanup = PTQ_FIRST(&self->pt_cleanup_stack);
! 463: PTQ_REMOVE(&self->pt_cleanup_stack, cleanup, ptc_next);
! 464: (*cleanup->ptc_cleanup)(cleanup->ptc_arg);
! 465: }
! 466:
! 467: /* Perform cleanup of thread-specific data */
! 468: pthread__destroy_tsd(self);
! 469:
! 470: self->pt_exitval = retval;
! 471:
! 472: pthread_spinlock(self, &self->pt_lock);
! 473: if (self->pt_flags & PT_FLAG_DETACHED) {
! 474: self->pt_state = PT_STATE_DEAD;
! 475: name = self->pt_name;
! 476: self->pt_name = NULL;
! 477: pthread_spinlock(self, &pthread__queue_lock);
! 478: PTQ_REMOVE(&pthread__allqueue, self, pt_allq);
! 479: PTQ_INSERT_TAIL(&pthread__deadqueue, self, pt_allq);
! 480: pthread_spinunlock(self, &pthread__queue_lock);
! 481: pthread_spinunlock(self, &self->pt_lock);
! 482: if (name != NULL)
! 483: free(name);
! 484: _lwp_exit();
! 485: } else {
! 486: self->pt_state = PT_STATE_ZOMBIE;
! 487: pthread_spinunlock(self, &self->pt_lock);
! 488: /* Note: name will be freed by the joiner. */
! 489: _lwp_exit();
! 490: }
! 491:
! 492: /*NOTREACHED*/
! 493: pthread__abort();
! 494: exit(1);
! 495: }
! 496:
! 497:
! 498: int
! 499: pthread_join(pthread_t thread, void **valptr)
! 500: {
! 501: pthread_t self;
! 502: char *name;
! 503: int num, retval;
! 504:
! 505: self = pthread__self();
! 506: SDPRINTF(("(pthread_join %p) Joining %p.\n", self, thread));
! 507:
! 508: if (pthread__find(self, thread) != 0)
! 509: return ESRCH;
! 510:
! 511: if (thread->pt_magic != PT_MAGIC)
! 512: return EINVAL;
! 513:
! 514: if (thread == self)
! 515: return EDEADLK;
! 516:
! 517: retval = 0;
! 518: name = NULL;
! 519: again:
! 520: pthread_spinlock(self, &thread->pt_lock);
! 521: switch (thread->pt_state) {
! 522: case PT_STATE_RUNNING:
! 523: pthread_spinunlock(self, &thread->pt_lock);
! 524:
! 525: /*
! 526: * IEEE Std 1003.1, 2004 Edition:
! 527: *
! 528: * "The pthread_join() function shall not
! 529: * return an error code of [EINTR]."
! 530: */
! 531: if (_lwp_wait(thread->pt_lid, &num) != 0 && errno != EINTR)
! 532: return errno;
! 533: goto again;
! 534: case PT_STATE_ZOMBIE:
! 535: if (valptr != NULL)
! 536: *valptr = thread->pt_exitval;
! 537: if (retval == 0) {
! 538: name = thread->pt_name;
! 539: thread->pt_name = NULL;
! 540: }
! 541: thread->pt_state = PT_STATE_DEAD;
! 542: pthread_spinlock(self, &pthread__queue_lock);
! 543: PTQ_REMOVE(&pthread__allqueue, thread, pt_allq);
! 544: PTQ_INSERT_HEAD(&pthread__deadqueue, thread, pt_allq);
! 545: pthread_spinunlock(self, &pthread__queue_lock);
! 546: pthread_spinunlock(self, &thread->pt_lock);
! 547: SDPRINTF(("(pthread_join %p) Joined %p.\n", self, thread));
! 548: if (name != NULL)
! 549: free(name);
! 550: (void)_lwp_detach(thread->pt_lid);
! 551: return retval;
! 552: default:
! 553: pthread_spinunlock(self, &thread->pt_lock);
! 554: return EINVAL;
! 555: }
! 556:
! 557: }
! 558:
! 559:
! 560: int
! 561: pthread_equal(pthread_t t1, pthread_t t2)
! 562: {
! 563:
! 564: /* Nothing special here. */
! 565: return (t1 == t2);
! 566: }
! 567:
! 568:
! 569: int
! 570: pthread_detach(pthread_t thread)
! 571: {
! 572: pthread_t self;
! 573:
! 574: self = pthread__self();
! 575:
! 576: if (pthread__find(self, thread) != 0)
! 577: return ESRCH;
! 578:
! 579: if (thread->pt_magic != PT_MAGIC)
! 580: return EINVAL;
! 581:
! 582: pthread_spinlock(self, &self->pt_lock);
! 583: thread->pt_flags |= PT_FLAG_DETACHED;
! 584: pthread_spinunlock(self, &self->pt_lock);
! 585:
! 586: return _lwp_detach(thread->pt_lid);
! 587: }
! 588:
! 589:
! 590: int
! 591: pthread_getname_np(pthread_t thread, char *name, size_t len)
! 592: {
! 593: pthread_t self;
! 594:
! 595: self = pthread__self();
! 596:
! 597: if (pthread__find(self, thread) != 0)
! 598: return ESRCH;
! 599:
! 600: if (thread->pt_magic != PT_MAGIC)
! 601: return EINVAL;
! 602:
! 603: pthread_spinlock(self, &thread->pt_lock);
! 604: if (thread->pt_name == NULL)
! 605: name[0] = '\0';
! 606: else
! 607: strlcpy(name, thread->pt_name, len);
! 608: pthread_spinunlock(self, &thread->pt_lock);
! 609:
! 610: return 0;
! 611: }
! 612:
! 613:
! 614: int
! 615: pthread_setname_np(pthread_t thread, const char *name, void *arg)
! 616: {
! 617: pthread_t self;
! 618: char *oldname, *cp, newname[PTHREAD_MAX_NAMELEN_NP];
! 619: int namelen;
! 620:
! 621: self = pthread__self();
! 622: if (pthread__find(self, thread) != 0)
! 623: return ESRCH;
! 624:
! 625: if (thread->pt_magic != PT_MAGIC)
! 626: return EINVAL;
! 627:
! 628: namelen = snprintf(newname, sizeof(newname), name, arg);
! 629: if (namelen >= PTHREAD_MAX_NAMELEN_NP)
! 630: return EINVAL;
! 631:
! 632: cp = strdup(newname);
! 633: if (cp == NULL)
! 634: return ENOMEM;
! 635:
! 636: pthread_spinlock(self, &thread->pt_lock);
! 637: oldname = thread->pt_name;
! 638: thread->pt_name = cp;
! 639: pthread_spinunlock(self, &thread->pt_lock);
! 640:
! 641: if (oldname != NULL)
! 642: free(oldname);
! 643:
! 644: return 0;
! 645: }
! 646:
! 647:
! 648:
! 649: /*
! 650: * XXX There should be a way for applications to use the efficent
! 651: * inline version, but there are opacity/namespace issues.
! 652: */
! 653: pthread_t
! 654: pthread_self(void)
! 655: {
! 656:
! 657: return pthread__self();
! 658: }
! 659:
! 660:
! 661: int
! 662: pthread_cancel(pthread_t thread)
! 663: {
! 664: pthread_t self;
! 665:
! 666: self = pthread__self();
! 667: if (pthread__find(self, thread) != 0)
! 668: return ESRCH;
! 669: pthread_spinlock(self, &thread->pt_lock);
! 670: thread->pt_flags |= PT_FLAG_CS_PENDING;
! 671: if ((thread->pt_flags & PT_FLAG_CS_DISABLED) == 0) {
! 672: thread->pt_cancel = 1;
! 673: pthread_spinunlock(self, &thread->pt_lock);
! 674: _lwp_wakeup(thread->pt_lid);
! 675: } else
! 676: pthread_spinunlock(self, &thread->pt_lock);
! 677:
! 678: return 0;
! 679: }
! 680:
! 681:
! 682: int
! 683: pthread_setcancelstate(int state, int *oldstate)
! 684: {
! 685: pthread_t self;
! 686: int retval;
! 687:
! 688: self = pthread__self();
! 689: retval = 0;
! 690:
! 691: pthread_spinlock(self, &self->pt_lock);
! 692:
! 693: if (oldstate != NULL) {
! 694: if (self->pt_flags & PT_FLAG_CS_DISABLED)
! 695: *oldstate = PTHREAD_CANCEL_DISABLE;
! 696: else
! 697: *oldstate = PTHREAD_CANCEL_ENABLE;
! 698: }
! 699:
! 700: if (state == PTHREAD_CANCEL_DISABLE) {
! 701: self->pt_flags |= PT_FLAG_CS_DISABLED;
! 702: if (self->pt_cancel) {
! 703: self->pt_flags |= PT_FLAG_CS_PENDING;
! 704: self->pt_cancel = 0;
! 705: }
! 706: } else if (state == PTHREAD_CANCEL_ENABLE) {
! 707: self->pt_flags &= ~PT_FLAG_CS_DISABLED;
! 708: /*
! 709: * If a cancellation was requested while cancellation
! 710: * was disabled, note that fact for future
! 711: * cancellation tests.
! 712: */
! 713: if (self->pt_flags & PT_FLAG_CS_PENDING) {
! 714: self->pt_cancel = 1;
! 715: /* This is not a deferred cancellation point. */
! 716: if (self->pt_flags & PT_FLAG_CS_ASYNC) {
! 717: pthread_spinunlock(self, &self->pt_lock);
! 718: pthread_exit(PTHREAD_CANCELED);
! 719: }
! 720: }
! 721: } else
! 722: retval = EINVAL;
! 723:
! 724: pthread_spinunlock(self, &self->pt_lock);
! 725:
! 726: return retval;
! 727: }
! 728:
! 729:
! 730: int
! 731: pthread_setcanceltype(int type, int *oldtype)
! 732: {
! 733: pthread_t self;
! 734: int retval;
! 735:
! 736: self = pthread__self();
! 737: retval = 0;
! 738:
! 739: pthread_spinlock(self, &self->pt_lock);
! 740:
! 741: if (oldtype != NULL) {
! 742: if (self->pt_flags & PT_FLAG_CS_ASYNC)
! 743: *oldtype = PTHREAD_CANCEL_ASYNCHRONOUS;
! 744: else
! 745: *oldtype = PTHREAD_CANCEL_DEFERRED;
! 746: }
! 747:
! 748: if (type == PTHREAD_CANCEL_ASYNCHRONOUS) {
! 749: self->pt_flags |= PT_FLAG_CS_ASYNC;
! 750: if (self->pt_cancel) {
! 751: pthread_spinunlock(self, &self->pt_lock);
! 752: pthread_exit(PTHREAD_CANCELED);
! 753: }
! 754: } else if (type == PTHREAD_CANCEL_DEFERRED)
! 755: self->pt_flags &= ~PT_FLAG_CS_ASYNC;
! 756: else
! 757: retval = EINVAL;
! 758:
! 759: pthread_spinunlock(self, &self->pt_lock);
! 760:
! 761: return retval;
! 762: }
! 763:
! 764:
! 765: void
! 766: pthread_testcancel()
! 767: {
! 768: pthread_t self;
! 769:
! 770: self = pthread__self();
! 771: if (self->pt_cancel)
! 772: pthread_exit(PTHREAD_CANCELED);
! 773: }
! 774:
! 775:
! 776: /*
! 777: * POSIX requires that certain functions return an error rather than
! 778: * invoking undefined behavior even when handed completely bogus
! 779: * pthread_t values, e.g. stack garbage or (pthread_t)666. This
! 780: * utility routine searches the list of threads for the pthread_t
! 781: * value without dereferencing it.
! 782: */
! 783: int
! 784: pthread__find(pthread_t self, pthread_t id)
! 785: {
! 786: pthread_t target;
! 787:
! 788: pthread_spinlock(self, &pthread__queue_lock);
! 789: PTQ_FOREACH(target, &pthread__allqueue, pt_allq)
! 790: if (target == id)
! 791: break;
! 792: pthread_spinunlock(self, &pthread__queue_lock);
! 793:
! 794: if (target == NULL)
! 795: return ESRCH;
! 796:
! 797: return 0;
! 798: }
! 799:
! 800:
! 801: void
! 802: pthread__testcancel(pthread_t self)
! 803: {
! 804:
! 805: if (self->pt_cancel)
! 806: pthread_exit(PTHREAD_CANCELED);
! 807: }
! 808:
! 809:
! 810: void
! 811: pthread__cleanup_push(void (*cleanup)(void *), void *arg, void *store)
! 812: {
! 813: pthread_t self;
! 814: struct pt_clean_t *entry;
! 815:
! 816: self = pthread__self();
! 817: entry = store;
! 818: entry->ptc_cleanup = cleanup;
! 819: entry->ptc_arg = arg;
! 820: PTQ_INSERT_HEAD(&self->pt_cleanup_stack, entry, ptc_next);
! 821: }
! 822:
! 823:
! 824: void
! 825: pthread__cleanup_pop(int ex, void *store)
! 826: {
! 827: pthread_t self;
! 828: struct pt_clean_t *entry;
! 829:
! 830: self = pthread__self();
! 831: entry = store;
! 832:
! 833: PTQ_REMOVE(&self->pt_cleanup_stack, entry, ptc_next);
! 834: if (ex)
! 835: (*entry->ptc_cleanup)(entry->ptc_arg);
! 836: }
! 837:
! 838:
! 839: int *
! 840: pthread__errno(void)
! 841: {
! 842: pthread_t self;
! 843:
! 844: self = pthread__self();
! 845:
! 846: return &(self->pt_errno);
! 847: }
! 848:
! 849: ssize_t _sys_write(int, const void *, size_t);
! 850:
! 851: void
! 852: pthread__assertfunc(const char *file, int line, const char *function,
! 853: const char *expr)
! 854: {
! 855: char buf[1024];
! 856: int len;
! 857:
! 858: SDPRINTF(("(af)\n"));
! 859:
! 860: /*
! 861: * snprintf should not acquire any locks, or we could
! 862: * end up deadlocked if the assert caller held locks.
! 863: */
! 864: len = snprintf(buf, 1024,
! 865: "assertion \"%s\" failed: file \"%s\", line %d%s%s%s\n",
! 866: expr, file, line,
! 867: function ? ", function \"" : "",
! 868: function ? function : "",
! 869: function ? "\"" : "");
! 870:
! 871: _sys_write(STDERR_FILENO, buf, (size_t)len);
! 872: (void)kill(getpid(), SIGABRT);
! 873:
! 874: _exit(1);
! 875: }
! 876:
! 877:
! 878: void
! 879: pthread__errorfunc(const char *file, int line, const char *function,
! 880: const char *msg)
! 881: {
! 882: char buf[1024];
! 883: size_t len;
! 884:
! 885: if (pthread__diagassert == 0)
! 886: return;
! 887:
! 888: /*
! 889: * snprintf should not acquire any locks, or we could
! 890: * end up deadlocked if the assert caller held locks.
! 891: */
! 892: len = snprintf(buf, 1024,
! 893: "%s: Error detected by libpthread: %s.\n"
! 894: "Detected by file \"%s\", line %d%s%s%s.\n"
! 895: "See pthread(3) for information.\n",
! 896: getprogname(), msg, file, line,
! 897: function ? ", function \"" : "",
! 898: function ? function : "",
! 899: function ? "\"" : "");
! 900:
! 901: if (pthread__diagassert & DIAGASSERT_STDERR)
! 902: _sys_write(STDERR_FILENO, buf, len);
! 903:
! 904: if (pthread__diagassert & DIAGASSERT_SYSLOG)
! 905: syslog(LOG_DEBUG | LOG_USER, "%s", buf);
! 906:
! 907: if (pthread__diagassert & DIAGASSERT_ABORT) {
! 908: (void)kill(getpid(), SIGABRT);
! 909: _exit(1);
! 910: }
! 911: }
! 912:
! 913: /*
! 914: * Thread park/unpark operations. The kernel operations are
! 915: * modelled after a brief description from "Multithreading in
! 916: * the Solaris Operating Environment":
! 917: *
! 918: * http://www.sun.com/software/whitepapers/solaris9/multithread.pdf
! 919: */
! 920:
! 921: #define OOPS(msg) \
! 922: pthread__errorfunc(__FILE__, __LINE__, __func__, msg)
! 923:
! 924: int
! 925: pthread__park(pthread_t self, pthread_spin_t *lock,
! 926: pthread_queue_t *queue, const struct timespec *abstime,
! 927: int cancelpt, const void *hint)
! 928: {
! 929: int rv;
! 930:
! 931: SDPRINTF(("(pthread__park %p) queue %p enter\n", self, queue));
! 932:
! 933: /*
! 934: * Wait until we are awoken by a pending unpark operation,
! 935: * a signal, an unpark posted after we have gone asleep,
! 936: * or an expired timeout.
! 937: *
! 938: * It is fine to test the value of both pt_sleepobj and
! 939: * pt_sleeponq without holding any locks, because:
! 940: *
! 941: * o Only the blocking thread (this thread) ever sets them
! 942: * to a non-NULL value.
! 943: *
! 944: * o Other threads may set them NULL, but if they do so they
! 945: * must also make this thread return from _lwp_park.
! 946: *
! 947: * o _lwp_park, _lwp_unpark and _lwp_unpark_all are system
! 948: * calls and all make use of spinlocks in the kernel. So
! 949: * these system calls act as full memory barriers, and will
! 950: * ensure that the calling CPU's store buffers are drained.
! 951: * In combination with the spinlock release before unpark,
! 952: * this means that modification of pt_sleepobj/onq by another
! 953: * thread will become globally visible before that thread
! 954: * schedules an unpark operation on this thread.
! 955: */
! 956: rv = 0;
! 957: while (self->pt_sleepobj != NULL && rv == 0) {
! 958: if (_lwp_park(abstime, NULL, hint) != 0) {
! 959: switch (rv = errno) {
! 960: case EINTR:
! 961: case EALREADY:
! 962: rv = 0;
! 963: break;
! 964: case ETIMEDOUT:
! 965: break;
! 966: default:
! 967: OOPS("_lwp_park failed");
! 968: SDPRINTF(("(pthread__park %p) syscall rv=%d\n",
! 969: self, rv));
! 970: break;
! 971: }
! 972: }
! 973: /* Check for cancellation. */
! 974: if (cancelpt && self->pt_cancel) {
! 975: /*
! 976: * Ensure visibility of the correct value.
! 977: * _lwp_park/_lwp_wakeup also provide a
! 978: * barrier.
! 979: */
! 980: pthread_spinlock(self, &self->pt_lock);
! 981: if (self->pt_cancel)
! 982: rv = EINTR;
! 983: pthread_spinunlock(self, &self->pt_lock);
! 984: }
! 985: }
! 986:
! 987: /*
! 988: * If we have been awoken early but are still on the queue,
! 989: * then remove ourself. Again, it's safe to do the test
! 990: * without holding any locks.
! 991: */
! 992: if (self->pt_sleeponq) {
! 993: pthread_spinlock(self, lock);
! 994: if (self->pt_sleeponq) {
! 995: PTQ_REMOVE(queue, self, pt_sleep);
! 996: self->pt_sleepobj = NULL;
! 997: self->pt_sleeponq = 0;
! 998: }
! 999: pthread_spinunlock(self, lock);
! 1000: }
! 1001:
! 1002: SDPRINTF(("(pthread__park %p) queue %p exit\n", self, queue));
! 1003:
! 1004: return rv;
! 1005: }
! 1006:
! 1007: void
! 1008: pthread__unpark(pthread_t self, pthread_spin_t *lock,
! 1009: pthread_queue_t *queue, pthread_t target)
! 1010: {
! 1011: int rv;
! 1012:
! 1013: if (target == NULL) {
! 1014: pthread_spinunlock(self, lock);
! 1015: return;
! 1016: }
! 1017:
! 1018: SDPRINTF(("(pthread__unpark %p) queue %p target %p\n",
! 1019: self, queue, target));
! 1020:
! 1021: /*
! 1022: * Easy: the thread has already been removed from
! 1023: * the queue, so just awaken it.
! 1024: */
! 1025: target->pt_sleepobj = NULL;
! 1026: target->pt_sleeponq = 0;
! 1027:
! 1028: /*
! 1029: * Releasing the spinlock serves as a store barrier,
! 1030: * which ensures that all our modifications are visible
! 1031: * to the thread in pthread__park() before the unpark
! 1032: * operation is set in motion.
! 1033: */
! 1034: pthread_spinunlock(self, lock);
! 1035: rv = _lwp_unpark(target->pt_lid, queue);
! 1036:
! 1037: if (rv != 0 && errno != EALREADY && errno != EINTR) {
! 1038: SDPRINTF(("(pthread__unpark %p) syscall rv=%d\n",
! 1039: self, rv));
! 1040: OOPS("_lwp_unpark failed");
! 1041: }
! 1042: }
! 1043:
! 1044: void
! 1045: pthread__unpark_all(pthread_t self, pthread_spin_t *lock,
! 1046: pthread_queue_t *queue)
! 1047: {
! 1048: lwpid_t waiters[PTHREAD__UNPARK_MAX];
! 1049: ssize_t n, rv;
! 1050: pthread_t thread, next;
! 1051:
! 1052: if (PTQ_EMPTY(queue)) {
! 1053: pthread_spinunlock(self, lock);
! 1054: return;
! 1055: }
! 1056:
! 1057: /*
! 1058: * First, clear all sleepobj pointers, since we can release the
! 1059: * spin lock before awkening everybody, and must synchronise with
! 1060: * pthread__park().
! 1061: */
! 1062: PTQ_FOREACH(thread, queue, pt_sleep) {
! 1063: thread->pt_sleepobj = NULL;
! 1064: if (thread == PTQ_NEXT(thread, pt_sleep))
! 1065: OOPS("unpark: thread linked to self");
! 1066: }
! 1067:
! 1068: for (;;) {
! 1069: thread = PTQ_FIRST(queue);
! 1070: for (n = 0; n < pthread__unpark_max && thread != NULL;
! 1071: thread = next) {
! 1072: /*
! 1073: * If the sleepobj pointer is non-NULL, it
! 1074: * means one of two things:
! 1075: *
! 1076: * o The thread has awoken early, spun
! 1077: * through application code and is
! 1078: * once more asleep on this object.
! 1079: *
! 1080: * o This is a new thread that has blocked
! 1081: * on the object after we have released
! 1082: * the interlock in this loop.
! 1083: *
! 1084: * In both cases we shouldn't remove the
! 1085: * thread from the queue.
! 1086: */
! 1087: next = PTQ_NEXT(thread, pt_sleep);
! 1088: if (thread->pt_sleepobj != NULL)
! 1089: continue;
! 1090: thread->pt_sleeponq = 0;
! 1091: waiters[n++] = thread->pt_lid;
! 1092: PTQ_REMOVE(queue, thread, pt_sleep);
! 1093: SDPRINTF(("(pthread__unpark_all %p) queue %p "
! 1094: "unpark %p\n", self, queue, thread));
! 1095: }
! 1096:
! 1097: /*
! 1098: * Releasing the spinlock serves as a store barrier,
! 1099: * which ensures that all our modifications are visible
! 1100: * to the thread in pthread__park() before the unpark
! 1101: * operation is set in motion.
! 1102: */
! 1103: pthread_spinunlock(self, lock);
! 1104: switch (n) {
! 1105: case 0:
! 1106: return;
! 1107: case 1:
! 1108: rv = (ssize_t)_lwp_unpark(waiters[0], queue);
! 1109: if (rv != 0 && errno != EALREADY && errno != EINTR) {
! 1110: OOPS("_lwp_unpark failed");
! 1111: SDPRINTF(("(pthread__unpark_all %p) "
! 1112: "syscall rv=%d\n", self, rv));
! 1113: }
! 1114: return;
! 1115: default:
! 1116: rv = _lwp_unpark_all(waiters, (size_t)n, queue);
! 1117: if (rv != 0 && errno != EINTR) {
! 1118: OOPS("_lwp_unpark_all failed");
! 1119: SDPRINTF(("(pthread__unpark_all %p) "
! 1120: "syscall rv=%d\n", self, rv));
! 1121: }
! 1122: break;
! 1123: }
! 1124: pthread_spinlock(self, lock);
! 1125: }
! 1126: }
! 1127:
! 1128: #undef OOPS
CVSweb <webmaster@jp.NetBSD.org>