nsprpub/pr/src/pthreads/ptthread.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/nsprpub/pr/src/pthreads/ptthread.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1814 @@
     1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +/*
    1.10 +** File:            ptthread.c
    1.11 +** Descritpion:        Implemenation for threds using pthreds
    1.12 +** Exports:            ptthread.h
    1.13 +*/
    1.14 +
    1.15 +#if defined(_PR_PTHREADS) || defined(_PR_DCETHREADS)
    1.16 +
    1.17 +#include "prlog.h"
    1.18 +#include "primpl.h"
    1.19 +#include "prpdce.h"
    1.20 +
    1.21 +#include <pthread.h>
    1.22 +#include <unistd.h>
    1.23 +#include <string.h>
    1.24 +#include <signal.h>
    1.25 +#include <dlfcn.h>
    1.26 +
    1.27 +#ifdef SYMBIAN
    1.28 +/* In Open C sched_get_priority_min/max do not work properly, so we undefine
    1.29 + * _POSIX_THREAD_PRIORITY_SCHEDULING here.
    1.30 + */
    1.31 +#undef _POSIX_THREAD_PRIORITY_SCHEDULING
    1.32 +#endif
    1.33 +
    1.34 +#ifdef _PR_NICE_PRIORITY_SCHEDULING
    1.35 +#undef _POSIX_THREAD_PRIORITY_SCHEDULING
    1.36 +#include <sys/resource.h>
    1.37 +#ifndef HAVE_GETTID
    1.38 +#define gettid() (syscall(SYS_gettid))
    1.39 +#endif
    1.40 +#endif
    1.41 +
    1.42 +/*
    1.43 + * Record whether or not we have the privilege to set the scheduling
    1.44 + * policy and priority of threads.  0 means that privilege is available.
    1.45 + * EPERM means that privilege is not available.
    1.46 + */
    1.47 +
    1.48 +static PRIntn pt_schedpriv = 0;
    1.49 +extern PRLock *_pr_sleeplock;
    1.50 +
    1.51 +static struct _PT_Bookeeping
    1.52 +{
    1.53 +    PRLock *ml;                 /* a lock to protect ourselves */
    1.54 +    PRCondVar *cv;              /* used to signal global things */
    1.55 +    PRInt32 system, user;       /* a count of the two different types */
    1.56 +    PRUintn this_many;          /* number of threads allowed for exit */
    1.57 +    pthread_key_t key;          /* thread private data key */
    1.58 +    PRBool keyCreated;          /* whether 'key' should be deleted */
    1.59 +    PRThread *first, *last;     /* list of threads we know about */
    1.60 +#if defined(_PR_DCETHREADS) || defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
    1.61 +    PRInt32 minPrio, maxPrio;   /* range of scheduling priorities */
    1.62 +#endif
    1.63 +} pt_book = {0};
    1.64 +
    1.65 +static void _pt_thread_death(void *arg);
    1.66 +static void _pt_thread_death_internal(void *arg, PRBool callDestructors);
    1.67 +static void init_pthread_gc_support(void);
    1.68 +
    1.69 +#if defined(_PR_DCETHREADS) || defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
    1.70 +static PRIntn pt_PriorityMap(PRThreadPriority pri)
    1.71 +{
    1.72 +#ifdef NTO
    1.73 +    /* This priority algorithm causes lots of problems on Neutrino
    1.74 +     * for now I have just hard coded everything to run at priority 10
    1.75 +     * until I can come up with a new algorithm.
    1.76 +     *     Jerry.Kirk@Nexwarecorp.com
    1.77 +     */
    1.78 +    return 10;
    1.79 +#else
    1.80 +    return pt_book.minPrio +
    1.81 +	    pri * (pt_book.maxPrio - pt_book.minPrio) / PR_PRIORITY_LAST;
    1.82 +#endif
    1.83 +}
    1.84 +#elif defined(_PR_NICE_PRIORITY_SCHEDULING)
    1.85 +/*
    1.86 + * This functions maps higher priorities to lower nice values relative to the
    1.87 + * nice value specified in the |nice| parameter. The corresponding relative
    1.88 + * adjustments are:
    1.89 + *
    1.90 + * PR_PRIORITY_LOW    +1
    1.91 + * PR_PRIORITY_NORMAL  0
    1.92 + * PR_PRIORITY_HIGH   -1
    1.93 + * PR_PRIORITY_URGENT -2
    1.94 + */
    1.95 +static int pt_RelativePriority(int nice, PRThreadPriority pri)
    1.96 +{
    1.97 +    return nice + (1 - pri);
    1.98 +}
    1.99 +#endif
   1.100 +
   1.101 +/*
   1.102 +** Initialize a stack for a native pthread thread
   1.103 +*/
   1.104 +static void _PR_InitializeStack(PRThreadStack *ts)
   1.105 +{
   1.106 +    if( ts && (ts->stackTop == 0) ) {
   1.107 +        ts->allocBase = (char *) &ts;
   1.108 +        ts->allocSize = ts->stackSize;
   1.109 +
   1.110 +        /*
   1.111 +        ** Setup stackTop and stackBottom values.
   1.112 +        */
   1.113 +#ifdef HAVE_STACK_GROWING_UP
   1.114 +        ts->stackBottom = ts->allocBase + ts->stackSize;
   1.115 +        ts->stackTop = ts->allocBase;
   1.116 +#else
   1.117 +        ts->stackTop    = ts->allocBase;
   1.118 +        ts->stackBottom = ts->allocBase - ts->stackSize;
   1.119 +#endif
   1.120 +    }
   1.121 +}
   1.122 +
   1.123 +static void *_pt_root(void *arg)
   1.124 +{
   1.125 +    PRIntn rv;
   1.126 +    PRThread *thred = (PRThread*)arg;
   1.127 +    PRBool detached = (thred->state & PT_THREAD_DETACHED) ? PR_TRUE : PR_FALSE;
   1.128 +    pthread_t id = pthread_self();
   1.129 +#ifdef _PR_NICE_PRIORITY_SCHEDULING
   1.130 +    pid_t tid;
   1.131 +#endif
   1.132 +
   1.133 +#ifdef _PR_NICE_PRIORITY_SCHEDULING
   1.134 +    /*
   1.135 +     * We need to know the kernel thread ID of each thread in order to
   1.136 +     * set its nice value hence we do it here instead of at creation time.
   1.137 +     */
   1.138 +    tid = gettid();
   1.139 +    errno = 0;
   1.140 +    rv = getpriority(PRIO_PROCESS, 0);
   1.141 +
   1.142 +    /* If we cannot read the main thread's nice value don't try to change the
   1.143 +     * new thread's nice value. */
   1.144 +    if (errno == 0) {
   1.145 +        setpriority(PRIO_PROCESS, tid,
   1.146 +                    pt_RelativePriority(rv, thred->priority));
   1.147 +    }
   1.148 +#endif
   1.149 +
   1.150 +    /*
   1.151 +    ** DCE Threads can't detach during creation, so do it late.
   1.152 +    ** I would like to do it only here, but that doesn't seem
   1.153 +    ** to work.
   1.154 +    */
   1.155 +#if defined(_PR_DCETHREADS)
   1.156 +    if (detached)
   1.157 +    {
   1.158 +        /* pthread_detach() modifies its argument, so we must pass a copy */
   1.159 +        pthread_t self = id;
   1.160 +        rv = pthread_detach(&self);
   1.161 +        PR_ASSERT(0 == rv);
   1.162 +    }
   1.163 +#endif /* defined(_PR_DCETHREADS) */
   1.164 +
   1.165 +    /* Set up the thread stack information */
   1.166 +    _PR_InitializeStack(thred->stack);
   1.167 +
   1.168 +    /*
   1.169 +     * Set within the current thread the pointer to our object.
   1.170 +     * This object will be deleted when the thread termintates,
   1.171 +     * whether in a join or detached (see _PR_InitThreads()).
   1.172 +     */
   1.173 +    rv = pthread_setspecific(pt_book.key, thred);
   1.174 +    PR_ASSERT(0 == rv);
   1.175 +
   1.176 +    /* make the thread visible to the rest of the runtime */
   1.177 +    PR_Lock(pt_book.ml);
   1.178 +    /*
   1.179 +     * Both the parent thread and this new thread set thred->id.
   1.180 +     * The new thread must ensure that thred->id is set before
   1.181 +     * it executes its startFunc.  The parent thread must ensure
   1.182 +     * that thred->id is set before PR_CreateThread() returns.
   1.183 +     * Both threads set thred->id while holding pt_book.ml and
   1.184 +     * use thred->idSet to ensure thred->id is written only once.
   1.185 +     */
   1.186 +    if (!thred->idSet)
   1.187 +    {
   1.188 +        thred->id = id;
   1.189 +        thred->idSet = PR_TRUE;
   1.190 +    }
   1.191 +    else
   1.192 +    {
   1.193 +        PR_ASSERT(pthread_equal(thred->id, id));
   1.194 +    }
   1.195 +
   1.196 +#ifdef _PR_NICE_PRIORITY_SCHEDULING
   1.197 +    thred->tid = tid;
   1.198 +    PR_NotifyAllCondVar(pt_book.cv);
   1.199 +#endif
   1.200 +
   1.201 +    /* If this is a GCABLE thread, set its state appropriately */
   1.202 +    if (thred->suspend & PT_THREAD_SETGCABLE)
   1.203 +	    thred->state |= PT_THREAD_GCABLE;
   1.204 +    thred->suspend = 0;
   1.205 +
   1.206 +    thred->prev = pt_book.last;
   1.207 +    if (pt_book.last)
   1.208 +        pt_book.last->next = thred;
   1.209 +    else
   1.210 +        pt_book.first = thred;
   1.211 +    thred->next = NULL;
   1.212 +    pt_book.last = thred;
   1.213 +    PR_Unlock(pt_book.ml);
   1.214 +
   1.215 +    thred->startFunc(thred->arg);  /* make visible to the client */
   1.216 +
   1.217 +    /* unhook the thread from the runtime */
   1.218 +    PR_Lock(pt_book.ml);
   1.219 +    /*
   1.220 +     * At this moment, PR_CreateThread() may not have set thred->id yet.
   1.221 +     * It is safe for a detached thread to free thred only after
   1.222 +     * PR_CreateThread() has accessed thred->id and thred->idSet.
   1.223 +     */
   1.224 +    if (detached)
   1.225 +    {
   1.226 +        while (!thred->okToDelete)
   1.227 +            PR_WaitCondVar(pt_book.cv, PR_INTERVAL_NO_TIMEOUT);
   1.228 +    }
   1.229 +
   1.230 +    if (thred->state & PT_THREAD_SYSTEM)
   1.231 +        pt_book.system -= 1;
   1.232 +    else if (--pt_book.user == pt_book.this_many)
   1.233 +        PR_NotifyAllCondVar(pt_book.cv);
   1.234 +    if (NULL == thred->prev)
   1.235 +        pt_book.first = thred->next;
   1.236 +    else
   1.237 +        thred->prev->next = thred->next;
   1.238 +    if (NULL == thred->next)
   1.239 +        pt_book.last = thred->prev;
   1.240 +    else
   1.241 +        thred->next->prev = thred->prev;
   1.242 +    PR_Unlock(pt_book.ml);
   1.243 +
   1.244 +    /*
   1.245 +    * Here we set the pthread's backpointer to the PRThread to NULL.
   1.246 +    * Otherwise the destructor would get called eagerly as the thread
   1.247 +    * returns to the pthread runtime. The joining thread would them be
   1.248 +    * the proud possessor of a dangling reference. However, this is the
   1.249 +    * last chance to delete the object if the thread is detached, so
   1.250 +    * just let the destructor do the work.
   1.251 +    */
   1.252 +    if (PR_FALSE == detached)
   1.253 +    {
   1.254 +        /* Call TPD destructors on this thread. */
   1.255 +        _PR_DestroyThreadPrivate(thred);
   1.256 +        rv = pthread_setspecific(pt_book.key, NULL);
   1.257 +        PR_ASSERT(0 == rv);
   1.258 +    }
   1.259 +
   1.260 +    return NULL;
   1.261 +}  /* _pt_root */
   1.262 +
   1.263 +static PRThread* pt_AttachThread(void)
   1.264 +{
   1.265 +    PRThread *thred = NULL;
   1.266 +
   1.267 +    /*
   1.268 +     * NSPR must have been initialized when PR_AttachThread is called.
   1.269 +     * We cannot have PR_AttachThread call implicit initialization
   1.270 +     * because if multiple threads call PR_AttachThread simultaneously,
   1.271 +     * NSPR may be initialized more than once.
   1.272 +     * We can't call any function that calls PR_GetCurrentThread()
   1.273 +     * either (e.g., PR_SetError()) as that will result in infinite
   1.274 +     * recursion.
   1.275 +     */
   1.276 +    if (!_pr_initialized) return NULL;
   1.277 +
   1.278 +    /* PR_NEWZAP must not call PR_GetCurrentThread() */
   1.279 +    thred = PR_NEWZAP(PRThread);
   1.280 +    if (NULL != thred)
   1.281 +    {
   1.282 +        int rv;
   1.283 +
   1.284 +        thred->priority = PR_PRIORITY_NORMAL;
   1.285 +        thred->id = pthread_self();
   1.286 +        thred->idSet = PR_TRUE;
   1.287 +#ifdef _PR_NICE_PRIORITY_SCHEDULING
   1.288 +        thred->tid = gettid();
   1.289 +#endif
   1.290 +        rv = pthread_setspecific(pt_book.key, thred);
   1.291 +        PR_ASSERT(0 == rv);
   1.292 +
   1.293 +        thred->state = PT_THREAD_GLOBAL | PT_THREAD_FOREIGN;
   1.294 +        PR_Lock(pt_book.ml);
   1.295 +
   1.296 +        /* then put it into the list */
   1.297 +        thred->prev = pt_book.last;
   1.298 +        if (pt_book.last)
   1.299 +            pt_book.last->next = thred;
   1.300 +        else
   1.301 +            pt_book.first = thred;
   1.302 +        thred->next = NULL;
   1.303 +        pt_book.last = thred;
   1.304 +        PR_Unlock(pt_book.ml);
   1.305 +
   1.306 +    }
   1.307 +    return thred;  /* may be NULL */
   1.308 +}  /* pt_AttachThread */
   1.309 +
   1.310 +static PRThread* _PR_CreateThread(
   1.311 +    PRThreadType type, void (*start)(void *arg),
   1.312 +    void *arg, PRThreadPriority priority, PRThreadScope scope,
   1.313 +    PRThreadState state, PRUint32 stackSize, PRBool isGCAble)
   1.314 +{
   1.315 +    int rv;
   1.316 +    PRThread *thred;
   1.317 +    pthread_attr_t tattr;
   1.318 +
   1.319 +    if (!_pr_initialized) _PR_ImplicitInitialization();
   1.320 +
   1.321 +    if ((PRIntn)PR_PRIORITY_FIRST > (PRIntn)priority)
   1.322 +        priority = PR_PRIORITY_FIRST;
   1.323 +    else if ((PRIntn)PR_PRIORITY_LAST < (PRIntn)priority)
   1.324 +        priority = PR_PRIORITY_LAST;
   1.325 +
   1.326 +    rv = _PT_PTHREAD_ATTR_INIT(&tattr);
   1.327 +    PR_ASSERT(0 == rv);
   1.328 +
   1.329 +    if (EPERM != pt_schedpriv)
   1.330 +    {
   1.331 +#if !defined(_PR_DCETHREADS) && defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
   1.332 +        struct sched_param schedule;
   1.333 +#endif
   1.334 +
   1.335 +#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
   1.336 +        rv = pthread_attr_setinheritsched(&tattr, PTHREAD_EXPLICIT_SCHED);
   1.337 +        PR_ASSERT(0 == rv);
   1.338 +#endif
   1.339 +
   1.340 +        /* Use the default scheduling policy */
   1.341 +
   1.342 +#if defined(_PR_DCETHREADS)
   1.343 +        rv = pthread_attr_setprio(&tattr, pt_PriorityMap(priority));
   1.344 +        PR_ASSERT(0 == rv);
   1.345 +#elif defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
   1.346 +        rv = pthread_attr_getschedparam(&tattr, &schedule);
   1.347 +        PR_ASSERT(0 == rv);
   1.348 +        schedule.sched_priority = pt_PriorityMap(priority);
   1.349 +        rv = pthread_attr_setschedparam(&tattr, &schedule);
   1.350 +        PR_ASSERT(0 == rv);
   1.351 +#ifdef NTO
   1.352 +        rv = pthread_attr_setschedpolicy(&tattr, SCHED_RR); /* Round Robin */
   1.353 +        PR_ASSERT(0 == rv);
   1.354 +#endif
   1.355 +#endif /* !defined(_PR_DCETHREADS) */
   1.356 +    }
   1.357 +
   1.358 +    /*
   1.359 +     * DCE threads can't set detach state before creating the thread.
   1.360 +     * AIX can't set detach late. Why can't we all just get along?
   1.361 +     */
   1.362 +#if !defined(_PR_DCETHREADS)
   1.363 +    rv = pthread_attr_setdetachstate(&tattr,
   1.364 +        ((PR_JOINABLE_THREAD == state) ?
   1.365 +            PTHREAD_CREATE_JOINABLE : PTHREAD_CREATE_DETACHED));
   1.366 +    PR_ASSERT(0 == rv);
   1.367 +#endif /* !defined(_PR_DCETHREADS) */
   1.368 +
   1.369 +    /*
   1.370 +     * If stackSize is 0, we use the default pthread stack size.
   1.371 +     */
   1.372 +    if (stackSize)
   1.373 +    {
   1.374 +#ifdef _MD_MINIMUM_STACK_SIZE
   1.375 +        if (stackSize < _MD_MINIMUM_STACK_SIZE)
   1.376 +            stackSize = _MD_MINIMUM_STACK_SIZE;
   1.377 +#endif
   1.378 +        rv = pthread_attr_setstacksize(&tattr, stackSize);
   1.379 +        PR_ASSERT(0 == rv);
   1.380 +    }
   1.381 +
   1.382 +    thred = PR_NEWZAP(PRThread);
   1.383 +    if (NULL == thred)
   1.384 +    {
   1.385 +        PR_SetError(PR_OUT_OF_MEMORY_ERROR, errno);
   1.386 +        goto done;
   1.387 +    }
   1.388 +    else
   1.389 +    {
   1.390 +        pthread_t id;
   1.391 +
   1.392 +        thred->arg = arg;
   1.393 +        thred->startFunc = start;
   1.394 +        thred->priority = priority;
   1.395 +        if (PR_UNJOINABLE_THREAD == state)
   1.396 +            thred->state |= PT_THREAD_DETACHED;
   1.397 +
   1.398 +        if (PR_LOCAL_THREAD == scope)
   1.399 +        	scope = PR_GLOBAL_THREAD;
   1.400 +			
   1.401 +        if (PR_GLOBAL_BOUND_THREAD == scope) {
   1.402 +#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
   1.403 +    		rv = pthread_attr_setscope(&tattr, PTHREAD_SCOPE_SYSTEM);
   1.404 +			if (rv) {
   1.405 +				/*
   1.406 +				 * system scope not supported
   1.407 +				 */
   1.408 +        		scope = PR_GLOBAL_THREAD;
   1.409 +				/*
   1.410 +				 * reset scope
   1.411 +				 */
   1.412 +    			rv = pthread_attr_setscope(&tattr, PTHREAD_SCOPE_PROCESS);
   1.413 +    			PR_ASSERT(0 == rv);
   1.414 +			}
   1.415 +#endif
   1.416 +		}
   1.417 +        if (PR_GLOBAL_THREAD == scope)
   1.418 +            thred->state |= PT_THREAD_GLOBAL;
   1.419 +        else if (PR_GLOBAL_BOUND_THREAD == scope)
   1.420 +            thred->state |= (PT_THREAD_GLOBAL | PT_THREAD_BOUND);
   1.421 +		else	/* force it global */
   1.422 +            thred->state |= PT_THREAD_GLOBAL;
   1.423 +        if (PR_SYSTEM_THREAD == type)
   1.424 +            thred->state |= PT_THREAD_SYSTEM;
   1.425 +
   1.426 +        thred->suspend =(isGCAble) ? PT_THREAD_SETGCABLE : 0;
   1.427 +
   1.428 +        thred->stack = PR_NEWZAP(PRThreadStack);
   1.429 +        if (thred->stack == NULL) {
   1.430 +            PRIntn oserr = errno;
   1.431 +            PR_Free(thred);  /* all that work ... poof! */
   1.432 +            PR_SetError(PR_OUT_OF_MEMORY_ERROR, oserr);
   1.433 +            thred = NULL;  /* and for what? */
   1.434 +            goto done;
   1.435 +        }
   1.436 +        thred->stack->stackSize = stackSize;
   1.437 +        thred->stack->thr = thred;
   1.438 +
   1.439 +#ifdef PT_NO_SIGTIMEDWAIT
   1.440 +        pthread_mutex_init(&thred->suspendResumeMutex,NULL);
   1.441 +        pthread_cond_init(&thred->suspendResumeCV,NULL);
   1.442 +#endif
   1.443 +
   1.444 +        /* make the thread counted to the rest of the runtime */
   1.445 +        PR_Lock(pt_book.ml);
   1.446 +        if (PR_SYSTEM_THREAD == type)
   1.447 +            pt_book.system += 1;
   1.448 +        else pt_book.user += 1;
   1.449 +        PR_Unlock(pt_book.ml);
   1.450 +
   1.451 +        /*
   1.452 +         * We pass a pointer to a local copy (instead of thred->id)
   1.453 +         * to pthread_create() because who knows what wacky things
   1.454 +         * pthread_create() may be doing to its argument.
   1.455 +         */
   1.456 +        rv = _PT_PTHREAD_CREATE(&id, tattr, _pt_root, thred);
   1.457 +
   1.458 +#if !defined(_PR_DCETHREADS)
   1.459 +        if (EPERM == rv)
   1.460 +        {
   1.461 +#if defined(IRIX)
   1.462 +        	if (PR_GLOBAL_BOUND_THREAD == scope) {
   1.463 +				/*
   1.464 +				 * SCOPE_SYSTEM requires appropriate privilege
   1.465 +				 * reset to process scope and try again
   1.466 +				 */
   1.467 +    			rv = pthread_attr_setscope(&tattr, PTHREAD_SCOPE_PROCESS);
   1.468 +    			PR_ASSERT(0 == rv);
   1.469 +            	thred->state &= ~PT_THREAD_BOUND;
   1.470 +			}
   1.471 +#else
   1.472 +            /* Remember that we don't have thread scheduling privilege. */
   1.473 +            pt_schedpriv = EPERM;
   1.474 +            PR_LOG(_pr_thread_lm, PR_LOG_MIN,
   1.475 +                ("_PR_CreateThread: no thread scheduling privilege"));
   1.476 +            /* Try creating the thread again without setting priority. */
   1.477 +#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
   1.478 +            rv = pthread_attr_setinheritsched(&tattr, PTHREAD_INHERIT_SCHED);
   1.479 +            PR_ASSERT(0 == rv);
   1.480 +#endif
   1.481 +#endif	/* IRIX */
   1.482 +            rv = _PT_PTHREAD_CREATE(&id, tattr, _pt_root, thred);
   1.483 +        }
   1.484 +#endif
   1.485 +
   1.486 +        if (0 != rv)
   1.487 +        {
   1.488 +#if defined(_PR_DCETHREADS)
   1.489 +            PRIntn oserr = errno;
   1.490 +#else
   1.491 +            PRIntn oserr = rv;
   1.492 +#endif
   1.493 +            PR_Lock(pt_book.ml);
   1.494 +            if (thred->state & PT_THREAD_SYSTEM)
   1.495 +                pt_book.system -= 1;
   1.496 +            else if (--pt_book.user == pt_book.this_many)
   1.497 +                PR_NotifyAllCondVar(pt_book.cv);
   1.498 +            PR_Unlock(pt_book.ml);
   1.499 +
   1.500 +            PR_Free(thred->stack);
   1.501 +            PR_Free(thred);  /* all that work ... poof! */
   1.502 +            PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, oserr);
   1.503 +            thred = NULL;  /* and for what? */
   1.504 +            goto done;
   1.505 +        }
   1.506 +
   1.507 +        PR_Lock(pt_book.ml);
   1.508 +        /*
   1.509 +         * Both the parent thread and this new thread set thred->id.
   1.510 +         * The parent thread must ensure that thred->id is set before
   1.511 +         * PR_CreateThread() returns.  (See comments in _pt_root().)
   1.512 +         */
   1.513 +        if (!thred->idSet)
   1.514 +        {
   1.515 +            thred->id = id;
   1.516 +            thred->idSet = PR_TRUE;
   1.517 +        }
   1.518 +        else
   1.519 +        {
   1.520 +            PR_ASSERT(pthread_equal(thred->id, id));
   1.521 +        }
   1.522 +
   1.523 +        /*
   1.524 +         * If the new thread is detached, tell it that PR_CreateThread() has
   1.525 +         * accessed thred->id and thred->idSet so it's ok to delete thred.
   1.526 +         */
   1.527 +        if (PR_UNJOINABLE_THREAD == state)
   1.528 +        {
   1.529 +            thred->okToDelete = PR_TRUE;
   1.530 +            PR_NotifyAllCondVar(pt_book.cv);
   1.531 +        }
   1.532 +        PR_Unlock(pt_book.ml);
   1.533 +    }
   1.534 +
   1.535 +done:
   1.536 +    rv = _PT_PTHREAD_ATTR_DESTROY(&tattr);
   1.537 +    PR_ASSERT(0 == rv);
   1.538 +
   1.539 +    return thred;
   1.540 +}  /* _PR_CreateThread */
   1.541 +
   1.542 +PR_IMPLEMENT(PRThread*) PR_CreateThread(
   1.543 +    PRThreadType type, void (*start)(void *arg), void *arg,
   1.544 +    PRThreadPriority priority, PRThreadScope scope,
   1.545 +    PRThreadState state, PRUint32 stackSize)
   1.546 +{
   1.547 +    return _PR_CreateThread(
   1.548 +        type, start, arg, priority, scope, state, stackSize, PR_FALSE);
   1.549 +} /* PR_CreateThread */
   1.550 +
   1.551 +PR_IMPLEMENT(PRThread*) PR_CreateThreadGCAble(
   1.552 +    PRThreadType type, void (*start)(void *arg), void *arg, 
   1.553 +    PRThreadPriority priority, PRThreadScope scope,
   1.554 +    PRThreadState state, PRUint32 stackSize)
   1.555 +{
   1.556 +    return _PR_CreateThread(
   1.557 +        type, start, arg, priority, scope, state, stackSize, PR_TRUE);
   1.558 +}  /* PR_CreateThreadGCAble */
   1.559 +
   1.560 +PR_IMPLEMENT(void*) GetExecutionEnvironment(PRThread *thred)
   1.561 +{
   1.562 +    return thred->environment;
   1.563 +}  /* GetExecutionEnvironment */
   1.564 + 
   1.565 +PR_IMPLEMENT(void) SetExecutionEnvironment(PRThread *thred, void *env)
   1.566 +{
   1.567 +    thred->environment = env;
   1.568 +}  /* SetExecutionEnvironment */
   1.569 +
   1.570 +PR_IMPLEMENT(PRThread*) PR_AttachThread(
   1.571 +    PRThreadType type, PRThreadPriority priority, PRThreadStack *stack)
   1.572 +{
   1.573 +    return PR_GetCurrentThread();
   1.574 +}  /* PR_AttachThread */
   1.575 +
   1.576 +
   1.577 +PR_IMPLEMENT(PRStatus) PR_JoinThread(PRThread *thred)
   1.578 +{
   1.579 +    int rv = -1;
   1.580 +    void *result = NULL;
   1.581 +    PR_ASSERT(thred != NULL);
   1.582 +
   1.583 +    if ((0xafafafaf == thred->state)
   1.584 +    || (PT_THREAD_DETACHED == (PT_THREAD_DETACHED & thred->state))
   1.585 +    || (PT_THREAD_FOREIGN == (PT_THREAD_FOREIGN & thred->state)))
   1.586 +    {
   1.587 +        /*
   1.588 +         * This might be a bad address, but if it isn't, the state should
   1.589 +         * either be an unjoinable thread or it's already had the object
   1.590 +         * deleted. However, the client that called join on a detached
   1.591 +         * thread deserves all the rath I can muster....
   1.592 +         */
   1.593 +        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
   1.594 +        PR_LogPrint(
   1.595 +            "PR_JoinThread: %p not joinable | already smashed\n", thred);
   1.596 +    }
   1.597 +    else
   1.598 +    {
   1.599 +        pthread_t id = thred->id;
   1.600 +        rv = pthread_join(id, &result);
   1.601 +        PR_ASSERT(rv == 0 && result == NULL);
   1.602 +        if (0 == rv)
   1.603 +        {
   1.604 +#ifdef _PR_DCETHREADS
   1.605 +            rv = pthread_detach(&id);
   1.606 +            PR_ASSERT(0 == rv);
   1.607 +#endif
   1.608 +            /*
   1.609 +             * PR_FALSE, because the thread already called the TPD
   1.610 +             * destructors before exiting _pt_root.
   1.611 +             */
   1.612 +            _pt_thread_death_internal(thred, PR_FALSE);
   1.613 +        }
   1.614 +        else
   1.615 +        {
   1.616 +            PRErrorCode prerror;
   1.617 +            switch (rv)
   1.618 +            {
   1.619 +                case EINVAL:  /* not a joinable thread */
   1.620 +                case ESRCH:   /* no thread with given ID */
   1.621 +                    prerror = PR_INVALID_ARGUMENT_ERROR;
   1.622 +                    break;
   1.623 +                case EDEADLK: /* a thread joining with itself */
   1.624 +                    prerror = PR_DEADLOCK_ERROR;
   1.625 +                    break;
   1.626 +                default:
   1.627 +                    prerror = PR_UNKNOWN_ERROR;
   1.628 +                    break;
   1.629 +            }
   1.630 +            PR_SetError(prerror, rv);
   1.631 +        }
   1.632 +    }
   1.633 +    return (0 == rv) ? PR_SUCCESS : PR_FAILURE;
   1.634 +}  /* PR_JoinThread */
   1.635 +
   1.636 +PR_IMPLEMENT(void) PR_DetachThread(void)
   1.637 +{
   1.638 +    void *thred;
   1.639 +    int rv;
   1.640 +
   1.641 +    _PT_PTHREAD_GETSPECIFIC(pt_book.key, thred);
   1.642 +    if (NULL == thred) return;
   1.643 +    _pt_thread_death(thred);
   1.644 +    rv = pthread_setspecific(pt_book.key, NULL);
   1.645 +    PR_ASSERT(0 == rv);
   1.646 +}  /* PR_DetachThread */
   1.647 +
   1.648 +PR_IMPLEMENT(PRThread*) PR_GetCurrentThread(void)
   1.649 +{
   1.650 +    void *thred;
   1.651 +
   1.652 +    if (!_pr_initialized) _PR_ImplicitInitialization();
   1.653 +
   1.654 +    _PT_PTHREAD_GETSPECIFIC(pt_book.key, thred);
   1.655 +    if (NULL == thred) thred = pt_AttachThread();
   1.656 +    PR_ASSERT(NULL != thred);
   1.657 +    return (PRThread*)thred;
   1.658 +}  /* PR_GetCurrentThread */
   1.659 +
   1.660 +PR_IMPLEMENT(PRThreadScope) PR_GetThreadScope(const PRThread *thred)
   1.661 +{
   1.662 +    return (thred->state & PT_THREAD_BOUND) ?
   1.663 +        PR_GLOBAL_BOUND_THREAD : PR_GLOBAL_THREAD;
   1.664 +}  /* PR_GetThreadScope() */
   1.665 +
   1.666 +PR_IMPLEMENT(PRThreadType) PR_GetThreadType(const PRThread *thred)
   1.667 +{
   1.668 +    return (thred->state & PT_THREAD_SYSTEM) ?
   1.669 +        PR_SYSTEM_THREAD : PR_USER_THREAD;
   1.670 +}
   1.671 +
   1.672 +PR_IMPLEMENT(PRThreadState) PR_GetThreadState(const PRThread *thred)
   1.673 +{
   1.674 +    return (thred->state & PT_THREAD_DETACHED) ?
   1.675 +        PR_UNJOINABLE_THREAD : PR_JOINABLE_THREAD;
   1.676 +}  /* PR_GetThreadState */
   1.677 +
   1.678 +PR_IMPLEMENT(PRThreadPriority) PR_GetThreadPriority(const PRThread *thred)
   1.679 +{
   1.680 +    PR_ASSERT(thred != NULL);
   1.681 +    return thred->priority;
   1.682 +}  /* PR_GetThreadPriority */
   1.683 +
   1.684 +PR_IMPLEMENT(void) PR_SetThreadPriority(PRThread *thred, PRThreadPriority newPri)
   1.685 +{
   1.686 +    PRIntn rv = -1;
   1.687 +
   1.688 +    PR_ASSERT(NULL != thred);
   1.689 +
   1.690 +    if ((PRIntn)PR_PRIORITY_FIRST > (PRIntn)newPri)
   1.691 +        newPri = PR_PRIORITY_FIRST;
   1.692 +    else if ((PRIntn)PR_PRIORITY_LAST < (PRIntn)newPri)
   1.693 +        newPri = PR_PRIORITY_LAST;
   1.694 +
   1.695 +#if defined(_PR_DCETHREADS)
   1.696 +    rv = pthread_setprio(thred->id, pt_PriorityMap(newPri));
   1.697 +    /* pthread_setprio returns the old priority */
   1.698 +#elif defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
   1.699 +    if (EPERM != pt_schedpriv)
   1.700 +    {
   1.701 +        int policy;
   1.702 +        struct sched_param schedule;
   1.703 +
   1.704 +        rv = pthread_getschedparam(thred->id, &policy, &schedule);
   1.705 +        if(0 == rv) {
   1.706 +			schedule.sched_priority = pt_PriorityMap(newPri);
   1.707 +			rv = pthread_setschedparam(thred->id, policy, &schedule);
   1.708 +			if (EPERM == rv)
   1.709 +			{
   1.710 +				pt_schedpriv = EPERM;
   1.711 +				PR_LOG(_pr_thread_lm, PR_LOG_MIN,
   1.712 +					("PR_SetThreadPriority: no thread scheduling privilege"));
   1.713 +			}
   1.714 +		}
   1.715 +		if (rv != 0)
   1.716 +			rv = -1;
   1.717 +    }
   1.718 +#elif defined(_PR_NICE_PRIORITY_SCHEDULING)
   1.719 +    PR_Lock(pt_book.ml);
   1.720 +    while (thred->tid == 0)
   1.721 +        PR_WaitCondVar(pt_book.cv, PR_INTERVAL_NO_TIMEOUT);
   1.722 +    PR_Unlock(pt_book.ml);
   1.723 +
   1.724 +    errno = 0;
   1.725 +    rv = getpriority(PRIO_PROCESS, 0);
   1.726 +
   1.727 +    /* Do not proceed unless we know the main thread's nice value. */
   1.728 +    if (errno == 0) {
   1.729 +        rv = setpriority(PRIO_PROCESS, thred->tid,
   1.730 +                         pt_RelativePriority(rv, newPri));
   1.731 +
   1.732 +        if (rv == -1)
   1.733 +        {
   1.734 +            /* We don't set pt_schedpriv to EPERM in case errno == EPERM
   1.735 +             * because adjusting the nice value might be permitted for certain
   1.736 +             * ranges but not for others. */
   1.737 +            PR_LOG(_pr_thread_lm, PR_LOG_MIN,
   1.738 +                ("PR_SetThreadPriority: setpriority failed with error %d",
   1.739 +                 errno));
   1.740 +        }
   1.741 +    }
   1.742 +#endif
   1.743 +
   1.744 +    thred->priority = newPri;
   1.745 +}  /* PR_SetThreadPriority */
   1.746 +
   1.747 +PR_IMPLEMENT(PRStatus) PR_Interrupt(PRThread *thred)
   1.748 +{
   1.749 +    /*
   1.750 +    ** If the target thread indicates that it's waiting,
   1.751 +    ** find the condition and broadcast to it. Broadcast
   1.752 +    ** since we don't know which thread (if there are more
   1.753 +    ** than one). This sounds risky, but clients must
   1.754 +    ** test their invariants when resumed from a wait and
   1.755 +    ** I don't expect very many threads to be waiting on
   1.756 +    ** a single condition and I don't expect interrupt to
   1.757 +    ** be used very often.
   1.758 +    **
   1.759 +    ** I don't know why I thought this would work. Must have
   1.760 +    ** been one of those weaker momements after I'd been
   1.761 +    ** smelling the vapors.
   1.762 +    **
   1.763 +    ** Even with the followng changes it is possible that
   1.764 +    ** the pointer to the condition variable is pointing
   1.765 +    ** at a bogus value. Will the unerlying code detect
   1.766 +    ** that?
   1.767 +    */
   1.768 +    PRCondVar *cv;
   1.769 +    PR_ASSERT(NULL != thred);
   1.770 +    if (NULL == thred) return PR_FAILURE;
   1.771 +
   1.772 +    thred->state |= PT_THREAD_ABORTED;
   1.773 +
   1.774 +    cv = thred->waiting;
   1.775 +    if ((NULL != cv) && !thred->interrupt_blocked)
   1.776 +    {
   1.777 +        PRIntn rv;
   1.778 +        (void)PR_ATOMIC_INCREMENT(&cv->notify_pending);
   1.779 +        rv = pthread_cond_broadcast(&cv->cv);
   1.780 +        PR_ASSERT(0 == rv);
   1.781 +        if (0 > PR_ATOMIC_DECREMENT(&cv->notify_pending))
   1.782 +            PR_DestroyCondVar(cv);
   1.783 +    }
   1.784 +    return PR_SUCCESS;
   1.785 +}  /* PR_Interrupt */
   1.786 +
   1.787 +PR_IMPLEMENT(void) PR_ClearInterrupt(void)
   1.788 +{
   1.789 +    PRThread *me = PR_GetCurrentThread();
   1.790 +    me->state &= ~PT_THREAD_ABORTED;
   1.791 +}  /* PR_ClearInterrupt */
   1.792 +
   1.793 +PR_IMPLEMENT(void) PR_BlockInterrupt(void)
   1.794 +{
   1.795 +    PRThread *me = PR_GetCurrentThread();
   1.796 +    _PT_THREAD_BLOCK_INTERRUPT(me);
   1.797 +}  /* PR_BlockInterrupt */
   1.798 +
   1.799 +PR_IMPLEMENT(void) PR_UnblockInterrupt(void)
   1.800 +{
   1.801 +    PRThread *me = PR_GetCurrentThread();
   1.802 +    _PT_THREAD_UNBLOCK_INTERRUPT(me);
   1.803 +}  /* PR_UnblockInterrupt */
   1.804 +
   1.805 +PR_IMPLEMENT(PRStatus) PR_Yield(void)
   1.806 +{
   1.807 +    static PRBool warning = PR_TRUE;
   1.808 +    if (warning) warning = _PR_Obsolete(
   1.809 +        "PR_Yield()", "PR_Sleep(PR_INTERVAL_NO_WAIT)");
   1.810 +    return PR_Sleep(PR_INTERVAL_NO_WAIT);
   1.811 +}
   1.812 +
   1.813 +PR_IMPLEMENT(PRStatus) PR_Sleep(PRIntervalTime ticks)
   1.814 +{
   1.815 +    PRStatus rv = PR_SUCCESS;
   1.816 +
   1.817 +    if (!_pr_initialized) _PR_ImplicitInitialization();
   1.818 +
   1.819 +    if (PR_INTERVAL_NO_WAIT == ticks)
   1.820 +    {
   1.821 +        _PT_PTHREAD_YIELD();
   1.822 +    }
   1.823 +    else
   1.824 +    {
   1.825 +        PRCondVar *cv;
   1.826 +        PRIntervalTime timein;
   1.827 +
   1.828 +        timein = PR_IntervalNow();
   1.829 +        cv = PR_NewCondVar(_pr_sleeplock);
   1.830 +        PR_ASSERT(cv != NULL);
   1.831 +        PR_Lock(_pr_sleeplock);
   1.832 +        do
   1.833 +        {
   1.834 +            PRIntervalTime now = PR_IntervalNow();
   1.835 +            PRIntervalTime delta = now - timein;
   1.836 +            if (delta > ticks) break;
   1.837 +            rv = PR_WaitCondVar(cv, ticks - delta);
   1.838 +        } while (PR_SUCCESS == rv);
   1.839 +        PR_Unlock(_pr_sleeplock);
   1.840 +        PR_DestroyCondVar(cv);
   1.841 +    }
   1.842 +    return rv;
   1.843 +}  /* PR_Sleep */
   1.844 +
   1.845 +static void _pt_thread_death(void *arg)
   1.846 +{
   1.847 +    void *thred;
   1.848 +    int rv;
   1.849 +
   1.850 +    _PT_PTHREAD_GETSPECIFIC(pt_book.key, thred);
   1.851 +    if (NULL == thred)
   1.852 +    {
   1.853 +        /*
   1.854 +         * Have PR_GetCurrentThread return the expected value to the
   1.855 +         * destructors.
   1.856 +         */
   1.857 +        rv = pthread_setspecific(pt_book.key, arg);
   1.858 +        PR_ASSERT(0 == rv);
   1.859 +    }
   1.860 +
   1.861 +    /* PR_TRUE for: call destructors */ 
   1.862 +    _pt_thread_death_internal(arg, PR_TRUE);
   1.863 +
   1.864 +    if (NULL == thred)
   1.865 +    {
   1.866 +        rv = pthread_setspecific(pt_book.key, NULL);
   1.867 +        PR_ASSERT(0 == rv);
   1.868 +    }
   1.869 +}
   1.870 +
   1.871 +static void _pt_thread_death_internal(void *arg, PRBool callDestructors)
   1.872 +{
   1.873 +    PRThread *thred = (PRThread*)arg;
   1.874 +
   1.875 +    if (thred->state & (PT_THREAD_FOREIGN|PT_THREAD_PRIMORD))
   1.876 +    {
   1.877 +        PR_Lock(pt_book.ml);
   1.878 +        if (NULL == thred->prev)
   1.879 +            pt_book.first = thred->next;
   1.880 +        else
   1.881 +            thred->prev->next = thred->next;
   1.882 +        if (NULL == thred->next)
   1.883 +            pt_book.last = thred->prev;
   1.884 +        else
   1.885 +            thred->next->prev = thred->prev;
   1.886 +        PR_Unlock(pt_book.ml);
   1.887 +    }
   1.888 +    if (callDestructors)
   1.889 +        _PR_DestroyThreadPrivate(thred);
   1.890 +    PR_Free(thred->privateData);
   1.891 +    if (NULL != thred->errorString)
   1.892 +        PR_Free(thred->errorString);
   1.893 +    if (NULL != thred->name)
   1.894 +        PR_Free(thred->name);
   1.895 +    PR_Free(thred->stack);
   1.896 +    if (NULL != thred->syspoll_list)
   1.897 +        PR_Free(thred->syspoll_list);
   1.898 +#if defined(_PR_POLL_WITH_SELECT)
   1.899 +    if (NULL != thred->selectfd_list)
   1.900 +        PR_Free(thred->selectfd_list);
   1.901 +#endif
   1.902 +#if defined(DEBUG)
   1.903 +    memset(thred, 0xaf, sizeof(PRThread));
   1.904 +#endif /* defined(DEBUG) */
   1.905 +    PR_Free(thred);
   1.906 +}  /* _pt_thread_death */
   1.907 +
   1.908 +void _PR_InitThreads(
   1.909 +    PRThreadType type, PRThreadPriority priority, PRUintn maxPTDs)
   1.910 +{
   1.911 +    int rv;
   1.912 +    PRThread *thred;
   1.913 +
   1.914 +    PR_ASSERT(priority == PR_PRIORITY_NORMAL);
   1.915 +
   1.916 +#ifdef _PR_NEED_PTHREAD_INIT
   1.917 +    /*
   1.918 +     * On BSD/OS (3.1 and 4.0), the pthread subsystem is lazily
   1.919 +     * initialized, but pthread_self() fails to initialize
   1.920 +     * pthreads and hence returns a null thread ID if invoked
   1.921 +     * by the primordial thread before any other pthread call.
   1.922 +     * So we explicitly initialize pthreads here.
   1.923 +     */
   1.924 +    pthread_init();
   1.925 +#endif
   1.926 +
   1.927 +#if defined(_PR_DCETHREADS) || defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
   1.928 +#if defined(FREEBSD)
   1.929 +    {
   1.930 +    pthread_attr_t attr;
   1.931 +    int policy;
   1.932 +    /* get the min and max priorities of the default policy */
   1.933 +    pthread_attr_init(&attr);
   1.934 +    pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
   1.935 +    pthread_attr_getschedpolicy(&attr, &policy);
   1.936 +    pt_book.minPrio = sched_get_priority_min(policy);
   1.937 +    PR_ASSERT(-1 != pt_book.minPrio);
   1.938 +    pt_book.maxPrio = sched_get_priority_max(policy);
   1.939 +    PR_ASSERT(-1 != pt_book.maxPrio);
   1.940 +    pthread_attr_destroy(&attr);
   1.941 +    }
   1.942 +#else
   1.943 +    /*
   1.944 +    ** These might be function evaluations
   1.945 +    */
   1.946 +    pt_book.minPrio = PT_PRIO_MIN;
   1.947 +    pt_book.maxPrio = PT_PRIO_MAX;
   1.948 +#endif
   1.949 +#endif
   1.950 +    
   1.951 +    PR_ASSERT(NULL == pt_book.ml);
   1.952 +    pt_book.ml = PR_NewLock();
   1.953 +    PR_ASSERT(NULL != pt_book.ml);
   1.954 +    pt_book.cv = PR_NewCondVar(pt_book.ml);
   1.955 +    PR_ASSERT(NULL != pt_book.cv);
   1.956 +    thred = PR_NEWZAP(PRThread);
   1.957 +    PR_ASSERT(NULL != thred);
   1.958 +    thred->arg = NULL;
   1.959 +    thred->startFunc = NULL;
   1.960 +    thred->priority = priority;
   1.961 +    thred->id = pthread_self();
   1.962 +    thred->idSet = PR_TRUE;
   1.963 +#ifdef _PR_NICE_PRIORITY_SCHEDULING
   1.964 +    thred->tid = gettid();
   1.965 +#endif
   1.966 +
   1.967 +    thred->state = (PT_THREAD_DETACHED | PT_THREAD_PRIMORD);
   1.968 +    if (PR_SYSTEM_THREAD == type)
   1.969 +    {
   1.970 +        thred->state |= PT_THREAD_SYSTEM;
   1.971 +        pt_book.system += 1;
   1.972 +	    pt_book.this_many = 0;
   1.973 +    }
   1.974 +    else
   1.975 +    {
   1.976 +	    pt_book.user += 1;
   1.977 +	    pt_book.this_many = 1;
   1.978 +    }
   1.979 +    thred->next = thred->prev = NULL;
   1.980 +    pt_book.first = pt_book.last = thred;
   1.981 +
   1.982 +    thred->stack = PR_NEWZAP(PRThreadStack);
   1.983 +    PR_ASSERT(thred->stack != NULL);
   1.984 +    thred->stack->stackSize = 0;
   1.985 +    thred->stack->thr = thred;
   1.986 +	_PR_InitializeStack(thred->stack);
   1.987 +
   1.988 +    /*
   1.989 +     * Create a key for our use to store a backpointer in the pthread
   1.990 +     * to our PRThread object. This object gets deleted when the thread
   1.991 +     * returns from its root in the case of a detached thread. Other
   1.992 +     * threads delete the objects in Join.
   1.993 +     *
   1.994 +     * NB: The destructor logic seems to have a bug so it isn't used.
   1.995 +     * NBB: Oh really? I'm going to give it a spin - AOF 19 June 1998.
   1.996 +     * More info - the problem is that pthreads calls the destructor
   1.997 +     * eagerly as the thread returns from its root, rather than lazily
   1.998 +     * after the thread is joined. Therefore, threads that are joining
   1.999 +     * and holding PRThread references are actually holding pointers to
  1.1000 +     * nothing.
  1.1001 +     */
  1.1002 +    rv = _PT_PTHREAD_KEY_CREATE(&pt_book.key, _pt_thread_death);
  1.1003 +    if (0 != rv)
  1.1004 +        PR_Assert("0 == rv", __FILE__, __LINE__);
  1.1005 +    pt_book.keyCreated = PR_TRUE;
  1.1006 +    rv = pthread_setspecific(pt_book.key, thred);
  1.1007 +    PR_ASSERT(0 == rv);
  1.1008 +}  /* _PR_InitThreads */
  1.1009 +
  1.1010 +#ifdef __GNUC__
  1.1011 +/*
  1.1012 + * GCC supports the constructor and destructor attributes as of
  1.1013 + * version 2.5.
  1.1014 + */
  1.1015 +static void _PR_Fini(void) __attribute__ ((destructor));
  1.1016 +#elif defined(__SUNPRO_C)
  1.1017 +/*
  1.1018 + * Sun Studio compiler
  1.1019 + */
  1.1020 +#pragma fini(_PR_Fini)
  1.1021 +static void _PR_Fini(void);
  1.1022 +#elif defined(HPUX)
  1.1023 +/*
  1.1024 + * Current versions of HP C compiler define __HP_cc.
  1.1025 + * HP C compiler A.11.01.20 doesn't define __HP_cc.
  1.1026 + */
  1.1027 +#if defined(__ia64) || defined(_LP64)
  1.1028 +#pragma FINI "_PR_Fini"
  1.1029 +static void _PR_Fini(void);
  1.1030 +#else
  1.1031 +/*
  1.1032 + * Only HP-UX 10.x style initializers are supported in 32-bit links.
  1.1033 + * Need to use the +I PR_HPUX10xInit linker option.
  1.1034 + */
  1.1035 +#include <dl.h>
  1.1036 +
  1.1037 +static void _PR_Fini(void);
  1.1038 +
  1.1039 +void PR_HPUX10xInit(shl_t handle, int loading)
  1.1040 +{
  1.1041 +    /*
  1.1042 +     * This function is called when a shared library is loaded as well
  1.1043 +     * as when the shared library is unloaded.  Note that it may not
  1.1044 +     * be called when the user's program terminates.
  1.1045 +     *
  1.1046 +     * handle is the shl_load API handle for the shared library being
  1.1047 +     * initialized.
  1.1048 +     *
  1.1049 +     * loading is non-zero at startup and zero at termination.
  1.1050 +     */
  1.1051 +    if (loading) {
  1.1052 +	/* ... do some initializations ... */
  1.1053 +    } else {
  1.1054 +	_PR_Fini();
  1.1055 +    }
  1.1056 +}
  1.1057 +#endif
  1.1058 +#elif defined(AIX)
  1.1059 +/* Need to use the -binitfini::_PR_Fini linker option. */
  1.1060 +#endif
  1.1061 +
  1.1062 +void _PR_Fini(void)
  1.1063 +{
  1.1064 +    void *thred;
  1.1065 +    int rv;
  1.1066 +
  1.1067 +    if (!_pr_initialized) {
  1.1068 +        /* Either NSPR was never successfully initialized or 
  1.1069 +         * PR_Cleanup has been called already. */
  1.1070 +        if (pt_book.keyCreated)
  1.1071 +        {
  1.1072 +            rv = pthread_key_delete(pt_book.key);
  1.1073 +            PR_ASSERT(0 == rv);
  1.1074 +            pt_book.keyCreated = PR_FALSE;
  1.1075 +        }
  1.1076 +        return;
  1.1077 +    }
  1.1078 +
  1.1079 +    _PT_PTHREAD_GETSPECIFIC(pt_book.key, thred);
  1.1080 +    if (NULL != thred)
  1.1081 +    {
  1.1082 +        /*
  1.1083 +         * PR_FALSE, because it is unsafe to call back to the 
  1.1084 +         * thread private data destructors at final cleanup.
  1.1085 +         */
  1.1086 +        _pt_thread_death_internal(thred, PR_FALSE);
  1.1087 +        rv = pthread_setspecific(pt_book.key, NULL);
  1.1088 +        PR_ASSERT(0 == rv);
  1.1089 +    }
  1.1090 +    rv = pthread_key_delete(pt_book.key);
  1.1091 +    PR_ASSERT(0 == rv);
  1.1092 +    pt_book.keyCreated = PR_FALSE;
  1.1093 +    /* TODO: free other resources used by NSPR */
  1.1094 +    /* _pr_initialized = PR_FALSE; */
  1.1095 +}  /* _PR_Fini */
  1.1096 +
  1.1097 +PR_IMPLEMENT(PRStatus) PR_Cleanup(void)
  1.1098 +{
  1.1099 +    PRThread *me = PR_GetCurrentThread();
  1.1100 +    int rv;
  1.1101 +    PR_LOG(_pr_thread_lm, PR_LOG_MIN, ("PR_Cleanup: shutting down NSPR"));
  1.1102 +    PR_ASSERT(me->state & PT_THREAD_PRIMORD);
  1.1103 +    if (me->state & PT_THREAD_PRIMORD)
  1.1104 +    {
  1.1105 +        PR_Lock(pt_book.ml);
  1.1106 +        while (pt_book.user > pt_book.this_many)
  1.1107 +            PR_WaitCondVar(pt_book.cv, PR_INTERVAL_NO_TIMEOUT);
  1.1108 +        if (me->state & PT_THREAD_SYSTEM)
  1.1109 +            pt_book.system -= 1;
  1.1110 +        else
  1.1111 +            pt_book.user -= 1;
  1.1112 +        PR_Unlock(pt_book.ml);
  1.1113 +
  1.1114 +        _PR_MD_EARLY_CLEANUP();
  1.1115 +
  1.1116 +        _PR_CleanupMW();
  1.1117 +        _PR_CleanupTime();
  1.1118 +        _PR_CleanupDtoa();
  1.1119 +        _PR_CleanupCallOnce();
  1.1120 +        _PR_ShutdownLinker();
  1.1121 +        _PR_LogCleanup();
  1.1122 +        _PR_CleanupNet();
  1.1123 +        /* Close all the fd's before calling _PR_CleanupIO */
  1.1124 +        _PR_CleanupIO();
  1.1125 +        _PR_CleanupCMon();
  1.1126 +
  1.1127 +        _pt_thread_death(me);
  1.1128 +        rv = pthread_setspecific(pt_book.key, NULL);
  1.1129 +        PR_ASSERT(0 == rv);
  1.1130 +        /*
  1.1131 +         * I am not sure if it's safe to delete the cv and lock here,
  1.1132 +         * since there may still be "system" threads around. If this
  1.1133 +         * call isn't immediately prior to exiting, then there's a
  1.1134 +         * problem.
  1.1135 +         */
  1.1136 +        if (0 == pt_book.system)
  1.1137 +        {
  1.1138 +            PR_DestroyCondVar(pt_book.cv); pt_book.cv = NULL;
  1.1139 +            PR_DestroyLock(pt_book.ml); pt_book.ml = NULL;
  1.1140 +        }
  1.1141 +        PR_DestroyLock(_pr_sleeplock);
  1.1142 +        _pr_sleeplock = NULL;
  1.1143 +        _PR_CleanupLayerCache();
  1.1144 +        _PR_CleanupEnv();
  1.1145 +#ifdef _PR_ZONE_ALLOCATOR
  1.1146 +        _PR_DestroyZones();
  1.1147 +#endif
  1.1148 +        _pr_initialized = PR_FALSE;
  1.1149 +        return PR_SUCCESS;
  1.1150 +    }
  1.1151 +    return PR_FAILURE;
  1.1152 +}  /* PR_Cleanup */
  1.1153 +
  1.1154 +PR_IMPLEMENT(void) PR_ProcessExit(PRIntn status)
  1.1155 +{
  1.1156 +    _exit(status);
  1.1157 +}
  1.1158 +
  1.1159 +PR_IMPLEMENT(PRUint32) PR_GetThreadID(PRThread *thred)
  1.1160 +{
  1.1161 +#if defined(_PR_DCETHREADS)
  1.1162 +    return (PRUint32)&thred->id;  /* this is really a sham! */
  1.1163 +#else
  1.1164 +    return (PRUint32)thred->id;  /* and I don't know what they will do with it */
  1.1165 +#endif
  1.1166 +}
  1.1167 +
  1.1168 +/*
  1.1169 + * $$$
  1.1170 + * The following two thread-to-processor affinity functions are not
  1.1171 + * yet implemented for pthreads.  By the way, these functions should return
  1.1172 + * PRStatus rather than PRInt32 to indicate the success/failure status.
  1.1173 + * $$$
  1.1174 + */
  1.1175 +
  1.1176 +PR_IMPLEMENT(PRInt32) PR_GetThreadAffinityMask(PRThread *thread, PRUint32 *mask)
  1.1177 +{
  1.1178 +    return 0;  /* not implemented */
  1.1179 +}
  1.1180 +
  1.1181 +PR_IMPLEMENT(PRInt32) PR_SetThreadAffinityMask(PRThread *thread, PRUint32 mask )
  1.1182 +{
  1.1183 +    return 0;  /* not implemented */
  1.1184 +}
  1.1185 +
  1.1186 +PR_IMPLEMENT(void)
  1.1187 +PR_SetThreadDumpProc(PRThread* thread, PRThreadDumpProc dump, void *arg)
  1.1188 +{
  1.1189 +    thread->dump = dump;
  1.1190 +    thread->dumpArg = arg;
  1.1191 +}
  1.1192 +
  1.1193 +/* 
  1.1194 + * Garbage collection support follows.
  1.1195 + */
  1.1196 +
  1.1197 +#if defined(_PR_DCETHREADS)
  1.1198 +
  1.1199 +/*
  1.1200 + * statics for Garbage Collection support.  We don't need to protect these
  1.1201 + * signal masks since the garbage collector itself is protected by a lock
  1.1202 + * and multiple threads will not be garbage collecting at the same time.
  1.1203 + */
  1.1204 +static sigset_t javagc_vtalarm_sigmask;
  1.1205 +static sigset_t javagc_intsoff_sigmask;
  1.1206 +
  1.1207 +#else /* defined(_PR_DCETHREADS) */
  1.1208 +
  1.1209 +/* a bogus signal mask for forcing a timed wait */
  1.1210 +/* Not so bogus in AIX as we really do a sigwait */
  1.1211 +static sigset_t sigwait_set;
  1.1212 +
  1.1213 +static struct timespec onemillisec = {0, 1000000L};
  1.1214 +#ifndef PT_NO_SIGTIMEDWAIT
  1.1215 +static struct timespec hundredmillisec = {0, 100000000L};
  1.1216 +#endif
  1.1217 +
  1.1218 +static void suspend_signal_handler(PRIntn sig);
  1.1219 +
  1.1220 +#ifdef PT_NO_SIGTIMEDWAIT
  1.1221 +static void null_signal_handler(PRIntn sig);
  1.1222 +#endif
  1.1223 +
  1.1224 +#endif /* defined(_PR_DCETHREADS) */
  1.1225 +
  1.1226 +/*
  1.1227 + * Linux pthreads use SIGUSR1 and SIGUSR2 internally, which
  1.1228 + * conflict with the use of these two signals in our GC support.
  1.1229 + * So we don't know how to support GC on Linux pthreads.
  1.1230 + */
  1.1231 +static void init_pthread_gc_support(void)
  1.1232 +{
  1.1233 +#ifndef SYMBIAN
  1.1234 +    PRIntn rv;
  1.1235 +
  1.1236 +#if defined(_PR_DCETHREADS)
  1.1237 +	rv = sigemptyset(&javagc_vtalarm_sigmask);
  1.1238 +    PR_ASSERT(0 == rv);
  1.1239 +	rv = sigaddset(&javagc_vtalarm_sigmask, SIGVTALRM);
  1.1240 +    PR_ASSERT(0 == rv);
  1.1241 +#else  /* defined(_PR_DCETHREADS) */
  1.1242 +	{
  1.1243 +	    struct sigaction sigact_usr2;
  1.1244 +
  1.1245 +	    sigact_usr2.sa_handler = suspend_signal_handler;
  1.1246 +	    sigact_usr2.sa_flags = SA_RESTART;
  1.1247 +	    sigemptyset (&sigact_usr2.sa_mask);
  1.1248 +
  1.1249 +        rv = sigaction (SIGUSR2, &sigact_usr2, NULL);
  1.1250 +        PR_ASSERT(0 == rv);
  1.1251 +
  1.1252 +        sigemptyset (&sigwait_set);
  1.1253 +#if defined(PT_NO_SIGTIMEDWAIT)
  1.1254 +        sigaddset (&sigwait_set, SIGUSR1);
  1.1255 +#else
  1.1256 +        sigaddset (&sigwait_set, SIGUSR2);
  1.1257 +#endif  /* defined(PT_NO_SIGTIMEDWAIT) */
  1.1258 +	}
  1.1259 +#if defined(PT_NO_SIGTIMEDWAIT)
  1.1260 +	{
  1.1261 +	    struct sigaction sigact_null;
  1.1262 +	    sigact_null.sa_handler = null_signal_handler;
  1.1263 +	    sigact_null.sa_flags = SA_RESTART;
  1.1264 +	    sigemptyset (&sigact_null.sa_mask);
  1.1265 +        rv = sigaction (SIGUSR1, &sigact_null, NULL);
  1.1266 +	    PR_ASSERT(0 ==rv); 
  1.1267 +    }
  1.1268 +#endif  /* defined(PT_NO_SIGTIMEDWAIT) */
  1.1269 +#endif /* defined(_PR_DCETHREADS) */
  1.1270 +#endif /* SYMBIAN */
  1.1271 +}
  1.1272 +
  1.1273 +PR_IMPLEMENT(void) PR_SetThreadGCAble(void)
  1.1274 +{
  1.1275 +    PR_Lock(pt_book.ml);
  1.1276 +	PR_GetCurrentThread()->state |= PT_THREAD_GCABLE;
  1.1277 +    PR_Unlock(pt_book.ml);
  1.1278 +}
  1.1279 +
  1.1280 +PR_IMPLEMENT(void) PR_ClearThreadGCAble(void)
  1.1281 +{
  1.1282 +    PR_Lock(pt_book.ml);
  1.1283 +	PR_GetCurrentThread()->state &= (~PT_THREAD_GCABLE);
  1.1284 +    PR_Unlock(pt_book.ml);
  1.1285 +}
  1.1286 +
  1.1287 +#if defined(DEBUG)
  1.1288 +static PRBool suspendAllOn = PR_FALSE;
  1.1289 +#endif
  1.1290 +
  1.1291 +static PRBool suspendAllSuspended = PR_FALSE;
  1.1292 +
  1.1293 +PR_IMPLEMENT(PRStatus) PR_EnumerateThreads(PREnumerator func, void *arg)
  1.1294 +{
  1.1295 +    PRIntn count = 0;
  1.1296 +    PRStatus rv = PR_SUCCESS;
  1.1297 +    PRThread* thred = pt_book.first;
  1.1298 +
  1.1299 +#if defined(DEBUG) || defined(FORCE_PR_ASSERT)
  1.1300 +#if !defined(_PR_DCETHREADS)
  1.1301 +    PRThread *me = PR_GetCurrentThread();
  1.1302 +#endif
  1.1303 +#endif
  1.1304 +
  1.1305 +    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_EnumerateThreads\n"));
  1.1306 +    /*
  1.1307 +     * $$$
  1.1308 +     * Need to suspend all threads other than me before doing this.
  1.1309 +     * This is really a gross and disgusting thing to do. The only
  1.1310 +     * good thing is that since all other threads are suspended, holding
  1.1311 +     * the lock during a callback seems like child's play.
  1.1312 +     * $$$
  1.1313 +     */
  1.1314 +    PR_ASSERT(suspendAllOn);
  1.1315 +
  1.1316 +    while (thred != NULL)
  1.1317 +    {
  1.1318 +        /* Steve Morse, 4-23-97: Note that we can't walk a queue by taking
  1.1319 +         * qp->next after applying the function "func".  In particular, "func"
  1.1320 +         * might remove the thread from the queue and put it into another one in
  1.1321 +         * which case qp->next no longer points to the next entry in the original
  1.1322 +         * queue.
  1.1323 +         *
  1.1324 +         * To get around this problem, we save qp->next in qp_next before applying
  1.1325 +         * "func" and use that saved value as the next value after applying "func".
  1.1326 +         */
  1.1327 +        PRThread* next = thred->next;
  1.1328 +
  1.1329 +        if (_PT_IS_GCABLE_THREAD(thred))
  1.1330 +        {
  1.1331 +#if !defined(_PR_DCETHREADS)
  1.1332 +            PR_ASSERT((thred == me) || (thred->suspend & PT_THREAD_SUSPENDED));
  1.1333 +#endif
  1.1334 +            PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 
  1.1335 +                   ("In PR_EnumerateThreads callback thread %p thid = %X\n", 
  1.1336 +                    thred, thred->id));
  1.1337 +
  1.1338 +            rv = func(thred, count++, arg);
  1.1339 +            if (rv != PR_SUCCESS)
  1.1340 +                return rv;
  1.1341 +        }
  1.1342 +        thred = next;
  1.1343 +    }
  1.1344 +    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 
  1.1345 +	   ("End PR_EnumerateThreads count = %d \n", count));
  1.1346 +    return rv;
  1.1347 +}  /* PR_EnumerateThreads */
  1.1348 +
  1.1349 +/*
  1.1350 + * PR_SuspendAll and PR_ResumeAll are called during garbage collection.  The strategy 
  1.1351 + * we use is to send a SIGUSR2 signal to every gc able thread that we intend to suspend.
  1.1352 + * The signal handler will record the stack pointer and will block until resumed by
  1.1353 + * the resume call.  Since the signal handler is the last routine called for the
  1.1354 + * suspended thread, the stack pointer will also serve as a place where all the
  1.1355 + * registers have been saved on the stack for the previously executing routines.
  1.1356 + *
  1.1357 + * Through global variables, we also make sure that PR_Suspend and PR_Resume does not
  1.1358 + * proceed until the thread is suspended or resumed.
  1.1359 + */
  1.1360 +
  1.1361 +#if !defined(_PR_DCETHREADS)
  1.1362 +
  1.1363 +/*
  1.1364 + * In the signal handler, we can not use condition variable notify or wait.
  1.1365 + * This does not work consistently across all pthread platforms.  We also can not 
  1.1366 + * use locking since that does not seem to work reliably across platforms.
  1.1367 + * Only thing we can do is yielding while testing for a global condition
  1.1368 + * to change.  This does work on pthread supported platforms.  We may have
  1.1369 + * to play with priortities if there are any problems detected.
  1.1370 + */
  1.1371 +
  1.1372 + /* 
  1.1373 +  * In AIX, you cannot use ANY pthread calls in the signal handler except perhaps
  1.1374 +  * pthread_yield. But that is horribly inefficient. Hence we use only sigwait, no
  1.1375 +  * sigtimedwait is available. We need to use another user signal, SIGUSR1. Actually
  1.1376 +  * SIGUSR1 is also used by exec in Java. So our usage here breaks the exec in Java,
  1.1377 +  * for AIX. You cannot use pthread_cond_wait or pthread_delay_np in the signal
  1.1378 +  * handler as all synchronization mechanisms just break down. 
  1.1379 +  */
  1.1380 +
  1.1381 +#if defined(PT_NO_SIGTIMEDWAIT)
  1.1382 +static void null_signal_handler(PRIntn sig)
  1.1383 +{
  1.1384 +	return;
  1.1385 +}
  1.1386 +#endif
  1.1387 +
  1.1388 +static void suspend_signal_handler(PRIntn sig)
  1.1389 +{
  1.1390 +	PRThread *me = PR_GetCurrentThread();
  1.1391 +
  1.1392 +	PR_ASSERT(me != NULL);
  1.1393 +	PR_ASSERT(_PT_IS_GCABLE_THREAD(me));
  1.1394 +	PR_ASSERT((me->suspend & PT_THREAD_SUSPENDED) == 0);
  1.1395 +
  1.1396 +	PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 
  1.1397 +        ("Begin suspend_signal_handler thred %p thread id = %X\n", 
  1.1398 +		me, me->id));
  1.1399 +
  1.1400 +	/*
  1.1401 +	 * save stack pointer
  1.1402 +	 */
  1.1403 +	me->sp = &me;
  1.1404 +
  1.1405 +	/* 
  1.1406 +	   At this point, the thread's stack pointer has been saved,
  1.1407 +	   And it is going to enter a wait loop until it is resumed.
  1.1408 +	   So it is _really_ suspended 
  1.1409 +	*/
  1.1410 +
  1.1411 +	me->suspend |= PT_THREAD_SUSPENDED;
  1.1412 +
  1.1413 +	/*
  1.1414 +	 * now, block current thread
  1.1415 +	 */
  1.1416 +#if defined(PT_NO_SIGTIMEDWAIT)
  1.1417 +	pthread_cond_signal(&me->suspendResumeCV);
  1.1418 +	while (me->suspend & PT_THREAD_SUSPENDED)
  1.1419 +	{
  1.1420 +#if !defined(FREEBSD) && !defined(NETBSD) && !defined(OPENBSD) \
  1.1421 +    && !defined(BSDI) && !defined(UNIXWARE) \
  1.1422 +    && !defined(DARWIN) && !defined(RISCOS) \
  1.1423 +    && !defined(SYMBIAN) /*XXX*/
  1.1424 +        PRIntn rv;
  1.1425 +	    sigwait(&sigwait_set, &rv);
  1.1426 +#endif
  1.1427 +	}
  1.1428 +	me->suspend |= PT_THREAD_RESUMED;
  1.1429 +	pthread_cond_signal(&me->suspendResumeCV);
  1.1430 +#else /* defined(PT_NO_SIGTIMEDWAIT) */
  1.1431 +	while (me->suspend & PT_THREAD_SUSPENDED)
  1.1432 +	{
  1.1433 +		PRIntn rv = sigtimedwait(&sigwait_set, NULL, &hundredmillisec);
  1.1434 +    	PR_ASSERT(-1 == rv);
  1.1435 +	}
  1.1436 +	me->suspend |= PT_THREAD_RESUMED;
  1.1437 +#endif
  1.1438 +
  1.1439 +    /*
  1.1440 +     * At this point, thread has been resumed, so set a global condition.
  1.1441 +     * The ResumeAll needs to know that this has really been resumed. 
  1.1442 +     * So the signal handler sets a flag which PR_ResumeAll will reset. 
  1.1443 +     * The PR_ResumeAll must reset this flag ...
  1.1444 +     */
  1.1445 +
  1.1446 +    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 
  1.1447 +        ("End suspend_signal_handler thred = %p tid = %X\n", me, me->id));
  1.1448 +}  /* suspend_signal_handler */
  1.1449 +
  1.1450 +static void pt_SuspendSet(PRThread *thred)
  1.1451 +{
  1.1452 +    PRIntn rv;
  1.1453 +
  1.1454 +    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 
  1.1455 +	   ("pt_SuspendSet thred %p thread id = %X\n", thred, thred->id));
  1.1456 +
  1.1457 +
  1.1458 +    /*
  1.1459 +     * Check the thread state and signal the thread to suspend
  1.1460 +     */
  1.1461 +
  1.1462 +    PR_ASSERT((thred->suspend & PT_THREAD_SUSPENDED) == 0);
  1.1463 +
  1.1464 +    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 
  1.1465 +	   ("doing pthread_kill in pt_SuspendSet thred %p tid = %X\n",
  1.1466 +	   thred, thred->id));
  1.1467 +#if defined(SYMBIAN)
  1.1468 +    /* All signal group functions are not implemented in Symbian OS */
  1.1469 +    rv = 0;
  1.1470 +#else
  1.1471 +    rv = pthread_kill (thred->id, SIGUSR2);
  1.1472 +#endif
  1.1473 +    PR_ASSERT(0 == rv);
  1.1474 +}
  1.1475 +
  1.1476 +static void pt_SuspendTest(PRThread *thred)
  1.1477 +{
  1.1478 +    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 
  1.1479 +	   ("Begin pt_SuspendTest thred %p thread id = %X\n", thred, thred->id));
  1.1480 +
  1.1481 +
  1.1482 +    /*
  1.1483 +     * Wait for the thread to be really suspended. This happens when the
  1.1484 +     * suspend signal handler stores the stack pointer and sets the state
  1.1485 +     * to suspended. 
  1.1486 +     */
  1.1487 +
  1.1488 +#if defined(PT_NO_SIGTIMEDWAIT)
  1.1489 +    pthread_mutex_lock(&thred->suspendResumeMutex);
  1.1490 +    while ((thred->suspend & PT_THREAD_SUSPENDED) == 0)
  1.1491 +    {
  1.1492 +	    pthread_cond_timedwait(
  1.1493 +	        &thred->suspendResumeCV, &thred->suspendResumeMutex, &onemillisec);
  1.1494 +	}
  1.1495 +	pthread_mutex_unlock(&thred->suspendResumeMutex);
  1.1496 +#else
  1.1497 +    while ((thred->suspend & PT_THREAD_SUSPENDED) == 0)
  1.1498 +    {
  1.1499 +		PRIntn rv = sigtimedwait(&sigwait_set, NULL, &onemillisec);
  1.1500 +    	PR_ASSERT(-1 == rv);
  1.1501 +	}
  1.1502 +#endif
  1.1503 +
  1.1504 +    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,
  1.1505 +        ("End pt_SuspendTest thred %p tid %X\n", thred, thred->id));
  1.1506 +}  /* pt_SuspendTest */
  1.1507 +
  1.1508 +static void pt_ResumeSet(PRThread *thred)
  1.1509 +{
  1.1510 +    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 
  1.1511 +	   ("pt_ResumeSet thred %p thread id = %X\n", thred, thred->id));
  1.1512 +
  1.1513 +    /*
  1.1514 +     * Clear the global state and set the thread state so that it will
  1.1515 +     * continue past yield loop in the suspend signal handler
  1.1516 +     */
  1.1517 +
  1.1518 +    PR_ASSERT(thred->suspend & PT_THREAD_SUSPENDED);
  1.1519 +
  1.1520 +
  1.1521 +    thred->suspend &= ~PT_THREAD_SUSPENDED;
  1.1522 +
  1.1523 +#if defined(PT_NO_SIGTIMEDWAIT)
  1.1524 +#if defined(SYMBIAN) 
  1.1525 +	/* All signal group functions are not implemented in Symbian OS */
  1.1526 +#else
  1.1527 +	pthread_kill(thred->id, SIGUSR1);
  1.1528 +#endif
  1.1529 +#endif
  1.1530 +
  1.1531 +}  /* pt_ResumeSet */
  1.1532 +
  1.1533 +static void pt_ResumeTest(PRThread *thred)
  1.1534 +{
  1.1535 +    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 
  1.1536 +	   ("Begin pt_ResumeTest thred %p thread id = %X\n", thred, thred->id));
  1.1537 +
  1.1538 +    /*
  1.1539 +     * Wait for the threads resume state to change
  1.1540 +     * to indicate it is really resumed 
  1.1541 +     */
  1.1542 +#if defined(PT_NO_SIGTIMEDWAIT)
  1.1543 +    pthread_mutex_lock(&thred->suspendResumeMutex);
  1.1544 +    while ((thred->suspend & PT_THREAD_RESUMED) == 0)
  1.1545 +    {
  1.1546 +	    pthread_cond_timedwait(
  1.1547 +	        &thred->suspendResumeCV, &thred->suspendResumeMutex, &onemillisec);
  1.1548 +    }
  1.1549 +    pthread_mutex_unlock(&thred->suspendResumeMutex);
  1.1550 +#else
  1.1551 +    while ((thred->suspend & PT_THREAD_RESUMED) == 0) {
  1.1552 +		PRIntn rv = sigtimedwait(&sigwait_set, NULL, &onemillisec);
  1.1553 +    	PR_ASSERT(-1 == rv);
  1.1554 +	}
  1.1555 +#endif
  1.1556 +
  1.1557 +    thred->suspend &= ~PT_THREAD_RESUMED;
  1.1558 +
  1.1559 +    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, (
  1.1560 +        "End pt_ResumeTest thred %p tid %X\n", thred, thred->id));
  1.1561 +}  /* pt_ResumeTest */
  1.1562 +
  1.1563 +static pthread_once_t pt_gc_support_control = PTHREAD_ONCE_INIT;
  1.1564 +
  1.1565 +PR_IMPLEMENT(void) PR_SuspendAll(void)
  1.1566 +{
  1.1567 +#ifdef DEBUG
  1.1568 +    PRIntervalTime stime, etime;
  1.1569 +#endif
  1.1570 +    PRThread* thred = pt_book.first;
  1.1571 +    PRThread *me = PR_GetCurrentThread();
  1.1572 +    int rv;
  1.1573 +
  1.1574 +    rv = pthread_once(&pt_gc_support_control, init_pthread_gc_support);
  1.1575 +    PR_ASSERT(0 == rv);
  1.1576 +    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_SuspendAll\n"));
  1.1577 +    /*
  1.1578 +     * Stop all threads which are marked GC able.
  1.1579 +     */
  1.1580 +    PR_Lock(pt_book.ml);
  1.1581 +#ifdef DEBUG
  1.1582 +    suspendAllOn = PR_TRUE;
  1.1583 +    stime = PR_IntervalNow();
  1.1584 +#endif
  1.1585 +    while (thred != NULL)
  1.1586 +    {
  1.1587 +	    if ((thred != me) && _PT_IS_GCABLE_THREAD(thred))
  1.1588 +    		pt_SuspendSet(thred);
  1.1589 +        thred = thred->next;
  1.1590 +    }
  1.1591 +
  1.1592 +    /* Wait till they are really suspended */
  1.1593 +    thred = pt_book.first;
  1.1594 +    while (thred != NULL)
  1.1595 +    {
  1.1596 +	    if ((thred != me) && _PT_IS_GCABLE_THREAD(thred))
  1.1597 +            pt_SuspendTest(thred);
  1.1598 +        thred = thred->next;
  1.1599 +    }
  1.1600 +
  1.1601 +    suspendAllSuspended = PR_TRUE;
  1.1602 +
  1.1603 +#ifdef DEBUG
  1.1604 +    etime = PR_IntervalNow();
  1.1605 +    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,\
  1.1606 +        ("End PR_SuspendAll (time %dms)\n",
  1.1607 +        PR_IntervalToMilliseconds(etime - stime)));
  1.1608 +#endif
  1.1609 +}  /* PR_SuspendAll */
  1.1610 +
  1.1611 +PR_IMPLEMENT(void) PR_ResumeAll(void)
  1.1612 +{
  1.1613 +#ifdef DEBUG
  1.1614 +    PRIntervalTime stime, etime;
  1.1615 +#endif
  1.1616 +    PRThread* thred = pt_book.first;
  1.1617 +    PRThread *me = PR_GetCurrentThread();
  1.1618 +    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_ResumeAll\n"));
  1.1619 +    /*
  1.1620 +     * Resume all previously suspended GC able threads.
  1.1621 +     */
  1.1622 +    suspendAllSuspended = PR_FALSE;
  1.1623 +#ifdef DEBUG
  1.1624 +    stime = PR_IntervalNow();
  1.1625 +#endif
  1.1626 +
  1.1627 +    while (thred != NULL)
  1.1628 +    {
  1.1629 +	    if ((thred != me) && _PT_IS_GCABLE_THREAD(thred))
  1.1630 +    	    pt_ResumeSet(thred);
  1.1631 +        thred = thred->next;
  1.1632 +    }
  1.1633 +
  1.1634 +    thred = pt_book.first;
  1.1635 +    while (thred != NULL)
  1.1636 +    {
  1.1637 +	    if ((thred != me) && _PT_IS_GCABLE_THREAD(thred))
  1.1638 +    	    pt_ResumeTest(thred);
  1.1639 +        thred = thred->next;
  1.1640 +    }
  1.1641 +
  1.1642 +    PR_Unlock(pt_book.ml);
  1.1643 +#ifdef DEBUG
  1.1644 +    suspendAllOn = PR_FALSE;
  1.1645 +    etime = PR_IntervalNow();
  1.1646 +    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,
  1.1647 +        ("End PR_ResumeAll (time %dms)\n",
  1.1648 +        PR_IntervalToMilliseconds(etime - stime)));
  1.1649 +#endif
  1.1650 +}  /* PR_ResumeAll */
  1.1651 +
  1.1652 +/* Return the stack pointer for the given thread- used by the GC */
  1.1653 +PR_IMPLEMENT(void *)PR_GetSP(PRThread *thred)
  1.1654 +{
  1.1655 +    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 
  1.1656 +	    ("in PR_GetSP thred %p thid = %X, sp = %p\n", 
  1.1657 +	    thred, thred->id, thred->sp));
  1.1658 +    return thred->sp;
  1.1659 +}  /* PR_GetSP */
  1.1660 +
  1.1661 +#else /* !defined(_PR_DCETHREADS) */
  1.1662 +
  1.1663 +static pthread_once_t pt_gc_support_control = pthread_once_init;
  1.1664 +
  1.1665 +/*
  1.1666 + * For DCE threads, there is no pthread_kill or a way of suspending or resuming a
  1.1667 + * particular thread.  We will just disable the preemption (virtual timer alarm) and
  1.1668 + * let the executing thread finish the garbage collection.  This stops all other threads
  1.1669 + * (GC able or not) and is very inefficient but there is no other choice.
  1.1670 + */
  1.1671 +PR_IMPLEMENT(void) PR_SuspendAll()
  1.1672 +{
  1.1673 +    PRIntn rv;
  1.1674 +
  1.1675 +    rv = pthread_once(&pt_gc_support_control, init_pthread_gc_support);
  1.1676 +    PR_ASSERT(0 == rv);  /* returns -1 on failure */
  1.1677 +#ifdef DEBUG
  1.1678 +    suspendAllOn = PR_TRUE;
  1.1679 +#endif
  1.1680 +    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_SuspendAll\n"));
  1.1681 +    /* 
  1.1682 +     * turn off preemption - i.e add virtual alarm signal to the set of 
  1.1683 +     * blocking signals 
  1.1684 +     */
  1.1685 +    rv = sigprocmask(
  1.1686 +        SIG_BLOCK, &javagc_vtalarm_sigmask, &javagc_intsoff_sigmask);
  1.1687 +    PR_ASSERT(0 == rv);
  1.1688 +    suspendAllSuspended = PR_TRUE;
  1.1689 +    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("End PR_SuspendAll\n"));
  1.1690 +}  /* PR_SuspendAll */
  1.1691 +
  1.1692 +PR_IMPLEMENT(void) PR_ResumeAll()
  1.1693 +{
  1.1694 +    PRIntn rv;
  1.1695 +    
  1.1696 +    suspendAllSuspended = PR_FALSE;
  1.1697 +    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_ResumeAll\n"));
  1.1698 +    /* turn on preemption - i.e re-enable virtual alarm signal */
  1.1699 +
  1.1700 +    rv = sigprocmask(SIG_SETMASK, &javagc_intsoff_sigmask, (sigset_t *)NULL);
  1.1701 +    PR_ASSERT(0 == rv);
  1.1702 +#ifdef DEBUG
  1.1703 +    suspendAllOn = PR_FALSE;
  1.1704 +#endif
  1.1705 +
  1.1706 +    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("End PR_ResumeAll\n"));
  1.1707 +}  /* PR_ResumeAll */
  1.1708 +
  1.1709 +/* Return the stack pointer for the given thread- used by the GC */
  1.1710 +PR_IMPLEMENT(void*)PR_GetSP(PRThread *thred)
  1.1711 +{
  1.1712 +	pthread_t tid = thred->id;
  1.1713 +	char *thread_tcb, *top_sp;
  1.1714 +
  1.1715 +	/*
  1.1716 +	 * For HPUX DCE threads, pthread_t is a struct with the
  1.1717 +	 * following three fields (see pthread.h, dce/cma.h):
  1.1718 +	 *     cma_t_address       field1;
  1.1719 +	 *     short int           field2;
  1.1720 +	 *     short int           field3;
  1.1721 +	 * where cma_t_address is typedef'd to be either void*
  1.1722 +	 * or char*.
  1.1723 +	 */
  1.1724 +	PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_GetSP\n"));
  1.1725 +	thread_tcb = (char*)tid.field1;
  1.1726 +	top_sp = *(char**)(thread_tcb + 128);
  1.1727 +	PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("End PR_GetSP %p \n", top_sp));
  1.1728 +	return top_sp;
  1.1729 +}  /* PR_GetSP */
  1.1730 +
  1.1731 +#endif /* !defined(_PR_DCETHREADS) */
  1.1732 +
  1.1733 +PR_IMPLEMENT(PRStatus) PR_SetCurrentThreadName(const char *name)
  1.1734 +{
  1.1735 +    PRThread *thread;
  1.1736 +    size_t nameLen;
  1.1737 +    int result;
  1.1738 +
  1.1739 +    if (!name) {
  1.1740 +        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  1.1741 +        return PR_FAILURE;
  1.1742 +    }
  1.1743 +
  1.1744 +    thread = PR_GetCurrentThread();
  1.1745 +    if (!thread)
  1.1746 +        return PR_FAILURE;
  1.1747 +
  1.1748 +    PR_Free(thread->name);
  1.1749 +    nameLen = strlen(name);
  1.1750 +    thread->name = (char *)PR_Malloc(nameLen + 1);
  1.1751 +    if (!thread->name)
  1.1752 +        return PR_FAILURE;
  1.1753 +    memcpy(thread->name, name, nameLen + 1);
  1.1754 +
  1.1755 +#if defined(OPENBSD) || defined(FREEBSD)
  1.1756 +    result = pthread_set_name_np(thread->id, name);
  1.1757 +#else /* not BSD */
  1.1758 +    /*
  1.1759 +     * On OSX, pthread_setname_np is only available in 10.6 or later, so test
  1.1760 +     * for it at runtime.  It also may not be available on all linux distros.
  1.1761 +     */
  1.1762 +#if defined(DARWIN)
  1.1763 +    int (*dynamic_pthread_setname_np)(const char*);
  1.1764 +#else
  1.1765 +    int (*dynamic_pthread_setname_np)(pthread_t, const char*);
  1.1766 +#endif
  1.1767 +
  1.1768 +    *(void**)(&dynamic_pthread_setname_np) =
  1.1769 +        dlsym(RTLD_DEFAULT, "pthread_setname_np");
  1.1770 +    if (!dynamic_pthread_setname_np)
  1.1771 +        return PR_SUCCESS;
  1.1772 +
  1.1773 +    /*
  1.1774 +     * The 15-character name length limit is an experimentally determined
  1.1775 +     * length of a null-terminated string that most linux distros and OS X
  1.1776 +     * accept as an argument to pthread_setname_np.  Otherwise the E2BIG
  1.1777 +     * error is returned by the function.
  1.1778 +     */
  1.1779 +#define SETNAME_LENGTH_CONSTRAINT 15
  1.1780 +#define SETNAME_FRAGMENT1_LENGTH (SETNAME_LENGTH_CONSTRAINT >> 1)
  1.1781 +#define SETNAME_FRAGMENT2_LENGTH \
  1.1782 +    (SETNAME_LENGTH_CONSTRAINT - SETNAME_FRAGMENT1_LENGTH - 1)
  1.1783 +    char name_dup[SETNAME_LENGTH_CONSTRAINT + 1];
  1.1784 +    if (nameLen > SETNAME_LENGTH_CONSTRAINT) {
  1.1785 +        memcpy(name_dup, name, SETNAME_FRAGMENT1_LENGTH);
  1.1786 +        name_dup[SETNAME_FRAGMENT1_LENGTH] = '~';
  1.1787 +        /* Note that this also copies the null terminator. */
  1.1788 +        memcpy(name_dup + SETNAME_FRAGMENT1_LENGTH + 1,
  1.1789 +               name + nameLen - SETNAME_FRAGMENT2_LENGTH,
  1.1790 +               SETNAME_FRAGMENT2_LENGTH + 1);
  1.1791 +        name = name_dup;
  1.1792 +    }
  1.1793 +
  1.1794 +#if defined(DARWIN)
  1.1795 +    result = dynamic_pthread_setname_np(name);
  1.1796 +#else
  1.1797 +    result = dynamic_pthread_setname_np(thread->id, name);
  1.1798 +#endif
  1.1799 +#endif /* not BSD */
  1.1800 +
  1.1801 +    if (result) {
  1.1802 +        PR_SetError(PR_UNKNOWN_ERROR, result);
  1.1803 +        return PR_FAILURE;
  1.1804 +    }
  1.1805 +    return PR_SUCCESS;
  1.1806 +}
  1.1807 +
  1.1808 +PR_IMPLEMENT(const char *) PR_GetThreadName(const PRThread *thread)
  1.1809 +{
  1.1810 +    if (!thread)
  1.1811 +        return NULL;
  1.1812 +    return thread->name;
  1.1813 +}
  1.1814 +
  1.1815 +#endif  /* defined(_PR_PTHREADS) || defined(_PR_DCETHREADS) */
  1.1816 +
  1.1817 +/* ptthread.c */

mercurial