LCOV - code coverage report
Current view: directory - nsprpub/pr/src/pthreads - ptthread.c (source / functions) Found Hit Coverage
Test: app.info Lines: 532 244 45.9 %
Date: 2012-06-02 Functions: 47 13 27.7 %

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

Generated by: LCOV version 1.7