LCOV - app.info - nsprpub/pr/src/pthreads/ptthread.c

LCOV - code coverage report
| Current view: | directory - nsprpub/pr/src/pthreads - ptthread.c (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 532 | 167 | 31.4 %
| Date: | 2012-04-07 | Functions: | 47 | 10 | 21.3 %

           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           37428 : 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           74856 :     return pt_book.minPrio +
         100           37428 :             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           37428 : static void _PR_InitializeStack(PRThreadStack *ts)
         109                 : {
         110           37428 :     if( ts && (ts->stackTop == 0) ) {
         111           37428 :         ts->allocBase = (char *) &ts;
         112           37428 :         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           37428 :         ts->stackTop    = ts->allocBase;
         122           37428 :         ts->stackBottom = ts->allocBase - ts->stackSize;
         123                 : #endif
         124                 :     }
         125           37428 : }
         126                 :
         127           18761 : static void *_pt_root(void *arg)
         128                 : {
         129                 :     PRIntn rv;
         130           18761 :     PRThread *thred = (PRThread*)arg;
         131           18761 :     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           18761 :     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           18761 :     _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           18761 :     rv = pthread_setspecific(pt_book.key, thred);
         168           18761 :     PR_ASSERT(0 == rv);
         169                 :
         170                 :     /* make the thread visible to the rest of the runtime */
         171           18761 :     PR_Lock(pt_book.ml);
         172                 :
         173                 :     /* If this is a GCABLE thread, set its state appropriately */
         174           18761 :     if (thred->suspend & PT_THREAD_SETGCABLE)
         175               0 :             thred->state |= PT_THREAD_GCABLE;
         176           18761 :     thred->suspend = 0;
         177                 :
         178           18761 :     thred->prev = pt_book.last;
         179           18761 :     if (pt_book.last)
         180           18761 :         pt_book.last->next = thred;
         181                 :     else
         182               0 :         pt_book.first = thred;
         183           18761 :     thred->next = NULL;
         184           18761 :     pt_book.last = thred;
         185           18761 :     PR_Unlock(pt_book.ml);
         186                 :
         187           18761 :     thred->startFunc(thred->arg);  /* make visible to the client */
         188                 :
         189                 :     /* unhook the thread from the runtime */
         190           18761 :     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           18761 :     if (detached)
         197                 :     {
         198               0 :         while (!thred->okToDelete)
         199               0 :             PR_WaitCondVar(pt_book.cv, PR_INTERVAL_NO_TIMEOUT);
         200                 :     }
         201                 :
         202           18761 :     if (thred->state & PT_THREAD_SYSTEM)
         203               0 :         pt_book.system -= 1;
         204           18761 :     else if (--pt_book.user == pt_book.this_many)
         205           18761 :         PR_NotifyAllCondVar(pt_book.cv);
         206           18761 :     if (NULL == thred->prev)
         207               0 :         pt_book.first = thred->next;
         208                 :     else
         209           18761 :         thred->prev->next = thred->next;
         210           18761 :     if (NULL == thred->next)
         211           18761 :         pt_book.last = thred->prev;
         212                 :     else
         213               0 :         thred->next->prev = thred->prev;
         214           18761 :     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           18761 :     if (PR_FALSE == detached)
         225                 :     {
         226                 :         /* Call TPD destructors on this thread. */
         227           18761 :         _PR_DestroyThreadPrivate(thred);
         228           18761 :         rv = pthread_setspecific(pt_book.key, NULL);
         229           18761 :         PR_ASSERT(0 == rv);
         230                 :     }
         231                 :
         232           18761 :     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           18761 : 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           18761 :     if (!_pr_initialized) _PR_ImplicitInitialization();
         288                 :
         289           18761 :     if ((PRIntn)PR_PRIORITY_FIRST > (PRIntn)priority)
         290               0 :         priority = PR_PRIORITY_FIRST;
         291           18761 :     else if ((PRIntn)PR_PRIORITY_LAST < (PRIntn)priority)
         292               0 :         priority = PR_PRIORITY_LAST;
         293                 :
         294           18761 :     rv = _PT_PTHREAD_ATTR_INIT(&tattr);
         295           18761 :     PR_ASSERT(0 == rv);
         296                 :
         297           18761 :     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           18761 :         rv = pthread_attr_setinheritsched(&tattr, PTHREAD_EXPLICIT_SCHED);
         305           18761 :         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           18761 :         rv = pthread_attr_getschedparam(&tattr, &schedule);
         315           18761 :         PR_ASSERT(0 == rv);
         316           18761 :         schedule.sched_priority = pt_PriorityMap(priority);
         317           18761 :         rv = pthread_attr_setschedparam(&tattr, &schedule);
         318           18761 :         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           18761 :     rv = pthread_attr_setdetachstate(&tattr,
         332                 :         ((PR_JOINABLE_THREAD == state) ?
         333                 :             PTHREAD_CREATE_JOINABLE : PTHREAD_CREATE_DETACHED));
         334           18761 :     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           18761 :     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           18761 :     thred = PR_NEWZAP(PRThread);
         351           18761 :     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           18761 :         thred->arg = arg;
         361           18761 :         thred->startFunc = start;
         362           18761 :         thred->priority = priority;
         363           18761 :         if (PR_UNJOINABLE_THREAD == state)
         364               0 :             thred->state |= PT_THREAD_DETACHED;
         365                 :
         366           18761 :         if (PR_LOCAL_THREAD == scope)
         367           18761 :                 scope = PR_GLOBAL_THREAD;
         368                 :
         369           18761 :         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           18761 :         if (PR_GLOBAL_THREAD == scope)
         386           18761 :             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           18761 :         if (PR_SYSTEM_THREAD == type)
         392               0 :             thred->state |= PT_THREAD_SYSTEM;
         393                 :
         394           18761 :         thred->suspend =(isGCAble) ? PT_THREAD_SETGCABLE : 0;
         395                 :
         396           18761 :         thred->stack = PR_NEWZAP(PRThreadStack);
         397           18761 :         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           18761 :         thred->stack->stackSize = stackSize;
         405           18761 :         thred->stack->thr = thred;
         406                 :
         407                 : #ifdef PT_NO_SIGTIMEDWAIT
         408           18761 :         pthread_mutex_init(&thred->suspendResumeMutex,NULL);
         409           18761 :         pthread_cond_init(&thred->suspendResumeCV,NULL);
         410                 : #endif
         411                 :
         412                 :         /* make the thread counted to the rest of the runtime */
         413           18761 :         PR_Lock(pt_book.ml);
         414           18761 :         if (PR_SYSTEM_THREAD == type)
         415               0 :             pt_book.system += 1;
         416           18761 :         else pt_book.user += 1;
         417           18761 :         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           18761 :         rv = _PT_PTHREAD_CREATE(&id, tattr, _pt_root, thred);
         425                 :
         426                 : #if !defined(_PR_DCETHREADS)
         427           18761 :         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           18761 :         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           18761 :         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           18761 :         if (PR_UNJOINABLE_THREAD == state)
         487                 :         {
         488               0 :             PR_Lock(pt_book.ml);
         489               0 :             thred->okToDelete = PR_TRUE;
         490               0 :             PR_NotifyAllCondVar(pt_book.cv);
         491               0 :             PR_Unlock(pt_book.ml);
         492                 :         }
         493                 :     }
         494                 :
         495                 : done:
         496           18761 :     rv = _PT_PTHREAD_ATTR_DESTROY(&tattr);
         497           18761 :     PR_ASSERT(0 == rv);
         498                 :
         499           18761 :     return thred;
         500                 : }  /* _PR_CreateThread */
         501                 :
         502           18761 : 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           18761 :     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           18761 : PR_IMPLEMENT(PRStatus) PR_JoinThread(PRThread *thred)
         538                 : {
         539           18761 :     int rv = -1;
         540           18761 :     void *result = NULL;
         541           18761 :     PR_ASSERT(thred != NULL);
         542                 :
         543           18761 :     if ((0xafafafaf == thred->state)
         544           18761 :     || (PT_THREAD_DETACHED == (PT_THREAD_DETACHED & thred->state))
         545           18761 :     || (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           18761 :         pthread_t id = thred->id;
         560           18761 :         rv = pthread_join(id, &result);
         561           18761 :         PR_ASSERT(rv == 0 && result == NULL);
         562           18761 :         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           18761 :             _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           18761 :     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      1162574842 : PR_IMPLEMENT(PRThread*) PR_GetCurrentThread(void)
         609                 : {
         610                 :     void *thred;
         611                 :
         612      1162574842 :     if (!_pr_initialized) _PR_ImplicitInitialization();
         613                 :
         614      1162574842 :     _PT_PTHREAD_GETSPECIFIC(pt_book.key, thred);
         615      1162574842 :     if (NULL == thred) thred = pt_AttachThread();
         616      1162574823 :     PR_ASSERT(NULL != thred);
         617      1162574823 :     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           18667 : PR_IMPLEMENT(void) PR_SetThreadPriority(PRThread *thred, PRThreadPriority newPri)
         645                 : {
         646           18667 :     PRIntn rv = -1;
         647                 :
         648           18667 :     PR_ASSERT(NULL != thred);
         649                 :
         650           18667 :     if ((PRIntn)PR_PRIORITY_FIRST > (PRIntn)newPri)
         651               0 :         newPri = PR_PRIORITY_FIRST;
         652           18667 :     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           18667 :     if (EPERM != pt_schedpriv)
         660                 :     {
         661                 :         int policy;
         662                 :         struct sched_param schedule;
         663                 :
         664           18667 :         rv = pthread_getschedparam(thred->id, &policy, &schedule);
         665           18667 :         if(0 == rv) {
         666           18667 :                         schedule.sched_priority = pt_PriorityMap(newPri);
         667           18667 :                         rv = pthread_setschedparam(thred->id, policy, &schedule);
         668           18667 :                         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           18667 :                 if (rv != 0)
         676               0 :                         rv = -1;
         677                 :     }
         678                 : #endif
         679                 :
         680           18667 :     thred->priority = newPri;
         681           18667 : }  /* 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               0 : PR_IMPLEMENT(PRStatus) PR_Sleep(PRIntervalTime ticks)
         750                 : {
         751               0 :     PRStatus rv = PR_SUCCESS;
         752                 :
         753               0 :     if (!_pr_initialized) _PR_ImplicitInitialization();
         754                 :
         755               0 :     if (PR_INTERVAL_NO_WAIT == ticks)
         756                 :     {
         757               0 :         _PT_PTHREAD_YIELD();
         758                 :     }
         759                 :     else
         760                 :     {
         761                 :         PRCondVar *cv;
         762                 :         PRIntervalTime timein;
         763                 :
         764               0 :         timein = PR_IntervalNow();
         765               0 :         cv = PR_NewCondVar(_pr_sleeplock);
         766               0 :         PR_ASSERT(cv != NULL);
         767               0 :         PR_Lock(_pr_sleeplock);
         768                 :         do
         769                 :         {
         770               0 :             PRIntervalTime now = PR_IntervalNow();
         771               0 :             PRIntervalTime delta = now - timein;
         772               0 :             if (delta > ticks) break;
         773               0 :             rv = PR_WaitCondVar(cv, ticks - delta);
         774               0 :         } while (PR_SUCCESS == rv);
         775               0 :         PR_Unlock(_pr_sleeplock);
         776               0 :         PR_DestroyCondVar(cv);
         777                 :     }
         778               0 :     return rv;
         779                 : }  /* PR_Sleep */
         780                 :
         781               0 : static void _pt_thread_death(void *arg)
         782                 : {
         783                 :     void *thred;
         784                 :     int rv;
         785                 :
         786               0 :     _PT_PTHREAD_GETSPECIFIC(pt_book.key, thred);
         787               0 :     if (NULL == thred)
         788                 :     {
         789                 :         /*
         790                 :          * Have PR_GetCurrentThread return the expected value to the
         791                 :          * destructors.
         792                 :          */
         793               0 :         rv = pthread_setspecific(pt_book.key, arg);
         794               0 :         PR_ASSERT(0 == rv);
         795                 :     }
         796                 :
         797                 :     /* PR_TRUE for: call destructors */
         798               0 :     _pt_thread_death_internal(arg, PR_TRUE);
         799                 :
         800               0 :     if (NULL == thred)
         801                 :     {
         802               0 :         rv = pthread_setspecific(pt_book.key, NULL);
         803               0 :         PR_ASSERT(0 == rv);
         804                 :     }
         805               0 : }
         806                 :
         807           18761 : static void _pt_thread_death_internal(void *arg, PRBool callDestructors)
         808                 : {
         809           18761 :     PRThread *thred = (PRThread*)arg;
         810                 :
         811           18761 :     if (thred->state & (PT_THREAD_FOREIGN|PT_THREAD_PRIMORD))
         812                 :     {
         813               0 :         PR_Lock(pt_book.ml);
         814               0 :         if (NULL == thred->prev)
         815               0 :             pt_book.first = thred->next;
         816                 :         else
         817               0 :             thred->prev->next = thred->next;
         818               0 :         if (NULL == thred->next)
         819               0 :             pt_book.last = thred->prev;
         820                 :         else
         821               0 :             thred->next->prev = thred->prev;
         822               0 :         PR_Unlock(pt_book.ml);
         823                 :     }
         824           18761 :     if (callDestructors)
         825               0 :         _PR_DestroyThreadPrivate(thred);
         826           18761 :     PR_Free(thred->privateData);
         827           18761 :     if (NULL != thred->errorString)
         828               0 :         PR_Free(thred->errorString);
         829           18761 :     PR_Free(thred->stack);
         830           18761 :     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           18761 :     memset(thred, 0xaf, sizeof(PRThread));
         838                 : #endif /* defined(DEBUG) */
         839           18761 :     PR_Free(thred);
         840           18761 : }  /* _pt_thread_death */
         841                 :
         842           18667 : 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           18667 :     pt_book.minPrio = PT_PRIO_MIN;
         879           18667 :     pt_book.maxPrio = PT_PRIO_MAX;
         880                 : #endif
         881                 : #endif
         882                 :
         883           18667 :     PR_ASSERT(NULL == pt_book.ml);
         884           18667 :     pt_book.ml = PR_NewLock();
         885           18667 :     PR_ASSERT(NULL != pt_book.ml);
         886           18667 :     pt_book.cv = PR_NewCondVar(pt_book.ml);
         887           18667 :     PR_ASSERT(NULL != pt_book.cv);
         888           18667 :     thred = PR_NEWZAP(PRThread);
         889           18667 :     PR_ASSERT(NULL != thred);
         890           18667 :     thred->arg = NULL;
         891           18667 :     thred->startFunc = NULL;
         892           18667 :     thred->priority = priority;
         893           18667 :     thred->id = pthread_self();
         894                 :
         895           18667 :     thred->state = (PT_THREAD_DETACHED | PT_THREAD_PRIMORD);
         896           18667 :     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           18667 :             pt_book.user += 1;
         905           18667 :             pt_book.this_many = 1;
         906                 :     }
         907           18667 :     thred->next = thred->prev = NULL;
         908           18667 :     pt_book.first = pt_book.last = thred;
         909                 :
         910           18667 :     thred->stack = PR_NEWZAP(PRThreadStack);
         911           18667 :     PR_ASSERT(thred->stack != NULL);
         912           18667 :     thred->stack->stackSize = 0;
         913           18667 :     thred->stack->thr = thred;
         914           18667 :         _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           18667 :     rv = _PT_PTHREAD_KEY_CREATE(&pt_book.key, _pt_thread_death);
         931           18667 :     PR_ASSERT(0 == rv);
         932           18667 :     rv = pthread_setspecific(pt_book.key, thred);
         933           18667 :     PR_ASSERT(0 == rv);
         934           18667 :     PR_SetThreadPriority(thred, priority);
         935           18667 : }  /* _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               0 : PR_IMPLEMENT(PRStatus) PR_Cleanup(void)
        1012                 : {
        1013               0 :     PRThread *me = PR_GetCurrentThread();
        1014                 :     int rv;
        1015               0 :     PR_LOG(_pr_thread_lm, PR_LOG_MIN, ("PR_Cleanup: shutting down NSPR"));
        1016               0 :     PR_ASSERT(me->state & PT_THREAD_PRIMORD);
        1017               0 :     if (me->state & PT_THREAD_PRIMORD)
        1018                 :     {
        1019               0 :         PR_Lock(pt_book.ml);
        1020               0 :         while (pt_book.user > pt_book.this_many)
        1021               0 :             PR_WaitCondVar(pt_book.cv, PR_INTERVAL_NO_TIMEOUT);
        1022               0 :         if (me->state & PT_THREAD_SYSTEM)
        1023               0 :             pt_book.system -= 1;
        1024                 :         else
        1025               0 :             pt_book.user -= 1;
        1026               0 :         PR_Unlock(pt_book.ml);
        1027                 :
        1028               0 :         _PR_MD_EARLY_CLEANUP();
        1029                 :
        1030               0 :         _PR_CleanupMW();
        1031               0 :         _PR_CleanupTime();
        1032               0 :         _PR_CleanupDtoa();
        1033               0 :         _PR_CleanupCallOnce();
        1034               0 :         _PR_ShutdownLinker();
        1035               0 :         _PR_LogCleanup();
        1036               0 :         _PR_CleanupNet();
        1037                 :         /* Close all the fd's before calling _PR_CleanupIO */
        1038               0 :         _PR_CleanupIO();
        1039               0 :         _PR_CleanupCMon();
        1040                 :
        1041               0 :         _pt_thread_death(me);
        1042               0 :         rv = pthread_setspecific(pt_book.key, NULL);
        1043               0 :         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               0 :         if (0 == pt_book.system)
        1051                 :         {
        1052               0 :             PR_DestroyCondVar(pt_book.cv); pt_book.cv = NULL;
        1053               0 :             PR_DestroyLock(pt_book.ml); pt_book.ml = NULL;
        1054                 :         }
        1055               0 :         PR_DestroyLock(_pr_sleeplock);
        1056               0 :         _pr_sleeplock = NULL;
        1057               0 :         _PR_CleanupLayerCache();
        1058               0 :         _PR_CleanupEnv();
        1059                 : #ifdef _PR_ZONE_ALLOCATOR
        1060               0 :         _PR_DestroyZones();
        1061                 : #endif
        1062               0 :         _pr_initialized = PR_FALSE;
        1063               0 :         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