nsprpub/pr/src/pthreads/ptthread.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial