tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 */