ptthread.c (46387B)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 /* 7 ** File: ptthread.c 8 ** Descritpion: Implemenation for threds using pthreds 9 ** Exports: ptthread.h 10 */ 11 12 #if defined(_PR_PTHREADS) 13 14 # include "prlog.h" 15 # include "primpl.h" 16 # include "prpdce.h" 17 18 # include <pthread.h> 19 # include <unistd.h> 20 # include <string.h> 21 # include <signal.h> 22 # include <dlfcn.h> 23 24 # if defined(OPENBSD) || defined(FREEBSD) || defined(DRAGONFLY) 25 # include <pthread_np.h> 26 # endif 27 28 # if defined(ANDROID) 29 # include <sys/prctl.h> 30 # endif 31 32 # ifdef _PR_NICE_PRIORITY_SCHEDULING 33 # undef _POSIX_THREAD_PRIORITY_SCHEDULING 34 # include <sys/resource.h> 35 # ifndef HAVE_GETTID 36 # define gettid() (syscall(SYS_gettid)) 37 # endif 38 # endif 39 40 /* 41 * Record whether or not we have the privilege to set the scheduling 42 * policy and priority of threads. 0 means that privilege is available. 43 * EPERM means that privilege is not available. 44 */ 45 46 static PRIntn pt_schedpriv = 0; 47 extern PRLock* _pr_sleeplock; 48 49 static struct _PT_Bookeeping { 50 PRLock* ml; /* a lock to protect ourselves */ 51 PRCondVar* cv; /* used to signal global things */ 52 PRInt32 system, user; /* a count of the two different types */ 53 PRUintn this_many; /* number of threads allowed for exit */ 54 pthread_key_t key; /* thread private data key */ 55 PRBool keyCreated; /* whether 'key' should be deleted */ 56 PRThread *first, *last; /* list of threads we know about */ 57 # if _POSIX_THREAD_PRIORITY_SCHEDULING > 0 58 PRInt32 minPrio, maxPrio; /* range of scheduling priorities */ 59 # endif 60 } pt_book = {0}; 61 62 static void _pt_thread_death(void* arg); 63 static void _pt_thread_death_internal(void* arg, PRBool callDestructors); 64 static void init_pthread_gc_support(void); 65 66 # if _POSIX_THREAD_PRIORITY_SCHEDULING > 0 67 static PRIntn pt_PriorityMap(PRThreadPriority pri) { 68 # ifdef NTO 69 /* This priority algorithm causes lots of problems on Neutrino 70 * for now I have just hard coded everything to run at priority 10 71 * until I can come up with a new algorithm. 72 * Jerry.Kirk@Nexwarecorp.com 73 */ 74 return 10; 75 # else 76 return pt_book.minPrio + 77 pri * (pt_book.maxPrio - pt_book.minPrio) / PR_PRIORITY_LAST; 78 # endif 79 } 80 # elif defined(_PR_NICE_PRIORITY_SCHEDULING) 81 /* 82 * This functions maps higher priorities to lower nice values relative to the 83 * nice value specified in the |nice| parameter. The corresponding relative 84 * adjustments are: 85 * 86 * PR_PRIORITY_LOW +1 87 * PR_PRIORITY_NORMAL 0 88 * PR_PRIORITY_HIGH -1 89 * PR_PRIORITY_URGENT -2 90 */ 91 static int pt_RelativePriority(int nice, PRThreadPriority pri) { 92 return nice + (1 - pri); 93 } 94 # endif 95 96 /* 97 ** Initialize a stack for a native pthread thread 98 */ 99 static void _PR_InitializeStack(PRThreadStack* ts) { 100 if (ts && (ts->stackTop == 0)) { 101 ts->allocBase = (char*)&ts; 102 ts->allocSize = ts->stackSize; 103 104 /* 105 ** Setup stackTop and stackBottom values. 106 */ 107 # ifdef HAVE_STACK_GROWING_UP 108 ts->stackBottom = ts->allocBase + ts->stackSize; 109 ts->stackTop = ts->allocBase; 110 # else 111 ts->stackTop = ts->allocBase; 112 ts->stackBottom = ts->allocBase - ts->stackSize; 113 # endif 114 } 115 } 116 117 static void* _pt_root(void* arg) { 118 PRIntn rv; 119 PRThread* thred = (PRThread*)arg; 120 PRBool detached = (thred->state & PT_THREAD_DETACHED) ? PR_TRUE : PR_FALSE; 121 pthread_t id = pthread_self(); 122 # ifdef _PR_NICE_PRIORITY_SCHEDULING 123 pid_t tid; 124 # endif 125 126 # ifdef _PR_NICE_PRIORITY_SCHEDULING 127 /* 128 * We need to know the kernel thread ID of each thread in order to 129 * set its nice value hence we do it here instead of at creation time. 130 */ 131 tid = gettid(); 132 errno = 0; 133 rv = getpriority(PRIO_PROCESS, 0); 134 135 /* If we cannot read the main thread's nice value don't try to change the 136 * new thread's nice value. */ 137 if (errno == 0) { 138 setpriority(PRIO_PROCESS, tid, pt_RelativePriority(rv, thred->priority)); 139 } 140 # endif 141 142 /* Set up the thread stack information */ 143 _PR_InitializeStack(thred->stack); 144 145 /* 146 * Set within the current thread the pointer to our object. 147 * This object will be deleted when the thread termintates, 148 * whether in a join or detached (see _PR_InitThreads()). 149 */ 150 rv = pthread_setspecific(pt_book.key, thred); 151 PR_ASSERT(0 == rv); 152 153 /* make the thread visible to the rest of the runtime */ 154 PR_Lock(pt_book.ml); 155 /* 156 * Both the parent thread and this new thread set thred->id. 157 * The new thread must ensure that thred->id is set before 158 * it executes its startFunc. The parent thread must ensure 159 * that thred->id is set before PR_CreateThread() returns. 160 * Both threads set thred->id while holding pt_book.ml and 161 * use thred->idSet to ensure thred->id is written only once. 162 */ 163 if (!thred->idSet) { 164 thred->id = id; 165 thred->idSet = PR_TRUE; 166 } else { 167 PR_ASSERT(pthread_equal(thred->id, id)); 168 } 169 170 # ifdef _PR_NICE_PRIORITY_SCHEDULING 171 thred->tid = tid; 172 PR_NotifyAllCondVar(pt_book.cv); 173 # endif 174 175 /* If this is a GCABLE thread, set its state appropriately */ 176 if (thred->suspend & PT_THREAD_SETGCABLE) { 177 thred->state |= PT_THREAD_GCABLE; 178 } 179 thred->suspend = 0; 180 181 thred->prev = pt_book.last; 182 if (pt_book.last) { 183 pt_book.last->next = thred; 184 } else { 185 pt_book.first = thred; 186 } 187 thred->next = NULL; 188 pt_book.last = thred; 189 PR_Unlock(pt_book.ml); 190 191 thred->startFunc(thred->arg); /* make visible to the client */ 192 193 /* unhook the thread from the runtime */ 194 PR_Lock(pt_book.ml); 195 /* 196 * At this moment, PR_CreateThread() may not have set thred->id yet. 197 * It is safe for a detached thread to free thred only after 198 * PR_CreateThread() has accessed thred->id and thred->idSet. 199 */ 200 if (detached) { 201 while (!thred->okToDelete) { 202 PR_WaitCondVar(pt_book.cv, PR_INTERVAL_NO_TIMEOUT); 203 } 204 } 205 206 if (thred->state & PT_THREAD_SYSTEM) { 207 pt_book.system -= 1; 208 } else if (--pt_book.user == pt_book.this_many) { 209 PR_NotifyAllCondVar(pt_book.cv); 210 } 211 if (NULL == thred->prev) { 212 pt_book.first = thred->next; 213 } else { 214 thred->prev->next = thred->next; 215 } 216 if (NULL == thred->next) { 217 pt_book.last = thred->prev; 218 } else { 219 thred->next->prev = thred->prev; 220 } 221 PR_Unlock(pt_book.ml); 222 223 /* 224 * Here we set the pthread's backpointer to the PRThread to NULL. 225 * Otherwise the destructor would get called eagerly as the thread 226 * returns to the pthread runtime. The joining thread would them be 227 * the proud possessor of a dangling reference. However, this is the 228 * last chance to delete the object if the thread is detached, so 229 * just let the destructor do the work. 230 */ 231 if (PR_FALSE == detached) { 232 /* Call TPD destructors on this thread. */ 233 _PR_DestroyThreadPrivate(thred); 234 rv = pthread_setspecific(pt_book.key, NULL); 235 PR_ASSERT(0 == rv); 236 } 237 238 return NULL; 239 } /* _pt_root */ 240 241 static PRThread* pt_AttachThread(void) { 242 PRThread* thred = NULL; 243 244 /* 245 * NSPR must have been initialized when PR_AttachThread is called. 246 * We cannot have PR_AttachThread call implicit initialization 247 * because if multiple threads call PR_AttachThread simultaneously, 248 * NSPR may be initialized more than once. 249 * We can't call any function that calls PR_GetCurrentThread() 250 * either (e.g., PR_SetError()) as that will result in infinite 251 * recursion. 252 */ 253 if (!_pr_initialized) { 254 return NULL; 255 } 256 257 /* PR_NEWZAP must not call PR_GetCurrentThread() */ 258 thred = PR_NEWZAP(PRThread); 259 if (NULL != thred) { 260 int rv; 261 262 thred->priority = PR_PRIORITY_NORMAL; 263 thred->id = pthread_self(); 264 thred->idSet = PR_TRUE; 265 # ifdef _PR_NICE_PRIORITY_SCHEDULING 266 thred->tid = gettid(); 267 # endif 268 rv = pthread_setspecific(pt_book.key, thred); 269 PR_ASSERT(0 == rv); 270 271 thred->state = PT_THREAD_GLOBAL | PT_THREAD_FOREIGN; 272 PR_Lock(pt_book.ml); 273 274 /* then put it into the list */ 275 thred->prev = pt_book.last; 276 if (pt_book.last) { 277 pt_book.last->next = thred; 278 } else { 279 pt_book.first = thred; 280 } 281 thred->next = NULL; 282 pt_book.last = thred; 283 PR_Unlock(pt_book.ml); 284 } 285 return thred; /* may be NULL */ 286 } /* pt_AttachThread */ 287 288 static PRThread* _PR_CreateThread(PRThreadType type, void (*start)(void* arg), 289 void* arg, PRThreadPriority priority, 290 PRThreadScope scope, PRThreadState state, 291 PRUint32 stackSize, PRBool isGCAble) { 292 int rv; 293 PRThread* thred; 294 pthread_attr_t tattr; 295 296 if (!_pr_initialized) { 297 _PR_ImplicitInitialization(); 298 } 299 300 if ((PRIntn)PR_PRIORITY_FIRST > (PRIntn)priority) { 301 priority = PR_PRIORITY_FIRST; 302 } else if ((PRIntn)PR_PRIORITY_LAST < (PRIntn)priority) { 303 priority = PR_PRIORITY_LAST; 304 } 305 306 rv = _PT_PTHREAD_ATTR_INIT(&tattr); 307 PR_ASSERT(0 == rv); 308 309 if (EPERM != pt_schedpriv) { 310 # if _POSIX_THREAD_PRIORITY_SCHEDULING > 0 311 struct sched_param schedule; 312 # endif 313 314 # if _POSIX_THREAD_PRIORITY_SCHEDULING > 0 315 rv = pthread_attr_setinheritsched(&tattr, PTHREAD_EXPLICIT_SCHED); 316 PR_ASSERT(0 == rv); 317 # endif 318 319 /* Use the default scheduling policy */ 320 321 # if _POSIX_THREAD_PRIORITY_SCHEDULING > 0 322 rv = pthread_attr_getschedparam(&tattr, &schedule); 323 PR_ASSERT(0 == rv); 324 schedule.sched_priority = pt_PriorityMap(priority); 325 rv = pthread_attr_setschedparam(&tattr, &schedule); 326 PR_ASSERT(0 == rv); 327 # ifdef NTO 328 rv = pthread_attr_setschedpolicy(&tattr, SCHED_RR); /* Round Robin */ 329 PR_ASSERT(0 == rv); 330 # endif 331 # endif /* _POSIX_THREAD_PRIORITY_SCHEDULING > 0 */ 332 } 333 334 rv = pthread_attr_setdetachstate( 335 &tattr, ((PR_JOINABLE_THREAD == state) ? PTHREAD_CREATE_JOINABLE 336 : PTHREAD_CREATE_DETACHED)); 337 PR_ASSERT(0 == rv); 338 339 /* 340 * If stackSize is 0, we use the default pthread stack size. 341 */ 342 if (stackSize) { 343 # ifdef _MD_MINIMUM_STACK_SIZE 344 if (stackSize < _MD_MINIMUM_STACK_SIZE) { 345 stackSize = _MD_MINIMUM_STACK_SIZE; 346 } 347 # endif 348 rv = pthread_attr_setstacksize(&tattr, stackSize); 349 PR_ASSERT(0 == rv); 350 } 351 352 thred = PR_NEWZAP(PRThread); 353 if (NULL == thred) { 354 PR_SetError(PR_OUT_OF_MEMORY_ERROR, errno); 355 goto done; 356 } else { 357 pthread_t id; 358 359 thred->arg = arg; 360 thred->startFunc = start; 361 thred->priority = priority; 362 if (PR_UNJOINABLE_THREAD == state) { 363 thred->state |= PT_THREAD_DETACHED; 364 } 365 366 if (PR_LOCAL_THREAD == scope) { 367 scope = PR_GLOBAL_THREAD; 368 } 369 370 if (PR_GLOBAL_BOUND_THREAD == scope) { 371 # if _POSIX_THREAD_PRIORITY_SCHEDULING > 0 372 rv = pthread_attr_setscope(&tattr, PTHREAD_SCOPE_SYSTEM); 373 if (rv) { 374 /* 375 * system scope not supported 376 */ 377 scope = PR_GLOBAL_THREAD; 378 /* 379 * reset scope 380 */ 381 rv = pthread_attr_setscope(&tattr, PTHREAD_SCOPE_PROCESS); 382 PR_ASSERT(0 == rv); 383 } 384 # endif 385 } 386 if (PR_GLOBAL_THREAD == scope) { 387 thred->state |= PT_THREAD_GLOBAL; 388 } else if (PR_GLOBAL_BOUND_THREAD == scope) { 389 thred->state |= (PT_THREAD_GLOBAL | PT_THREAD_BOUND); 390 } else { /* force it global */ 391 thred->state |= PT_THREAD_GLOBAL; 392 } 393 if (PR_SYSTEM_THREAD == type) { 394 thred->state |= PT_THREAD_SYSTEM; 395 } 396 397 thred->suspend = (isGCAble) ? PT_THREAD_SETGCABLE : 0; 398 399 thred->stack = PR_NEWZAP(PRThreadStack); 400 if (thred->stack == NULL) { 401 PRIntn oserr = errno; 402 PR_Free(thred); /* all that work ... poof! */ 403 PR_SetError(PR_OUT_OF_MEMORY_ERROR, oserr); 404 thred = NULL; /* and for what? */ 405 goto done; 406 } 407 thred->stack->stackSize = stackSize; 408 thred->stack->thr = thred; 409 410 # ifdef PT_NO_SIGTIMEDWAIT 411 pthread_mutex_init(&thred->suspendResumeMutex, NULL); 412 pthread_cond_init(&thred->suspendResumeCV, NULL); 413 # endif 414 415 /* make the thread counted to the rest of the runtime */ 416 PR_Lock(pt_book.ml); 417 if (PR_SYSTEM_THREAD == type) { 418 pt_book.system += 1; 419 } else { 420 pt_book.user += 1; 421 } 422 PR_Unlock(pt_book.ml); 423 424 /* 425 * We pass a pointer to a local copy (instead of thred->id) 426 * to pthread_create() because who knows what wacky things 427 * pthread_create() may be doing to its argument. 428 */ 429 rv = _PT_PTHREAD_CREATE(&id, tattr, _pt_root, thred); 430 431 if (EPERM == rv) { 432 /* Remember that we don't have thread scheduling privilege. */ 433 pt_schedpriv = EPERM; 434 PR_LOG(_pr_thread_lm, PR_LOG_MIN, 435 ("_PR_CreateThread: no thread scheduling privilege")); 436 /* Try creating the thread again without setting priority. */ 437 # if _POSIX_THREAD_PRIORITY_SCHEDULING > 0 438 rv = pthread_attr_setinheritsched(&tattr, PTHREAD_INHERIT_SCHED); 439 PR_ASSERT(0 == rv); 440 # endif 441 rv = _PT_PTHREAD_CREATE(&id, tattr, _pt_root, thred); 442 } 443 444 if (0 != rv) { 445 PRIntn oserr = rv; 446 PR_Lock(pt_book.ml); 447 if (thred->state & PT_THREAD_SYSTEM) { 448 pt_book.system -= 1; 449 } else if (--pt_book.user == pt_book.this_many) { 450 PR_NotifyAllCondVar(pt_book.cv); 451 } 452 PR_Unlock(pt_book.ml); 453 454 PR_Free(thred->stack); 455 PR_Free(thred); /* all that work ... poof! */ 456 PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, oserr); 457 thred = NULL; /* and for what? */ 458 goto done; 459 } 460 461 PR_Lock(pt_book.ml); 462 /* 463 * Both the parent thread and this new thread set thred->id. 464 * The parent thread must ensure that thred->id is set before 465 * PR_CreateThread() returns. (See comments in _pt_root().) 466 */ 467 if (!thred->idSet) { 468 thred->id = id; 469 thred->idSet = PR_TRUE; 470 } else { 471 PR_ASSERT(pthread_equal(thred->id, id)); 472 } 473 474 /* 475 * If the new thread is detached, tell it that PR_CreateThread() has 476 * accessed thred->id and thred->idSet so it's ok to delete thred. 477 */ 478 if (PR_UNJOINABLE_THREAD == state) { 479 thred->okToDelete = PR_TRUE; 480 PR_NotifyAllCondVar(pt_book.cv); 481 } 482 PR_Unlock(pt_book.ml); 483 } 484 485 done: 486 rv = _PT_PTHREAD_ATTR_DESTROY(&tattr); 487 PR_ASSERT(0 == rv); 488 489 return thred; 490 } /* _PR_CreateThread */ 491 492 PR_IMPLEMENT(PRThread*) 493 PR_CreateThread(PRThreadType type, void (*start)(void* arg), void* arg, 494 PRThreadPriority priority, PRThreadScope scope, 495 PRThreadState state, PRUint32 stackSize) { 496 return _PR_CreateThread(type, start, arg, priority, scope, state, stackSize, 497 PR_FALSE); 498 } /* PR_CreateThread */ 499 500 PR_IMPLEMENT(PRThread*) 501 PR_CreateThreadGCAble(PRThreadType type, void (*start)(void* arg), void* arg, 502 PRThreadPriority priority, PRThreadScope scope, 503 PRThreadState state, PRUint32 stackSize) { 504 return _PR_CreateThread(type, start, arg, priority, scope, state, stackSize, 505 PR_TRUE); 506 } /* PR_CreateThreadGCAble */ 507 508 PR_IMPLEMENT(void*) GetExecutionEnvironment(PRThread* thred) { 509 return thred->environment; 510 } /* GetExecutionEnvironment */ 511 512 PR_IMPLEMENT(void) SetExecutionEnvironment(PRThread* thred, void* env) { 513 thred->environment = env; 514 } /* SetExecutionEnvironment */ 515 516 PR_IMPLEMENT(PRThread*) 517 PR_AttachThread(PRThreadType type, PRThreadPriority priority, 518 PRThreadStack* stack) { 519 return PR_GetCurrentThread(); 520 } /* PR_AttachThread */ 521 522 PR_IMPLEMENT(PRStatus) PR_JoinThread(PRThread* thred) { 523 int rv = -1; 524 void* result = NULL; 525 PR_ASSERT(thred != NULL); 526 527 if ((0xafafafaf == thred->state) || 528 (PT_THREAD_DETACHED == (PT_THREAD_DETACHED & thred->state)) || 529 (PT_THREAD_FOREIGN == (PT_THREAD_FOREIGN & thred->state))) { 530 /* 531 * This might be a bad address, but if it isn't, the state should 532 * either be an unjoinable thread or it's already had the object 533 * deleted. However, the client that called join on a detached 534 * thread deserves all the rath I can muster.... 535 */ 536 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); 537 PR_LogPrint("PR_JoinThread: %p not joinable | already smashed\n", thred); 538 } else { 539 pthread_t id = thred->id; 540 rv = pthread_join(id, &result); 541 PR_ASSERT(rv == 0 && result == NULL); 542 if (0 == rv) { 543 /* 544 * PR_FALSE, because the thread already called the TPD 545 * destructors before exiting _pt_root. 546 */ 547 _pt_thread_death_internal(thred, PR_FALSE); 548 } else { 549 PRErrorCode prerror; 550 switch (rv) { 551 case EINVAL: /* not a joinable thread */ 552 case ESRCH: /* no thread with given ID */ 553 prerror = PR_INVALID_ARGUMENT_ERROR; 554 break; 555 case EDEADLK: /* a thread joining with itself */ 556 prerror = PR_DEADLOCK_ERROR; 557 break; 558 default: 559 prerror = PR_UNKNOWN_ERROR; 560 break; 561 } 562 PR_SetError(prerror, rv); 563 } 564 } 565 return (0 == rv) ? PR_SUCCESS : PR_FAILURE; 566 } /* PR_JoinThread */ 567 568 PR_IMPLEMENT(void) PR_DetachThread(void) { 569 void* thred; 570 int rv; 571 572 _PT_PTHREAD_GETSPECIFIC(pt_book.key, thred); 573 if (NULL == thred) { 574 return; 575 } 576 _pt_thread_death(thred); 577 rv = pthread_setspecific(pt_book.key, NULL); 578 PR_ASSERT(0 == rv); 579 } /* PR_DetachThread */ 580 581 PR_IMPLEMENT(PRThread*) PR_GetCurrentThread(void) { 582 void* thred; 583 584 if (!_pr_initialized) { 585 _PR_ImplicitInitialization(); 586 } 587 588 _PT_PTHREAD_GETSPECIFIC(pt_book.key, thred); 589 if (NULL == thred) { 590 thred = pt_AttachThread(); 591 } 592 PR_ASSERT(NULL != thred); 593 return (PRThread*)thred; 594 } /* PR_GetCurrentThread */ 595 596 PR_IMPLEMENT(PRThreadScope) PR_GetThreadScope(const PRThread* thred) { 597 return (thred->state & PT_THREAD_BOUND) ? PR_GLOBAL_BOUND_THREAD 598 : PR_GLOBAL_THREAD; 599 } /* PR_GetThreadScope() */ 600 601 PR_IMPLEMENT(PRThreadType) PR_GetThreadType(const PRThread* thred) { 602 return (thred->state & PT_THREAD_SYSTEM) ? PR_SYSTEM_THREAD : PR_USER_THREAD; 603 } 604 605 PR_IMPLEMENT(PRThreadState) PR_GetThreadState(const PRThread* thred) { 606 return (thred->state & PT_THREAD_DETACHED) ? PR_UNJOINABLE_THREAD 607 : PR_JOINABLE_THREAD; 608 } /* PR_GetThreadState */ 609 610 PR_IMPLEMENT(PRThreadPriority) PR_GetThreadPriority(const PRThread* thred) { 611 PR_ASSERT(thred != NULL); 612 return thred->priority; 613 } /* PR_GetThreadPriority */ 614 615 PR_IMPLEMENT(void) 616 PR_SetThreadPriority(PRThread* thred, PRThreadPriority newPri) { 617 PRIntn rv; 618 619 PR_ASSERT(NULL != thred); 620 621 if ((PRIntn)PR_PRIORITY_FIRST > (PRIntn)newPri) { 622 newPri = PR_PRIORITY_FIRST; 623 } else if ((PRIntn)PR_PRIORITY_LAST < (PRIntn)newPri) { 624 newPri = PR_PRIORITY_LAST; 625 } 626 627 # if _POSIX_THREAD_PRIORITY_SCHEDULING > 0 628 if (EPERM != pt_schedpriv) { 629 int policy; 630 struct sched_param schedule; 631 632 rv = pthread_getschedparam(thred->id, &policy, &schedule); 633 if (0 == rv) { 634 schedule.sched_priority = pt_PriorityMap(newPri); 635 rv = pthread_setschedparam(thred->id, policy, &schedule); 636 if (EPERM == rv) { 637 pt_schedpriv = EPERM; 638 PR_LOG(_pr_thread_lm, PR_LOG_MIN, 639 ("PR_SetThreadPriority: no thread scheduling privilege")); 640 } 641 } 642 if (rv != 0) { 643 rv = -1; 644 } 645 } 646 # elif defined(_PR_NICE_PRIORITY_SCHEDULING) 647 PR_Lock(pt_book.ml); 648 while (thred->tid == 0) { 649 PR_WaitCondVar(pt_book.cv, PR_INTERVAL_NO_TIMEOUT); 650 } 651 PR_Unlock(pt_book.ml); 652 653 errno = 0; 654 rv = getpriority(PRIO_PROCESS, 0); 655 656 /* Do not proceed unless we know the main thread's nice value. */ 657 if (errno == 0) { 658 rv = setpriority(PRIO_PROCESS, thred->tid, pt_RelativePriority(rv, newPri)); 659 660 if (rv == -1) { 661 /* We don't set pt_schedpriv to EPERM in case errno == EPERM 662 * because adjusting the nice value might be permitted for certain 663 * ranges but not for others. */ 664 PR_LOG(_pr_thread_lm, PR_LOG_MIN, 665 ("PR_SetThreadPriority: setpriority failed with error %d", errno)); 666 } 667 } 668 # else 669 (void)rv; /* rv is unused */ 670 # endif 671 672 thred->priority = newPri; 673 } /* PR_SetThreadPriority */ 674 675 PR_IMPLEMENT(PRStatus) PR_Interrupt(PRThread* thred) { 676 /* 677 ** If the target thread indicates that it's waiting, 678 ** find the condition and broadcast to it. Broadcast 679 ** since we don't know which thread (if there are more 680 ** than one). This sounds risky, but clients must 681 ** test their invariants when resumed from a wait and 682 ** I don't expect very many threads to be waiting on 683 ** a single condition and I don't expect interrupt to 684 ** be used very often. 685 ** 686 ** I don't know why I thought this would work. Must have 687 ** been one of those weaker momements after I'd been 688 ** smelling the vapors. 689 ** 690 ** Even with the followng changes it is possible that 691 ** the pointer to the condition variable is pointing 692 ** at a bogus value. Will the unerlying code detect 693 ** that? 694 */ 695 PRCondVar* cv; 696 PR_ASSERT(NULL != thred); 697 if (NULL == thred) { 698 return PR_FAILURE; 699 } 700 701 thred->state |= PT_THREAD_ABORTED; 702 703 cv = thred->waiting; 704 if ((NULL != cv) && !thred->interrupt_blocked) { 705 PRIntn rv; 706 (void)PR_ATOMIC_INCREMENT(&cv->notify_pending); 707 rv = pthread_cond_broadcast(&cv->cv); 708 PR_ASSERT(0 == rv); 709 if (0 > PR_ATOMIC_DECREMENT(&cv->notify_pending)) { 710 PR_DestroyCondVar(cv); 711 } 712 } 713 return PR_SUCCESS; 714 } /* PR_Interrupt */ 715 716 PR_IMPLEMENT(void) PR_ClearInterrupt(void) { 717 PRThread* me = PR_GetCurrentThread(); 718 me->state &= ~PT_THREAD_ABORTED; 719 } /* PR_ClearInterrupt */ 720 721 PR_IMPLEMENT(void) PR_BlockInterrupt(void) { 722 PRThread* me = PR_GetCurrentThread(); 723 _PT_THREAD_BLOCK_INTERRUPT(me); 724 } /* PR_BlockInterrupt */ 725 726 PR_IMPLEMENT(void) PR_UnblockInterrupt(void) { 727 PRThread* me = PR_GetCurrentThread(); 728 _PT_THREAD_UNBLOCK_INTERRUPT(me); 729 } /* PR_UnblockInterrupt */ 730 731 PR_IMPLEMENT(PRStatus) PR_Yield(void) { 732 static PRBool warning = PR_TRUE; 733 if (warning) 734 warning = _PR_Obsolete("PR_Yield()", "PR_Sleep(PR_INTERVAL_NO_WAIT)"); 735 return PR_Sleep(PR_INTERVAL_NO_WAIT); 736 } 737 738 PR_IMPLEMENT(PRStatus) PR_Sleep(PRIntervalTime ticks) { 739 PRStatus rv = PR_SUCCESS; 740 741 if (!_pr_initialized) { 742 _PR_ImplicitInitialization(); 743 } 744 745 if (PR_INTERVAL_NO_WAIT == ticks) { 746 _PT_PTHREAD_YIELD(); 747 } else { 748 PRCondVar* cv; 749 PRIntervalTime timein; 750 751 timein = PR_IntervalNow(); 752 cv = PR_NewCondVar(_pr_sleeplock); 753 PR_ASSERT(cv != NULL); 754 PR_Lock(_pr_sleeplock); 755 do { 756 PRIntervalTime now = PR_IntervalNow(); 757 PRIntervalTime delta = now - timein; 758 if (delta > ticks) { 759 break; 760 } 761 rv = PR_WaitCondVar(cv, ticks - delta); 762 } while (PR_SUCCESS == rv); 763 PR_Unlock(_pr_sleeplock); 764 PR_DestroyCondVar(cv); 765 } 766 return rv; 767 } /* PR_Sleep */ 768 769 static void _pt_thread_death(void* arg) { 770 void* thred; 771 int rv; 772 773 _PT_PTHREAD_GETSPECIFIC(pt_book.key, thred); 774 if (NULL == thred) { 775 /* 776 * Have PR_GetCurrentThread return the expected value to the 777 * destructors. 778 */ 779 rv = pthread_setspecific(pt_book.key, arg); 780 PR_ASSERT(0 == rv); 781 } 782 783 /* PR_TRUE for: call destructors */ 784 _pt_thread_death_internal(arg, PR_TRUE); 785 786 if (NULL == thred) { 787 rv = pthread_setspecific(pt_book.key, NULL); 788 PR_ASSERT(0 == rv); 789 } 790 } 791 792 static void _pt_thread_death_internal(void* arg, PRBool callDestructors) { 793 PRThread* thred = (PRThread*)arg; 794 795 if (thred->state & (PT_THREAD_FOREIGN | PT_THREAD_PRIMORD)) { 796 PR_Lock(pt_book.ml); 797 if (NULL == thred->prev) { 798 pt_book.first = thred->next; 799 } else { 800 thred->prev->next = thred->next; 801 } 802 if (NULL == thred->next) { 803 pt_book.last = thred->prev; 804 } else { 805 thred->next->prev = thred->prev; 806 } 807 PR_Unlock(pt_book.ml); 808 } 809 if (callDestructors) { 810 _PR_DestroyThreadPrivate(thred); 811 } 812 PR_Free(thred->privateData); 813 if (NULL != thred->errorString) { 814 PR_Free(thred->errorString); 815 } 816 if (NULL != thred->name) { 817 PR_Free(thred->name); 818 } 819 PR_Free(thred->stack); 820 if (NULL != thred->syspoll_list) { 821 PR_Free(thred->syspoll_list); 822 } 823 # if defined(DEBUG) 824 memset(thred, 0xaf, sizeof(PRThread)); 825 # endif /* defined(DEBUG) */ 826 PR_Free(thred); 827 } /* _pt_thread_death */ 828 829 void _PR_InitThreads(PRThreadType type, PRThreadPriority priority, 830 PRUintn maxPTDs) { 831 int rv; 832 PRThread* thred; 833 834 PR_ASSERT(priority == PR_PRIORITY_NORMAL); 835 836 # ifdef _PR_NEED_PTHREAD_INIT 837 /* 838 * On BSD/OS (3.1 and 4.0), the pthread subsystem is lazily 839 * initialized, but pthread_self() fails to initialize 840 * pthreads and hence returns a null thread ID if invoked 841 * by the primordial thread before any other pthread call. 842 * So we explicitly initialize pthreads here. 843 */ 844 pthread_init(); 845 # endif 846 847 # if _POSIX_THREAD_PRIORITY_SCHEDULING > 0 848 # if defined(FREEBSD) 849 { 850 pthread_attr_t attr; 851 int policy; 852 /* get the min and max priorities of the default policy */ 853 pthread_attr_init(&attr); 854 pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); 855 pthread_attr_getschedpolicy(&attr, &policy); 856 pt_book.minPrio = sched_get_priority_min(policy); 857 PR_ASSERT(-1 != pt_book.minPrio); 858 pt_book.maxPrio = sched_get_priority_max(policy); 859 PR_ASSERT(-1 != pt_book.maxPrio); 860 pthread_attr_destroy(&attr); 861 } 862 # else 863 /* 864 ** These might be function evaluations 865 */ 866 pt_book.minPrio = PT_PRIO_MIN; 867 pt_book.maxPrio = PT_PRIO_MAX; 868 # endif 869 # endif 870 871 PR_ASSERT(NULL == pt_book.ml); 872 pt_book.ml = PR_NewLock(); 873 PR_ASSERT(NULL != pt_book.ml); 874 pt_book.cv = PR_NewCondVar(pt_book.ml); 875 PR_ASSERT(NULL != pt_book.cv); 876 thred = PR_NEWZAP(PRThread); 877 PR_ASSERT(NULL != thred); 878 thred->arg = NULL; 879 thred->startFunc = NULL; 880 thred->priority = priority; 881 thred->id = pthread_self(); 882 thred->idSet = PR_TRUE; 883 # ifdef _PR_NICE_PRIORITY_SCHEDULING 884 thred->tid = gettid(); 885 # endif 886 887 thred->state = (PT_THREAD_DETACHED | PT_THREAD_PRIMORD); 888 if (PR_SYSTEM_THREAD == type) { 889 thred->state |= PT_THREAD_SYSTEM; 890 pt_book.system += 1; 891 pt_book.this_many = 0; 892 } else { 893 pt_book.user += 1; 894 pt_book.this_many = 1; 895 } 896 thred->next = thred->prev = NULL; 897 pt_book.first = pt_book.last = thred; 898 899 thred->stack = PR_NEWZAP(PRThreadStack); 900 PR_ASSERT(thred->stack != NULL); 901 thred->stack->stackSize = 0; 902 thred->stack->thr = thred; 903 _PR_InitializeStack(thred->stack); 904 905 /* 906 * Create a key for our use to store a backpointer in the pthread 907 * to our PRThread object. This object gets deleted when the thread 908 * returns from its root in the case of a detached thread. Other 909 * threads delete the objects in Join. 910 * 911 * NB: The destructor logic seems to have a bug so it isn't used. 912 * NBB: Oh really? I'm going to give it a spin - AOF 19 June 1998. 913 * More info - the problem is that pthreads calls the destructor 914 * eagerly as the thread returns from its root, rather than lazily 915 * after the thread is joined. Therefore, threads that are joining 916 * and holding PRThread references are actually holding pointers to 917 * nothing. 918 */ 919 rv = _PT_PTHREAD_KEY_CREATE(&pt_book.key, _pt_thread_death); 920 if (0 != rv) { 921 PR_Assert("0 == rv", __FILE__, __LINE__); 922 } 923 pt_book.keyCreated = PR_TRUE; 924 rv = pthread_setspecific(pt_book.key, thred); 925 PR_ASSERT(0 == rv); 926 } /* _PR_InitThreads */ 927 928 # ifdef __GNUC__ 929 /* 930 * GCC supports the constructor and destructor attributes as of 931 * version 2.5. 932 */ 933 # if defined(DARWIN) 934 /* 935 * The dynamic linker on OSX doesn't execute __attribute__((destructor)) 936 * destructors in the right order wrt non-__attribute((destructor)) destructors 937 * in other libraries. So use atexit() instead, which does. 938 * See https://bugzilla.mozilla.org/show_bug.cgi?id=1399746#c99 939 */ 940 static void _PR_Fini(void); 941 942 __attribute__((constructor)) static void _register_PR_Fini() { 943 atexit(_PR_Fini); 944 } 945 # else 946 static void _PR_Fini(void) __attribute__((destructor)); 947 # endif 948 949 # elif defined(__SUNPRO_C) 950 /* 951 * Sun Studio compiler 952 */ 953 # pragma fini(_PR_Fini) 954 static void _PR_Fini(void); 955 # elif defined(AIX) 956 /* Need to use the -binitfini::_PR_Fini linker option. */ 957 # endif 958 959 void _PR_Fini(void) { 960 void* thred; 961 int rv; 962 963 if (!_pr_initialized) { 964 /* Either NSPR was never successfully initialized or 965 * PR_Cleanup has been called already. */ 966 if (pt_book.keyCreated) { 967 rv = pthread_key_delete(pt_book.key); 968 PR_ASSERT(0 == rv); 969 pt_book.keyCreated = PR_FALSE; 970 } 971 return; 972 } 973 974 _PT_PTHREAD_GETSPECIFIC(pt_book.key, thred); 975 if (NULL != thred) { 976 /* 977 * PR_FALSE, because it is unsafe to call back to the 978 * thread private data destructors at final cleanup. 979 */ 980 _pt_thread_death_internal(thred, PR_FALSE); 981 rv = pthread_setspecific(pt_book.key, NULL); 982 PR_ASSERT(0 == rv); 983 } 984 rv = pthread_key_delete(pt_book.key); 985 PR_ASSERT(0 == rv); 986 pt_book.keyCreated = PR_FALSE; 987 /* TODO: free other resources used by NSPR */ 988 /* _pr_initialized = PR_FALSE; */ 989 } /* _PR_Fini */ 990 991 PR_IMPLEMENT(PRStatus) PR_Cleanup(void) { 992 PRThread* me = PR_GetCurrentThread(); 993 int rv; 994 PR_LOG(_pr_thread_lm, PR_LOG_MIN, ("PR_Cleanup: shutting down NSPR")); 995 PR_ASSERT(me->state & PT_THREAD_PRIMORD); 996 if (me->state & PT_THREAD_PRIMORD) { 997 PR_Lock(pt_book.ml); 998 while (pt_book.user > pt_book.this_many) { 999 PR_WaitCondVar(pt_book.cv, PR_INTERVAL_NO_TIMEOUT); 1000 } 1001 if (me->state & PT_THREAD_SYSTEM) { 1002 pt_book.system -= 1; 1003 } else { 1004 pt_book.user -= 1; 1005 } 1006 PR_Unlock(pt_book.ml); 1007 1008 _PR_MD_EARLY_CLEANUP(); 1009 1010 _PR_CleanupMW(); 1011 _PR_CleanupTime(); 1012 _PR_CleanupDtoa(); 1013 _PR_CleanupCallOnce(); 1014 _PR_ShutdownLinker(); 1015 _PR_LogCleanup(); 1016 _PR_CleanupNet(); 1017 /* Close all the fd's before calling _PR_CleanupIO */ 1018 _PR_CleanupIO(); 1019 _PR_CleanupCMon(); 1020 1021 _pt_thread_death(me); 1022 rv = pthread_setspecific(pt_book.key, NULL); 1023 PR_ASSERT(0 == rv); 1024 /* 1025 * I am not sure if it's safe to delete the cv and lock here, 1026 * since there may still be "system" threads around. If this 1027 * call isn't immediately prior to exiting, then there's a 1028 * problem. 1029 */ 1030 if (0 == pt_book.system) { 1031 PR_DestroyCondVar(pt_book.cv); 1032 pt_book.cv = NULL; 1033 PR_DestroyLock(pt_book.ml); 1034 pt_book.ml = NULL; 1035 } 1036 PR_DestroyLock(_pr_sleeplock); 1037 _pr_sleeplock = NULL; 1038 _PR_CleanupLayerCache(); 1039 _PR_CleanupEnv(); 1040 # ifdef _PR_ZONE_ALLOCATOR 1041 _PR_DestroyZones(); 1042 # endif 1043 _pr_initialized = PR_FALSE; 1044 return PR_SUCCESS; 1045 } 1046 return PR_FAILURE; 1047 } /* PR_Cleanup */ 1048 1049 PR_IMPLEMENT(void) PR_ProcessExit(PRIntn status) { _exit(status); } 1050 1051 PR_IMPLEMENT(PRUint32) PR_GetThreadID(PRThread* thred) { 1052 return (PRUint32)thred->id; /* and I don't know what they will do with it */ 1053 } 1054 1055 /* 1056 * $$$ 1057 * The following two thread-to-processor affinity functions are not 1058 * yet implemented for pthreads. By the way, these functions should return 1059 * PRStatus rather than PRInt32 to indicate the success/failure status. 1060 * $$$ 1061 */ 1062 1063 PR_IMPLEMENT(PRInt32) 1064 PR_GetThreadAffinityMask(PRThread* thread, PRUint32* mask) { 1065 return 0; /* not implemented */ 1066 } 1067 1068 PR_IMPLEMENT(PRInt32) 1069 PR_SetThreadAffinityMask(PRThread* thread, PRUint32 mask) { 1070 return 0; /* not implemented */ 1071 } 1072 1073 PR_IMPLEMENT(void) 1074 PR_SetThreadDumpProc(PRThread* thread, PRThreadDumpProc dump, void* arg) { 1075 thread->dump = dump; 1076 thread->dumpArg = arg; 1077 } 1078 1079 /* 1080 * Garbage collection support follows. 1081 */ 1082 1083 /* a bogus signal mask for forcing a timed wait */ 1084 /* Not so bogus in AIX as we really do a sigwait */ 1085 static sigset_t sigwait_set; 1086 1087 static struct timespec onemillisec = {0, 1000000L}; 1088 # ifndef PT_NO_SIGTIMEDWAIT 1089 static struct timespec hundredmillisec = {0, 100000000L}; 1090 # endif 1091 1092 static void suspend_signal_handler(PRIntn sig); 1093 1094 # ifdef PT_NO_SIGTIMEDWAIT 1095 static void null_signal_handler(PRIntn sig); 1096 # endif 1097 1098 /* 1099 * Linux pthreads use SIGUSR1 and SIGUSR2 internally, which 1100 * conflict with the use of these two signals in our GC support. 1101 * So we don't know how to support GC on Linux pthreads. 1102 */ 1103 static void init_pthread_gc_support(void) { 1104 PRIntn rv; 1105 1106 { 1107 struct sigaction sigact_usr2; 1108 1109 sigact_usr2.sa_handler = suspend_signal_handler; 1110 sigact_usr2.sa_flags = SA_RESTART; 1111 sigemptyset(&sigact_usr2.sa_mask); 1112 1113 rv = sigaction(SIGUSR2, &sigact_usr2, NULL); 1114 PR_ASSERT(0 == rv); 1115 1116 sigemptyset(&sigwait_set); 1117 # if defined(PT_NO_SIGTIMEDWAIT) 1118 sigaddset(&sigwait_set, SIGUSR1); 1119 # else 1120 sigaddset(&sigwait_set, SIGUSR2); 1121 # endif /* defined(PT_NO_SIGTIMEDWAIT) */ 1122 } 1123 # if defined(PT_NO_SIGTIMEDWAIT) 1124 { 1125 struct sigaction sigact_null; 1126 sigact_null.sa_handler = null_signal_handler; 1127 sigact_null.sa_flags = SA_RESTART; 1128 sigemptyset(&sigact_null.sa_mask); 1129 rv = sigaction(SIGUSR1, &sigact_null, NULL); 1130 PR_ASSERT(0 == rv); 1131 } 1132 # endif /* defined(PT_NO_SIGTIMEDWAIT) */ 1133 } 1134 1135 PR_IMPLEMENT(void) PR_SetThreadGCAble(void) { 1136 PR_Lock(pt_book.ml); 1137 PR_GetCurrentThread()->state |= PT_THREAD_GCABLE; 1138 PR_Unlock(pt_book.ml); 1139 } 1140 1141 PR_IMPLEMENT(void) PR_ClearThreadGCAble(void) { 1142 PR_Lock(pt_book.ml); 1143 PR_GetCurrentThread()->state &= (~PT_THREAD_GCABLE); 1144 PR_Unlock(pt_book.ml); 1145 } 1146 1147 # if defined(DEBUG) 1148 static PRBool suspendAllOn = PR_FALSE; 1149 # endif 1150 1151 static PRBool suspendAllSuspended = PR_FALSE; 1152 1153 PR_IMPLEMENT(PRStatus) PR_EnumerateThreads(PREnumerator func, void* arg) { 1154 PRIntn count = 0; 1155 PRStatus rv = PR_SUCCESS; 1156 PRThread* thred = pt_book.first; 1157 1158 # if defined(DEBUG) || defined(FORCE_PR_ASSERT) 1159 PRThread* me = PR_GetCurrentThread(); 1160 # endif 1161 1162 PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_EnumerateThreads\n")); 1163 /* 1164 * $$$ 1165 * Need to suspend all threads other than me before doing this. 1166 * This is really a gross and disgusting thing to do. The only 1167 * good thing is that since all other threads are suspended, holding 1168 * the lock during a callback seems like child's play. 1169 * $$$ 1170 */ 1171 PR_ASSERT(suspendAllOn); 1172 1173 while (thred != NULL) { 1174 /* Steve Morse, 4-23-97: Note that we can't walk a queue by taking 1175 * qp->next after applying the function "func". In particular, "func" 1176 * might remove the thread from the queue and put it into another one in 1177 * which case qp->next no longer points to the next entry in the original 1178 * queue. 1179 * 1180 * To get around this problem, we save qp->next in qp_next before applying 1181 * "func" and use that saved value as the next value after applying "func". 1182 */ 1183 PRThread* next = thred->next; 1184 1185 if (_PT_IS_GCABLE_THREAD(thred)) { 1186 PR_ASSERT((thred == me) || (thred->suspend & PT_THREAD_SUSPENDED)); 1187 PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 1188 ("In PR_EnumerateThreads callback thread %p thid = %X\n", thred, 1189 thred->id)); 1190 1191 rv = func(thred, count++, arg); 1192 if (rv != PR_SUCCESS) { 1193 return rv; 1194 } 1195 } 1196 thred = next; 1197 } 1198 PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 1199 ("End PR_EnumerateThreads count = %d \n", count)); 1200 return rv; 1201 } /* PR_EnumerateThreads */ 1202 1203 /* 1204 * PR_SuspendAll and PR_ResumeAll are called during garbage collection. The 1205 * strategy we use is to send a SIGUSR2 signal to every gc able thread that we 1206 * intend to suspend. The signal handler will record the stack pointer and will 1207 * block until resumed by the resume call. Since the signal handler is the last 1208 * routine called for the suspended thread, the stack pointer will also serve as 1209 * a place where all the registers have been saved on the stack for the 1210 * previously executing routines. 1211 * 1212 * Through global variables, we also make sure that PR_Suspend and PR_Resume 1213 * does not proceed until the thread is suspended or resumed. 1214 */ 1215 1216 /* 1217 * In the signal handler, we can not use condition variable notify or wait. 1218 * This does not work consistently across all pthread platforms. We also can 1219 * not use locking since that does not seem to work reliably across platforms. 1220 * Only thing we can do is yielding while testing for a global condition 1221 * to change. This does work on pthread supported platforms. We may have 1222 * to play with priortities if there are any problems detected. 1223 */ 1224 1225 /* 1226 * In AIX, you cannot use ANY pthread calls in the signal handler except perhaps 1227 * pthread_yield. But that is horribly inefficient. Hence we use only sigwait, 1228 * no sigtimedwait is available. We need to use another user signal, SIGUSR1. 1229 * Actually SIGUSR1 is also used by exec in Java. So our usage here breaks the 1230 * exec in Java, for AIX. You cannot use pthread_cond_wait or pthread_delay_np 1231 * in the signal handler as all synchronization mechanisms just break down. 1232 */ 1233 1234 # if defined(PT_NO_SIGTIMEDWAIT) 1235 static void null_signal_handler(PRIntn sig) { return; } 1236 # endif 1237 1238 static void suspend_signal_handler(PRIntn sig) { 1239 PRThread* me = PR_GetCurrentThread(); 1240 1241 PR_ASSERT(me != NULL); 1242 PR_ASSERT(_PT_IS_GCABLE_THREAD(me)); 1243 PR_ASSERT((me->suspend & PT_THREAD_SUSPENDED) == 0); 1244 1245 PR_LOG( 1246 _pr_gc_lm, PR_LOG_ALWAYS, 1247 ("Begin suspend_signal_handler thred %p thread id = %X\n", me, me->id)); 1248 1249 /* 1250 * save stack pointer 1251 */ 1252 me->sp = &me; 1253 1254 /* 1255 At this point, the thread's stack pointer has been saved, 1256 And it is going to enter a wait loop until it is resumed. 1257 So it is _really_ suspended 1258 */ 1259 1260 me->suspend |= PT_THREAD_SUSPENDED; 1261 1262 /* 1263 * now, block current thread 1264 */ 1265 # if defined(PT_NO_SIGTIMEDWAIT) 1266 pthread_cond_signal(&me->suspendResumeCV); 1267 while (me->suspend & PT_THREAD_SUSPENDED) { 1268 # if !defined(FREEBSD) && !defined(NETBSD) && !defined(OPENBSD) && \ 1269 !defined(DARWIN) && !defined(RISCOS) 1270 PRIntn rv; 1271 sigwait(&sigwait_set, &rv); 1272 # endif 1273 } 1274 me->suspend |= PT_THREAD_RESUMED; 1275 pthread_cond_signal(&me->suspendResumeCV); 1276 # else /* defined(PT_NO_SIGTIMEDWAIT) */ 1277 while (me->suspend & PT_THREAD_SUSPENDED) { 1278 PRIntn rv = sigtimedwait(&sigwait_set, NULL, &hundredmillisec); 1279 PR_ASSERT(-1 == rv); 1280 } 1281 me->suspend |= PT_THREAD_RESUMED; 1282 # endif 1283 1284 /* 1285 * At this point, thread has been resumed, so set a global condition. 1286 * The ResumeAll needs to know that this has really been resumed. 1287 * So the signal handler sets a flag which PR_ResumeAll will reset. 1288 * The PR_ResumeAll must reset this flag ... 1289 */ 1290 1291 PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 1292 ("End suspend_signal_handler thred = %p tid = %X\n", me, me->id)); 1293 } /* suspend_signal_handler */ 1294 1295 static void pt_SuspendSet(PRThread* thred) { 1296 PRIntn rv; 1297 1298 PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 1299 ("pt_SuspendSet thred %p thread id = %X\n", thred, thred->id)); 1300 1301 /* 1302 * Check the thread state and signal the thread to suspend 1303 */ 1304 1305 PR_ASSERT((thred->suspend & PT_THREAD_SUSPENDED) == 0); 1306 1307 PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 1308 ("doing pthread_kill in pt_SuspendSet thred %p tid = %X\n", thred, 1309 thred->id)); 1310 rv = pthread_kill(thred->id, SIGUSR2); 1311 PR_ASSERT(0 == rv); 1312 } 1313 1314 static void pt_SuspendTest(PRThread* thred) { 1315 PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 1316 ("Begin pt_SuspendTest thred %p thread id = %X\n", thred, thred->id)); 1317 1318 /* 1319 * Wait for the thread to be really suspended. This happens when the 1320 * suspend signal handler stores the stack pointer and sets the state 1321 * to suspended. 1322 */ 1323 1324 # if defined(PT_NO_SIGTIMEDWAIT) 1325 pthread_mutex_lock(&thred->suspendResumeMutex); 1326 while ((thred->suspend & PT_THREAD_SUSPENDED) == 0) { 1327 pthread_cond_timedwait(&thred->suspendResumeCV, &thred->suspendResumeMutex, 1328 &onemillisec); 1329 } 1330 pthread_mutex_unlock(&thred->suspendResumeMutex); 1331 # else 1332 while ((thred->suspend & PT_THREAD_SUSPENDED) == 0) { 1333 PRIntn rv = sigtimedwait(&sigwait_set, NULL, &onemillisec); 1334 PR_ASSERT(-1 == rv); 1335 } 1336 # endif 1337 1338 PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 1339 ("End pt_SuspendTest thred %p tid %X\n", thred, thred->id)); 1340 } /* pt_SuspendTest */ 1341 1342 static void pt_ResumeSet(PRThread* thred) { 1343 PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 1344 ("pt_ResumeSet thred %p thread id = %X\n", thred, thred->id)); 1345 1346 /* 1347 * Clear the global state and set the thread state so that it will 1348 * continue past yield loop in the suspend signal handler 1349 */ 1350 1351 PR_ASSERT(thred->suspend & PT_THREAD_SUSPENDED); 1352 1353 thred->suspend &= ~PT_THREAD_SUSPENDED; 1354 1355 # if defined(PT_NO_SIGTIMEDWAIT) 1356 pthread_kill(thred->id, SIGUSR1); 1357 # endif 1358 1359 } /* pt_ResumeSet */ 1360 1361 static void pt_ResumeTest(PRThread* thred) { 1362 PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 1363 ("Begin pt_ResumeTest thred %p thread id = %X\n", thred, thred->id)); 1364 1365 /* 1366 * Wait for the threads resume state to change 1367 * to indicate it is really resumed 1368 */ 1369 # if defined(PT_NO_SIGTIMEDWAIT) 1370 pthread_mutex_lock(&thred->suspendResumeMutex); 1371 while ((thred->suspend & PT_THREAD_RESUMED) == 0) { 1372 pthread_cond_timedwait(&thred->suspendResumeCV, &thred->suspendResumeMutex, 1373 &onemillisec); 1374 } 1375 pthread_mutex_unlock(&thred->suspendResumeMutex); 1376 # else 1377 while ((thred->suspend & PT_THREAD_RESUMED) == 0) { 1378 PRIntn rv = sigtimedwait(&sigwait_set, NULL, &onemillisec); 1379 PR_ASSERT(-1 == rv); 1380 } 1381 # endif 1382 1383 thred->suspend &= ~PT_THREAD_RESUMED; 1384 1385 PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 1386 ("End pt_ResumeTest thred %p tid %X\n", thred, thred->id)); 1387 } /* pt_ResumeTest */ 1388 1389 static pthread_once_t pt_gc_support_control = PTHREAD_ONCE_INIT; 1390 1391 PR_IMPLEMENT(void) PR_SuspendAll(void) { 1392 # ifdef DEBUG 1393 PRIntervalTime stime, etime; 1394 # endif 1395 PRThread* thred = pt_book.first; 1396 PRThread* me = PR_GetCurrentThread(); 1397 int rv; 1398 1399 rv = pthread_once(&pt_gc_support_control, init_pthread_gc_support); 1400 PR_ASSERT(0 == rv); 1401 PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_SuspendAll\n")); 1402 /* 1403 * Stop all threads which are marked GC able. 1404 */ 1405 PR_Lock(pt_book.ml); 1406 # ifdef DEBUG 1407 suspendAllOn = PR_TRUE; 1408 stime = PR_IntervalNow(); 1409 # endif 1410 while (thred != NULL) { 1411 if ((thred != me) && _PT_IS_GCABLE_THREAD(thred)) { 1412 pt_SuspendSet(thred); 1413 } 1414 thred = thred->next; 1415 } 1416 1417 /* Wait till they are really suspended */ 1418 thred = pt_book.first; 1419 while (thred != NULL) { 1420 if ((thred != me) && _PT_IS_GCABLE_THREAD(thred)) { 1421 pt_SuspendTest(thred); 1422 } 1423 thred = thred->next; 1424 } 1425 1426 suspendAllSuspended = PR_TRUE; 1427 1428 # ifdef DEBUG 1429 etime = PR_IntervalNow(); 1430 PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 1431 ("End PR_SuspendAll (time %dms)\n", 1432 PR_IntervalToMilliseconds(etime - stime))); 1433 # endif 1434 } /* PR_SuspendAll */ 1435 1436 PR_IMPLEMENT(void) PR_ResumeAll(void) { 1437 # ifdef DEBUG 1438 PRIntervalTime stime, etime; 1439 # endif 1440 PRThread* thred = pt_book.first; 1441 PRThread* me = PR_GetCurrentThread(); 1442 PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_ResumeAll\n")); 1443 /* 1444 * Resume all previously suspended GC able threads. 1445 */ 1446 suspendAllSuspended = PR_FALSE; 1447 # ifdef DEBUG 1448 stime = PR_IntervalNow(); 1449 # endif 1450 1451 while (thred != NULL) { 1452 if ((thred != me) && _PT_IS_GCABLE_THREAD(thred)) { 1453 pt_ResumeSet(thred); 1454 } 1455 thred = thred->next; 1456 } 1457 1458 thred = pt_book.first; 1459 while (thred != NULL) { 1460 if ((thred != me) && _PT_IS_GCABLE_THREAD(thred)) { 1461 pt_ResumeTest(thred); 1462 } 1463 thred = thred->next; 1464 } 1465 1466 PR_Unlock(pt_book.ml); 1467 # ifdef DEBUG 1468 suspendAllOn = PR_FALSE; 1469 etime = PR_IntervalNow(); 1470 PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 1471 ("End PR_ResumeAll (time %dms)\n", 1472 PR_IntervalToMilliseconds(etime - stime))); 1473 # endif 1474 } /* PR_ResumeAll */ 1475 1476 /* Return the stack pointer for the given thread- used by the GC */ 1477 PR_IMPLEMENT(void*) PR_GetSP(PRThread* thred) { 1478 PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 1479 ("in PR_GetSP thred %p thid = %X, sp = %p\n", thred, thred->id, 1480 thred->sp)); 1481 return thred->sp; 1482 } /* PR_GetSP */ 1483 1484 PR_IMPLEMENT(PRStatus) PR_SetCurrentThreadName(const char* name) { 1485 PRThread* thread; 1486 size_t nameLen; 1487 int result = 0; 1488 1489 if (!name) { 1490 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); 1491 return PR_FAILURE; 1492 } 1493 1494 thread = PR_GetCurrentThread(); 1495 if (!thread) { 1496 return PR_FAILURE; 1497 } 1498 1499 PR_Free(thread->name); 1500 nameLen = strlen(name); 1501 thread->name = (char*)PR_Malloc(nameLen + 1); 1502 if (!thread->name) { 1503 return PR_FAILURE; 1504 } 1505 memcpy(thread->name, name, nameLen + 1); 1506 1507 # if defined(OPENBSD) || defined(FREEBSD) || defined(DRAGONFLY) 1508 pthread_set_name_np(thread->id, name); 1509 # elif defined(ANDROID) 1510 prctl(PR_SET_NAME, (unsigned long)(name)); 1511 # elif defined(NETBSD) 1512 result = pthread_setname_np(thread->id, "%s", (void*)name); 1513 # else /* not BSD */ 1514 /* 1515 * On OSX, pthread_setname_np is only available in 10.6 or later, so test 1516 * for it at runtime. It also may not be available on all linux distros. 1517 */ 1518 # if defined(DARWIN) 1519 int (*dynamic_pthread_setname_np)(const char*); 1520 # else 1521 int (*dynamic_pthread_setname_np)(pthread_t, const char*); 1522 # endif 1523 1524 *(void**)(&dynamic_pthread_setname_np) = 1525 dlsym(RTLD_DEFAULT, "pthread_setname_np"); 1526 if (!dynamic_pthread_setname_np) { 1527 return PR_SUCCESS; 1528 } 1529 1530 # if defined(DARWIN) 1531 /* Mac OS X has a length limit of 63 characters, but there is no API 1532 * exposing it. 1533 */ 1534 # define SETNAME_LENGTH_CONSTRAINT 63 1535 # else 1536 /* 1537 * The 15-character name length limit is an experimentally determined 1538 * length of a null-terminated string that most linux distros accept 1539 * as an argument to pthread_setname_np. Otherwise the E2BIG 1540 * error is returned by the function. 1541 */ 1542 # define SETNAME_LENGTH_CONSTRAINT 15 1543 # endif 1544 # define SETNAME_FRAGMENT1_LENGTH (SETNAME_LENGTH_CONSTRAINT >> 1) 1545 # define SETNAME_FRAGMENT2_LENGTH \ 1546 (SETNAME_LENGTH_CONSTRAINT - SETNAME_FRAGMENT1_LENGTH - 1) 1547 char name_dup[SETNAME_LENGTH_CONSTRAINT + 1]; 1548 if (nameLen > SETNAME_LENGTH_CONSTRAINT) { 1549 memcpy(name_dup, name, SETNAME_FRAGMENT1_LENGTH); 1550 name_dup[SETNAME_FRAGMENT1_LENGTH] = '~'; 1551 /* Note that this also copies the null terminator. */ 1552 memcpy(name_dup + SETNAME_FRAGMENT1_LENGTH + 1, 1553 name + nameLen - SETNAME_FRAGMENT2_LENGTH, 1554 SETNAME_FRAGMENT2_LENGTH + 1); 1555 name = name_dup; 1556 } 1557 1558 # if defined(DARWIN) 1559 result = dynamic_pthread_setname_np(name); 1560 # else 1561 result = dynamic_pthread_setname_np(thread->id, name); 1562 # endif 1563 # endif /* not BSD */ 1564 1565 if (result) { 1566 PR_SetError(PR_UNKNOWN_ERROR, result); 1567 return PR_FAILURE; 1568 } 1569 return PR_SUCCESS; 1570 } 1571 1572 PR_IMPLEMENT(const char*) PR_GetThreadName(const PRThread* thread) { 1573 if (!thread) { 1574 return NULL; 1575 } 1576 return thread->name; 1577 } 1578 1579 #endif /* defined(_PR_PTHREADS) */ 1580 1581 /* ptthread.c */