LCOV - code coverage report
Current view: top level - nsprpub/pr/src/pthreads - ptthread.c (source / functions) Hit Total Coverage
Test: output.info Lines: 229 562 40.7 %
Date: 2017-07-14 16:53:18 Functions: 8 32 25.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13