Back to index

lightning-sunbird  0.9+nobinonly
Functions | Variables
pruthr.c File Reference
#include "primpl.h"
#include <signal.h>
#include <string.h>

Go to the source code of this file.

Functions

static void _PR_DecrActiveThreadCount (PRThread *thread)
static PRThread_PR_AttachThread (PRThreadType, PRThreadPriority, PRThreadStack *)
static void _PR_InitializeNativeStack (PRThreadStack *ts)
static void _PR_InitializeRecycledThread (PRThread *thread)
static void _PR_UserRunThread (void)
void _PR_InitThreads (PRThreadType type, PRThreadPriority priority, PRUintn maxPTDs)
void _PR_CleanupThreads (void)
void _PR_NotifyJoinWaiters (PRThread *thread)
PRStatus _PR_RecycleThread (PRThread *thread)
static void _PR_DestroyThread (PRThread *thread)
void _PR_NativeDestroyThread (PRThread *thread)
void _PR_UserDestroyThread (PRThread *thread)
void _PR_NativeRunThread (void *arg)
void _PR_SetThreadPriority (PRThread *thread, PRThreadPriority newPri)
static void _PR_Suspend (PRThread *thread)
static void _PR_Resume (PRThread *thread)
void _PR_Schedule (void)
 _PR_NativeCreateThread (PRThreadType type, void(*start)(void *arg), void *arg, PRThreadPriority priority, PRThreadScope scope, PRThreadState state, PRUint32 stackSize, PRUint32 flags)
 PR_IMPLEMENT (PRThread *)
PRThread_PRI_AttachThread (PRThreadType type, PRThreadPriority priority, PRThreadStack *stack, PRUint32 flags)
 PR_IMPLEMENT (void)
void _PRI_DetachThread (void)
 PR_IMPLEMENT (PRStatus)
 _PR_AddSleepQ (PRThread *thread, PRIntervalTime timeout)
 _PR_DelSleepQ (PRThread *thread, PRBool propogate_time)
void _PR_AddThreadToRunQ (PRThread *me, PRThread *thread)

Variables

PRLock_pr_activeLock
PRInt32 _pr_primordialExitCount
PRCondVar_pr_primordialExitCVar
PRLock_pr_deadQLock
PRUint32 _pr_numNativeDead
PRUint32 _pr_numUserDead
PRCList _pr_deadNativeQ
PRCList _pr_deadUserQ
PRUint32 _pr_join_counter
PRUint32 _pr_local_threads
PRUint32 _pr_global_threads
PRBool suspendAllOn = PR_FALSE
PRThreadsuspendAllThread = NULL
PRCList _pr_active_global_threadQ
PRCList _pr_active_local_threadQ

Function Documentation

_PR_AddSleepQ ( PRThread thread,
PRIntervalTime  timeout 
)

Definition at line 1776 of file pruthr.c.

{
    _PRCPU *cpu = thread->cpu;

    if (timeout == PR_INTERVAL_NO_TIMEOUT) {
        /* append the thread to the global pause Q */
        PR_APPEND_LINK(&thread->links, &_PR_PAUSEQ(thread->cpu));
        thread->flags |= _PR_ON_PAUSEQ;
    } else {
        PRIntervalTime sleep;
        PRCList *q;
        PRThread *t;

        /* sort onto global sleepQ */
        sleep = timeout;

        /* Check if we are longest timeout */
        if (timeout >= _PR_SLEEPQMAX(cpu)) {
            PR_INSERT_BEFORE(&thread->links, &_PR_SLEEPQ(cpu));
            thread->sleep = timeout - _PR_SLEEPQMAX(cpu);
            _PR_SLEEPQMAX(cpu) = timeout;
        } else {
            /* Sort thread into global sleepQ at appropriate point */
            q = _PR_SLEEPQ(cpu).next;

            /* Now scan the list for where to insert this entry */
            while (q != &_PR_SLEEPQ(cpu)) {
                t = _PR_THREAD_PTR(q);
                if (sleep < t->sleep) {
                    /* Found sleeper to insert in front of */
                    break;
                }
                sleep -= t->sleep;
                q = q->next;
            }
            thread->sleep = sleep;
            PR_INSERT_BEFORE(&thread->links, q);

            /*
            ** Subtract our sleep time from the sleeper that follows us (there
            ** must be one) so that they remain relative to us.
            */
            PR_ASSERT (thread->links.next != &_PR_SLEEPQ(cpu));
          
            t = _PR_THREAD_PTR(thread->links.next);
            PR_ASSERT(_PR_THREAD_PTR(t->links.prev) == thread);
            t->sleep -= sleep;
        }

        thread->flags |= _PR_ON_SLEEPQ;
    }
}
void _PR_AddThreadToRunQ ( PRThread me,
PRThread thread 
)

Definition at line 1874 of file pruthr.c.

{
    PRThreadPriority pri = thread->priority;
    _PRCPU *cpu = thread->cpu;

    PR_ASSERT(!_PR_IS_NATIVE_THREAD(thread));

#if defined(WINNT)
    /*
     * On NT, we can only reliably know that the current CPU
     * is not idle.  We add the awakened thread to the run
     * queue of its CPU if its CPU is the current CPU.
     * For any other CPU, we don't really know whether it
     * is busy or idle.  So in all other cases, we just
     * "post" the awakened thread to the IO completion port
     * for the next idle CPU to execute (this is done in
     * _PR_MD_WAKEUP_WAITER).
        * Threads with a suspended I/O operation remain bound to
        * the same cpu until I/O is cancelled
     *
     * NOTE: the boolean expression below must be the exact
     * opposite of the corresponding boolean expression in
     * _PR_MD_WAKEUP_WAITER.
     */
    if ((!_PR_IS_NATIVE_THREAD(me) && (cpu == me->cpu)) ||
                                   (thread->md.thr_bound_cpu)) {
              PR_ASSERT(!thread->md.thr_bound_cpu ||
                                                 (thread->md.thr_bound_cpu == cpu));
        _PR_RUNQ_LOCK(cpu);
        _PR_ADD_RUNQ(thread, cpu, pri);
        _PR_RUNQ_UNLOCK(cpu);
    }
#else
    _PR_RUNQ_LOCK(cpu);
    _PR_ADD_RUNQ(thread, cpu, pri);
    _PR_RUNQ_UNLOCK(cpu);
    if (!_PR_IS_NATIVE_THREAD(me) && (cpu == me->cpu)) {
        if (pri > me->priority) {
            _PR_SET_RESCHED_FLAG();
        }
    }
#endif
}

Here is the caller graph for this function:

static PRThread * _PR_AttachThread ( PRThreadType  type,
PRThreadPriority  priority,
PRThreadStack stack 
) [static]

Definition at line 1005 of file pruthr.c.

{
#if defined(XP_MAC)
#pragma unused (type)
#endif

    PRThread *thread;
    char *mem;

    if (priority > PR_PRIORITY_LAST) {
        priority = PR_PRIORITY_LAST;
    } else if (priority < PR_PRIORITY_FIRST) {
        priority = PR_PRIORITY_FIRST;
    }

    mem = (char*) PR_CALLOC(sizeof(PRThread));
    if (mem) {
        thread = (PRThread*) mem;
        thread->priority = priority;
        thread->stack = stack;
        thread->state = _PR_RUNNING;
        PR_INIT_CLIST(&thread->lockList);
        if (_PR_MD_NEW_LOCK(&thread->threadLock) == PR_FAILURE) {
        PR_DELETE(thread);
        return 0;
    }

        return thread;
    }
    return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 184 of file pruthr.c.

Here is the call graph for this function:

Here is the caller graph for this function:

static void _PR_DecrActiveThreadCount ( PRThread thread) [static]

Definition at line 323 of file pruthr.c.

Here is the call graph for this function:

Here is the caller graph for this function:

_PR_DelSleepQ ( PRThread thread,
PRBool  propogate_time 
)

Definition at line 1841 of file pruthr.c.

{
    _PRCPU *cpu = thread->cpu;

    /* Remove from pauseQ/sleepQ */
    if (thread->flags & (_PR_ON_PAUSEQ|_PR_ON_SLEEPQ)) {
        if (thread->flags & _PR_ON_SLEEPQ) {
            PRCList *q = thread->links.next;
            if (q != &_PR_SLEEPQ(cpu)) {
                if (propogate_time == PR_TRUE) {
                    PRThread *after = _PR_THREAD_PTR(q);
                    after->sleep += thread->sleep;
                } else 
                    _PR_SLEEPQMAX(cpu) -= thread->sleep;
            } else {
                /* Check if prev is the beggining of the list; if so,
                 * we are the only element on the list.  
                 */
                if (thread->links.prev != &_PR_SLEEPQ(cpu))
                    _PR_SLEEPQMAX(cpu) -= thread->sleep;
                else
                    _PR_SLEEPQMAX(cpu) = 0;
            }
            thread->flags &= ~_PR_ON_SLEEPQ;
        } else {
            thread->flags &= ~_PR_ON_PAUSEQ;
        }
        PR_REMOVE_LINK(&thread->links);
    } else 
        PR_ASSERT(0);
}
static void _PR_DestroyThread ( PRThread thread) [static]

Definition at line 341 of file pruthr.c.

{
    _PR_MD_FREE_LOCK(&thread->threadLock);
    PR_DELETE(thread);
}

Here is the caller graph for this function:

static void _PR_InitializeNativeStack ( PRThreadStack ts) [static]

Definition at line 208 of file pruthr.c.

{
    if( ts && (ts->stackTop == 0) ) {
        ts->allocSize = ts->stackSize;

        /*
        ** Setup stackTop and stackBottom values.
        */
#ifdef HAVE_STACK_GROWING_UP
    ts->allocBase = (char*) ((((long)&ts) >> _pr_pageShift)
                  << _pr_pageShift);
        ts->stackBottom = ts->allocBase + ts->stackSize;
        ts->stackTop = ts->allocBase;
#else
        ts->allocBase = (char*) ((((long)&ts + _pr_pageSize - 1)
                >> _pr_pageShift) << _pr_pageShift);
        ts->stackTop    = ts->allocBase;
        ts->stackBottom = ts->allocBase - ts->stackSize;
#endif
    }
}

Here is the caller graph for this function:

static void _PR_InitializeRecycledThread ( PRThread thread) [static]

Definition at line 265 of file pruthr.c.

{
    /*
     * Assert that the following data members are already zeroed
     * by _PR_CleanupThread().
     */
#ifdef DEBUG
    if (thread->privateData) {
        unsigned int i;
        for (i = 0; i < thread->tpdLength; i++) {
            PR_ASSERT(thread->privateData[i] == NULL);
        }
    }
#endif
    PR_ASSERT(thread->dumpArg == 0 && thread->dump == 0);
    PR_ASSERT(thread->errorString == 0 && thread->errorStringSize == 0);
    PR_ASSERT(thread->errorStringLength == 0);

    /* Reset data members in thread structure */
    thread->errorCode = thread->osErrorCode = 0;
    thread->io_pending = thread->io_suspended = PR_FALSE;
    thread->environment = 0;
    PR_INIT_CLIST(&thread->lockList);
}

Here is the caller graph for this function:

void _PR_InitThreads ( PRThreadType  type,
PRThreadPriority  priority,
PRUintn  maxPTDs 
)

Definition at line 98 of file pruthr.c.

{
#if defined(XP_MAC)
#pragma unused (maxPTDs)
#endif

    PRThread *thread;
    PRThreadStack *stack;

    _pr_terminationCVLock = PR_NewLock();
    _pr_activeLock = PR_NewLock();

#ifndef HAVE_CUSTOM_USER_THREADS
    stack = PR_NEWZAP(PRThreadStack);
#ifdef HAVE_STACK_GROWING_UP
    stack->stackTop = (char*) ((((long)&type) >> _pr_pageShift)
                  << _pr_pageShift);
#else
#if defined(SOLARIS) || defined (UNIXWARE) && defined (USR_SVR4_THREADS)
    stack->stackTop = (char*) &thread;
#elif defined(XP_MAC)
    stack->stackTop = (char*) LMGetCurStackBase();
#else
    stack->stackTop = (char*) ((((long)&type + _pr_pageSize - 1)
                >> _pr_pageShift) << _pr_pageShift);
#endif
#endif
#else
    /* If stack is NULL, we're using custom user threads like NT fibers. */
    stack = PR_NEWZAP(PRThreadStack);
    if (stack) {
        stack->stackSize = 0;
        _PR_InitializeNativeStack(stack);
    }
#endif /* HAVE_CUSTOM_USER_THREADS */

    thread = _PR_AttachThread(type, priority, stack);
    if (thread) {
        _PR_MD_SET_CURRENT_THREAD(thread);

        if (type == PR_SYSTEM_THREAD) {
            thread->flags = _PR_SYSTEM;
            _pr_systemActive++;
            _pr_primordialExitCount = 0;
        } else {
            _pr_userActive++;
            _pr_primordialExitCount = 1;
        }
    thread->no_sched = 1;
    _pr_primordialExitCVar = PR_NewCondVar(_pr_activeLock);
    }

    if (!thread) PR_Abort();
#ifdef _PR_LOCAL_THREADS_ONLY
    thread->flags |= _PR_PRIMORDIAL;
#else
    thread->flags |= _PR_PRIMORDIAL | _PR_GLOBAL_SCOPE;
#endif

    /*
     * Needs _PR_PRIMORDIAL flag set before calling
     * _PR_MD_INIT_THREAD()
     */
    if (_PR_MD_INIT_THREAD(thread) == PR_FAILURE) {
        /*
         * XXX do what?
         */
    }

    if (_PR_IS_NATIVE_THREAD(thread)) {
        PR_APPEND_LINK(&thread->active, &_PR_ACTIVE_GLOBAL_THREADQ());
        _pr_global_threads++;
    } else {
        PR_APPEND_LINK(&thread->active, &_PR_ACTIVE_LOCAL_THREADQ());
        _pr_local_threads++;
    }

    _pr_recycleThreads = 0;
    _pr_deadQLock = PR_NewLock();
    _pr_numNativeDead = 0;
    _pr_numUserDead = 0;
    PR_INIT_CLIST(&_pr_deadNativeQ);
    PR_INIT_CLIST(&_pr_deadUserQ);
}

Here is the call graph for this function:

Here is the caller graph for this function:

_PR_NativeCreateThread ( PRThreadType  type,
void(*)(void *arg start,
void arg,
PRThreadPriority  priority,
PRThreadScope  scope,
PRThreadState  state,
PRUint32  stackSize,
PRUint32  flags 
)

Definition at line 1041 of file pruthr.c.

{
#if defined(XP_MAC)
#pragma unused (scope)
#endif

    PRThread *thread;

    thread = _PR_AttachThread(type, priority, NULL);

    if (thread) {
        PR_Lock(_pr_activeLock);
        thread->flags = (flags | _PR_GLOBAL_SCOPE);
        thread->id = ++_pr_utid;
        if (type == PR_SYSTEM_THREAD) {
            thread->flags |= _PR_SYSTEM;
            _pr_systemActive++;
        } else {
            _pr_userActive++;
        }
        PR_Unlock(_pr_activeLock);

        thread->stack = PR_NEWZAP(PRThreadStack);
        if (!thread->stack) {
            PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
            goto done;
        }
        thread->stack->stackSize = stackSize?stackSize:_MD_DEFAULT_STACK_SIZE;
        thread->stack->thr = thread;
        thread->startFunc = start;
        thread->arg = arg;

        /* 
          Set thread flags related to scope and joinable state. If joinable
          thread, allocate a "termination" conidition variable.
         */
        if (state == PR_JOINABLE_THREAD) {
            thread->term = PR_NewCondVar(_pr_terminationCVLock);
        if (thread->term == NULL) {
        PR_DELETE(thread->stack);
        goto done;
        }
        }

    thread->state = _PR_RUNNING;
        if (_PR_MD_CREATE_THREAD(thread, _PR_NativeRunThread, priority,
            scope,state,stackSize) == PR_SUCCESS) {
            return thread;
        }
        if (thread->term) {
            PR_DestroyCondVar(thread->term);
            thread->term = NULL;
        }
    PR_DELETE(thread->stack);
    }

done:
    if (thread) {
    _PR_DecrActiveThreadCount(thread);
        _PR_DestroyThread(thread);
    }
    return NULL;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 348 of file pruthr.c.

{
    if(thread->term) {
        PR_DestroyCondVar(thread->term);
        thread->term = 0;
    }
    if (NULL != thread->privateData) {
        PR_ASSERT(0 != thread->tpdLength);
        PR_DELETE(thread->privateData);
        thread->tpdLength = 0;
    }
    PR_DELETE(thread->stack);
    _PR_DestroyThread(thread);
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 405 of file pruthr.c.

{
    PRThread *thread = (PRThread *)arg;

    _PR_MD_SET_CURRENT_THREAD(thread);

    _PR_MD_SET_CURRENT_CPU(NULL);

    /* Set up the thread stack information */
    _PR_InitializeNativeStack(thread->stack);

    /* Set up the thread md information */
    if (_PR_MD_INIT_THREAD(thread) == PR_FAILURE) {
        /*
         * thread failed to initialize itself, possibly due to
         * failure to allocate per-thread resources
         */
        return;
    }

    while(1) {
        thread->state = _PR_RUNNING;

        /*
         * Add to list of active threads
         */
        PR_Lock(_pr_activeLock);
        PR_APPEND_LINK(&thread->active, &_PR_ACTIVE_GLOBAL_THREADQ());
        _pr_global_threads++;
        PR_Unlock(_pr_activeLock);

        (*thread->startFunc)(thread->arg);

        /*
         * The following two assertions are meant for NT asynch io.
         *
         * The thread should have no asynch io in progress when it
         * exits, otherwise the overlapped buffer, which is part of
         * the thread structure, would become invalid.
         */
        PR_ASSERT(thread->io_pending == PR_FALSE);
        /*
         * This assertion enforces the programming guideline that
         * if an io function times out or is interrupted, the thread
         * should close the fd to force the asynch io to abort
         * before it exits.  Right now, closing the fd is the only
         * way to clear the io_suspended flag.
         */
        PR_ASSERT(thread->io_suspended == PR_FALSE);

        /*
         * remove thread from list of active threads
         */
        PR_Lock(_pr_activeLock);
        PR_REMOVE_LINK(&thread->active);
        _pr_global_threads--;
        PR_Unlock(_pr_activeLock);

        PR_LOG(_pr_thread_lm, PR_LOG_MIN, ("thread exiting"));

        /* All done, time to go away */
        _PR_CleanupThread(thread);

        _PR_NotifyJoinWaiters(thread);

        _PR_DecrActiveThreadCount(thread);

        thread->state = _PR_DEAD_STATE;

        if (!_pr_recycleThreads || (_PR_RecycleThread(thread) ==
                        PR_FAILURE)) {
            /*
             * thread not recycled
             * platform-specific thread exit processing
             *        - for stuff like releasing native-thread resources, etc.
             */
            _PR_MD_EXIT_THREAD(thread);
            /*
             * Free memory allocated for the thread
             */
            _PR_NativeDestroyThread(thread);
            /*
             * thread gone, cannot de-reference thread now
             */
            return;
        }

        /* Now wait for someone to activate us again... */
        _PR_MD_WAIT(thread, PR_INTERVAL_NO_TIMEOUT);
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 230 of file pruthr.c.

{
    /*
    ** Handle joinable threads.  Change the state to waiting for join.
    ** Remove from our run Q and put it on global waiting to join Q.
    ** Notify on our "termination" condition variable so that joining
    ** thread will know about our termination.  Switch our context and
    ** come back later on to continue the cleanup.
    */    
    PR_ASSERT(thread == _PR_MD_CURRENT_THREAD());
    if (thread->term != NULL) {
        PR_Lock(_pr_terminationCVLock);
        _PR_THREAD_LOCK(thread);
        thread->state = _PR_JOIN_WAIT;
        if ( !_PR_IS_NATIVE_THREAD(thread) ) {
            _PR_MISCQ_LOCK(thread->cpu);
            _PR_ADD_JOINQ(thread, thread->cpu);
            _PR_MISCQ_UNLOCK(thread->cpu);
        }
        _PR_THREAD_UNLOCK(thread);
        PR_NotifyCondVar(thread->term);
        PR_Unlock(_pr_terminationCVLock);
        _PR_MD_WAIT(thread, PR_INTERVAL_NO_TIMEOUT);
        PR_ASSERT(thread->state != _PR_JOIN_WAIT);
    }

}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 290 of file pruthr.c.

Here is the caller graph for this function:

static void _PR_Resume ( PRThread thread) [static]

Definition at line 707 of file pruthr.c.

{
    PRThreadPriority pri;
    PRIntn is;
    PRThread *me = _PR_MD_CURRENT_THREAD();

    if (!_PR_IS_NATIVE_THREAD(me))
    _PR_INTSOFF(is);
    _PR_THREAD_LOCK(thread);
    switch (thread->state) {
      case _PR_SUSPENDED:
        thread->state = _PR_RUNNABLE;
        thread->flags &= ~_PR_SUSPENDING;
        if (!_PR_IS_NATIVE_THREAD(thread)) {
            _PR_MISCQ_LOCK(thread->cpu);
            _PR_DEL_SUSPENDQ(thread);
            _PR_MISCQ_UNLOCK(thread->cpu);

            pri = thread->priority;

            _PR_RUNQ_LOCK(thread->cpu);
            _PR_ADD_RUNQ(thread, thread->cpu, pri);
            _PR_RUNQ_UNLOCK(thread->cpu);

            if (pri > _PR_MD_CURRENT_THREAD()->priority) {
                if (!_PR_IS_NATIVE_THREAD(me))
                    _PR_SET_RESCHED_FLAG();
            }
        } else {
            PR_ASSERT(0);
        }
        break;

      case _PR_IO_WAIT:
      case _PR_COND_WAIT:
        thread->flags &= ~_PR_SUSPENDING;
/*      PR_ASSERT(thread->wait.monitor->stickyCount == 0); */
        break;

      case _PR_LOCK_WAIT: 
      {
        PRLock *wLock = thread->wait.lock;

        thread->flags &= ~_PR_SUSPENDING;
 
        _PR_LOCK_LOCK(wLock);
        if (thread->wait.lock->owner == 0) {
            _PR_UnblockLockWaiter(thread->wait.lock);
        }
        _PR_LOCK_UNLOCK(wLock);
        break;
      }
      case _PR_RUNNABLE:
        break;
      case _PR_RUNNING:
        /*
         * The thread being suspended should be a LOCAL thread with
         * _pr_numCPUs == 1. Hence, the thread cannot be in RUNNING state
         */
        PR_ASSERT(0);
        break;

      default:
    /*
     * thread should have been in one of the above-listed blocked states
     * (_PR_JOIN_WAIT, _PR_IO_WAIT, _PR_UNBORN, _PR_DEAD_STATE)
     */
        PR_Abort();
    }
    _PR_THREAD_UNLOCK(thread);
    if (!_PR_IS_NATIVE_THREAD(me))
        _PR_INTSON(is);

}

Here is the call graph for this function:

Definition at line 865 of file pruthr.c.

{
    PRThread *thread, *me = _PR_MD_CURRENT_THREAD();
    _PRCPU *cpu = _PR_MD_CURRENT_CPU();
    PRIntn pri;
    PRUint32 r;
    PRCList *qp;
    PRIntn priMin, priMax;
#if !defined(_PR_LOCAL_THREADS_ONLY) && defined(XP_UNIX)
    PRBool wakeup_cpus;
#endif

    /* Interrupts must be disabled */
    PR_ASSERT(_PR_IS_NATIVE_THREAD(me) || _PR_MD_GET_INTSOFF() != 0);

    /* Since we are rescheduling, we no longer want to */
    _PR_CLEAR_RESCHED_FLAG();

    /*
    ** Find highest priority thread to run. Bigger priority numbers are
    ** higher priority threads
    */
    _PR_RUNQ_LOCK(cpu);
    /*
     *  if we are in SuspendAll mode, can schedule only the thread
     *    that called PR_SuspendAll
     *
     *  The thread may be ready to run now, after completing an I/O
     *  operation, for example
     */
    if ((thread = suspendAllThread) != 0) {
    if ((!(thread->no_sched)) && (thread->state == _PR_RUNNABLE)) {
            /* Pull thread off of its run queue */
            _PR_DEL_RUNQ(thread);
            _PR_RUNQ_UNLOCK(cpu);
            goto found_thread;
    } else {
            thread = NULL;
            _PR_RUNQ_UNLOCK(cpu);
            goto idle_thread;
    }
    }
    r = _PR_RUNQREADYMASK(cpu);
    if (r==0) {
        priMin = priMax = PR_PRIORITY_FIRST;
    } else if (r == (1<<PR_PRIORITY_NORMAL) ) {
        priMin = priMax = PR_PRIORITY_NORMAL;
    } else {
        priMin = PR_PRIORITY_FIRST;
        priMax = PR_PRIORITY_LAST;
    }
    thread = NULL;
    for (pri = priMax; pri >= priMin ; pri-- ) {
    if (r & (1 << pri)) {
            for (qp = _PR_RUNQ(cpu)[pri].next; 
                 qp != &_PR_RUNQ(cpu)[pri];
                 qp = qp->next) {
                thread = _PR_THREAD_PTR(qp);
                /*
                * skip non-schedulable threads
                */
#if !defined(XP_MAC)
                PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD));
#endif
                if ((thread->no_sched) && (me != thread)){
                    thread = NULL;
                    continue;
                } else {
                    /* Pull thread off of its run queue */
                    _PR_DEL_RUNQ(thread);
                    _PR_RUNQ_UNLOCK(cpu);
                    goto found_thread;
                }
            }
        }
        thread = NULL;
    }
    _PR_RUNQ_UNLOCK(cpu);

#if !defined(_PR_LOCAL_THREADS_ONLY) && defined(XP_UNIX)

    wakeup_cpus = PR_FALSE;
    _PR_CPU_LIST_LOCK();
    for (qp = _PR_CPUQ().next; qp != &_PR_CPUQ(); qp = qp->next) {
        if (cpu != _PR_CPU_PTR(qp)) {
            if ((thread = get_thread(_PR_CPU_PTR(qp), &wakeup_cpus))
                                        != NULL) {
                thread->cpu = cpu;
                _PR_CPU_LIST_UNLOCK();
                if (wakeup_cpus == PR_TRUE)
                    _PR_MD_WAKEUP_CPUS();
                goto found_thread;
            }
        }
    }
    _PR_CPU_LIST_UNLOCK();
    if (wakeup_cpus == PR_TRUE)
        _PR_MD_WAKEUP_CPUS();

#endif        /* _PR_LOCAL_THREADS_ONLY */

idle_thread:
   /*
    ** There are no threads to run. Switch to the idle thread
    */
    PR_LOG(_pr_sched_lm, PR_LOG_MAX, ("pausing"));
    thread = _PR_MD_CURRENT_CPU()->idle_thread;

found_thread:
    PR_ASSERT((me == thread) || ((thread->state == _PR_RUNNABLE) &&
                    (!(thread->no_sched))));

    /* Resume the thread */
    PR_LOG(_pr_sched_lm, PR_LOG_MAX,
       ("switching to %d[%p]", thread->id, thread));
    PR_ASSERT(thread->state != _PR_RUNNING);
    thread->state = _PR_RUNNING;
 
    /* If we are on the runq, it just means that we went to sleep on some
     * resource, and by the time we got here another real native thread had
     * already given us the resource and put us back on the runqueue 
     */
       PR_ASSERT(thread->cpu == _PR_MD_CURRENT_CPU());
    if (thread != me) 
        _PR_MD_RESTORE_CONTEXT(thread);
#if 0
    /* XXXMB; with setjmp/longjmp it is impossible to land here, but 
     * it is not with fibers... Is this a bad thing?  I believe it is 
     * still safe.
     */
    PR_NOT_REACHED("impossible return from schedule");
#endif
}

Here is the call graph for this function:

Definition at line 589 of file pruthr.c.

{
    PRThread *me = _PR_MD_CURRENT_THREAD();
    PRIntn is;

    if ( _PR_IS_NATIVE_THREAD(thread) ) {
        _PR_MD_SET_PRIORITY(&(thread->md), newPri);
        return;
    }

    if (!_PR_IS_NATIVE_THREAD(me))
    _PR_INTSOFF(is);
    _PR_THREAD_LOCK(thread);
    if (newPri != thread->priority) {
    _PRCPU *cpu = thread->cpu;

    switch (thread->state) {
      case _PR_RUNNING:
        /* Change my priority */

            _PR_RUNQ_LOCK(cpu);
        thread->priority = newPri;
        if (_PR_RUNQREADYMASK(cpu) >> (newPri + 1)) {
            if (!_PR_IS_NATIVE_THREAD(me))
                    _PR_SET_RESCHED_FLAG();
        }
            _PR_RUNQ_UNLOCK(cpu);
        break;

      case _PR_RUNNABLE:

        _PR_RUNQ_LOCK(cpu);
            /* Move to different runQ */
            _PR_DEL_RUNQ(thread);
            thread->priority = newPri;
            PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD));
            _PR_ADD_RUNQ(thread, cpu, newPri);
        _PR_RUNQ_UNLOCK(cpu);

            if (newPri > me->priority) {
            if (!_PR_IS_NATIVE_THREAD(me))
                    _PR_SET_RESCHED_FLAG();
            }

        break;

      case _PR_LOCK_WAIT:
      case _PR_COND_WAIT:
      case _PR_IO_WAIT:
      case _PR_SUSPENDED:

        thread->priority = newPri;
        break;
    }
    }
    _PR_THREAD_UNLOCK(thread);
    if (!_PR_IS_NATIVE_THREAD(me))
    _PR_INTSON(is);
}

Here is the caller graph for this function:

static void _PR_Suspend ( PRThread thread) [static]

Definition at line 652 of file pruthr.c.

{
    PRIntn is;
    PRThread *me = _PR_MD_CURRENT_THREAD();

    PR_ASSERT(thread != me);
    PR_ASSERT(!_PR_IS_NATIVE_THREAD(thread) || (!thread->cpu));

    if (!_PR_IS_NATIVE_THREAD(me))
        _PR_INTSOFF(is);
    _PR_THREAD_LOCK(thread);
    switch (thread->state) {
      case _PR_RUNNABLE:
        if (!_PR_IS_NATIVE_THREAD(thread)) {
            _PR_RUNQ_LOCK(thread->cpu);
            _PR_DEL_RUNQ(thread);
            _PR_RUNQ_UNLOCK(thread->cpu);

            _PR_MISCQ_LOCK(thread->cpu);
            _PR_ADD_SUSPENDQ(thread, thread->cpu);
            _PR_MISCQ_UNLOCK(thread->cpu);
        } else {
            /*
             * Only LOCAL threads are suspended by _PR_Suspend
             */
             PR_ASSERT(0);
        }
        thread->state = _PR_SUSPENDED;
        break;

      case _PR_RUNNING:
        /*
         * The thread being suspended should be a LOCAL thread with
         * _pr_numCPUs == 1. Hence, the thread cannot be in RUNNING state
         */
        PR_ASSERT(0);
        break;

      case _PR_LOCK_WAIT:
      case _PR_IO_WAIT:
      case _PR_COND_WAIT:
        if (_PR_IS_NATIVE_THREAD(thread)) {
            _PR_MD_SUSPEND_THREAD(thread);
    }
        thread->flags |= _PR_SUSPENDING;
        break;

      default:
        PR_Abort();
    }
    _PR_THREAD_UNLOCK(thread);
    if (!_PR_IS_NATIVE_THREAD(me))
    _PR_INTSON(is);
}

Definition at line 364 of file pruthr.c.

{
    if(thread->term) {
        PR_DestroyCondVar(thread->term);
        thread->term = 0;
    }
    if (NULL != thread->privateData) {
        PR_ASSERT(0 != thread->tpdLength);
        PR_DELETE(thread->privateData);
        thread->tpdLength = 0;
    }
    _PR_MD_FREE_LOCK(&thread->threadLock);
    if (thread->threadAllocatedOnStack == 1) {
        _PR_MD_CLEAN_THREAD(thread);
        /*
         *  Because the no_sched field is set, this thread/stack will
         *  will not be re-used until the flag is cleared by the thread
         *  we will context switch to.
         */
        _PR_FreeStack(thread->stack);
    } else {
#ifdef WINNT
        _PR_MD_CLEAN_THREAD(thread);
#else
        /*
         * This assertion does not apply to NT.  On NT, every fiber
         * has its threadAllocatedOnStack equal to 0.  Elsewhere,
         * only the primordial thread has its threadAllocatedOnStack
         * equal to 0.
         */
        PR_ASSERT(thread->flags & _PR_PRIMORDIAL);
#endif
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void _PR_UserRunThread ( void  ) [static]

Definition at line 497 of file pruthr.c.

{
    PRThread *thread = _PR_MD_CURRENT_THREAD();
    PRIntn is;

    if (_MD_LAST_THREAD())
    _MD_LAST_THREAD()->no_sched = 0;

#ifdef HAVE_CUSTOM_USER_THREADS
    if (thread->stack == NULL) {
        thread->stack = PR_NEWZAP(PRThreadStack);
        _PR_InitializeNativeStack(thread->stack);
    }
#endif /* HAVE_CUSTOM_USER_THREADS */

    while(1) {
        /* Run thread main */
        if ( !_PR_IS_NATIVE_THREAD(thread)) _PR_MD_SET_INTSOFF(0);

    /*
     * Add to list of active threads
     */
    if (!(thread->flags & _PR_IDLE_THREAD)) {
        PR_Lock(_pr_activeLock);
        PR_APPEND_LINK(&thread->active, &_PR_ACTIVE_LOCAL_THREADQ());
        _pr_local_threads++;
        PR_Unlock(_pr_activeLock);
    }

        (*thread->startFunc)(thread->arg);

        /*
         * The following two assertions are meant for NT asynch io.
         *
         * The thread should have no asynch io in progress when it
         * exits, otherwise the overlapped buffer, which is part of
         * the thread structure, would become invalid.
         */
        PR_ASSERT(thread->io_pending == PR_FALSE);
        /*
         * This assertion enforces the programming guideline that
         * if an io function times out or is interrupted, the thread
         * should close the fd to force the asynch io to abort
         * before it exits.  Right now, closing the fd is the only
         * way to clear the io_suspended flag.
         */
        PR_ASSERT(thread->io_suspended == PR_FALSE);

        PR_Lock(_pr_activeLock);
    /*
     * remove thread from list of active threads
     */
    if (!(thread->flags & _PR_IDLE_THREAD)) {
           PR_REMOVE_LINK(&thread->active);
        _pr_local_threads--;
    }
    PR_Unlock(_pr_activeLock);
        PR_LOG(_pr_thread_lm, PR_LOG_MIN, ("thread exiting"));

        /* All done, time to go away */
        _PR_CleanupThread(thread);

        _PR_INTSOFF(is);    

        _PR_NotifyJoinWaiters(thread);

    _PR_DecrActiveThreadCount(thread);

        thread->state = _PR_DEAD_STATE;

        if (!_pr_recycleThreads || (_PR_RecycleThread(thread) ==
                        PR_FAILURE)) {
            /*
            ** Destroy the thread resources
            */
        _PR_UserDestroyThread(thread);
        }

        /*
        ** Find another user thread to run. This cpu has finished the
        ** previous threads main and is now ready to run another thread.
        */
        {
            PRInt32 is;
            _PR_INTSOFF(is);
            _PR_MD_SWITCH_CONTEXT(thread);
        }

        /* Will land here when we get scheduled again if we are recycling... */
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

PRThread* _PRI_AttachThread ( PRThreadType  type,
PRThreadPriority  priority,
PRThreadStack stack,
PRUint32  flags 
)

Definition at line 1447 of file pruthr.c.

{
    PRThread *thread;

    if ((thread = _PR_MD_GET_ATTACHED_THREAD()) != NULL) {
        return thread;
    }
    _PR_MD_SET_CURRENT_THREAD(NULL);

    /* Clear out any state if this thread was attached before */
    _PR_MD_SET_CURRENT_CPU(NULL);

    thread = _PR_AttachThread(type, priority, stack);
    if (thread) {
        PRIntn is;

        _PR_MD_SET_CURRENT_THREAD(thread);

        thread->flags = flags | _PR_GLOBAL_SCOPE | _PR_ATTACHED;

        if (!stack) {
            thread->stack = PR_NEWZAP(PRThreadStack);
            if (!thread->stack) {
                _PR_DestroyThread(thread);
                return NULL;
            }
            thread->stack->stackSize = _MD_DEFAULT_STACK_SIZE;
        }
        PR_INIT_CLIST(&thread->links);

        if (_PR_MD_INIT_ATTACHED_THREAD(thread) == PR_FAILURE) {
                PR_DELETE(thread->stack);
                _PR_DestroyThread(thread);
                return NULL;
        }

        _PR_MD_SET_CURRENT_CPU(NULL);

        if (_PR_MD_CURRENT_CPU()) {
            _PR_INTSOFF(is);
            PR_Lock(_pr_activeLock);
        }
        if (type == PR_SYSTEM_THREAD) {
            thread->flags |= _PR_SYSTEM;
            _pr_systemActive++;
        } else {
            _pr_userActive++;
        }
        if (_PR_MD_CURRENT_CPU()) {
            PR_Unlock(_pr_activeLock);
            _PR_INTSON(is);
        }
    }
    return thread;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 1530 of file pruthr.c.

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 1114 of file pruthr.c.

{
    PRThread *me;
    PRThread *thread = NULL;
    PRThreadStack *stack;
    char *top;
    PRIntn is;
    PRIntn native = 0;
    PRIntn useRecycled = 0;
    PRBool status;

    /* 
    First, pin down the priority.  Not all compilers catch passing out of
    range enum here.  If we let bad values thru, priority queues won't work.
    */
    if (priority > PR_PRIORITY_LAST) {
        priority = PR_PRIORITY_LAST;
    } else if (priority < PR_PRIORITY_FIRST) {
        priority = PR_PRIORITY_FIRST;
    }
        
    if (!_pr_initialized) _PR_ImplicitInitialization();

    if (! (flags & _PR_IDLE_THREAD))
        me = _PR_MD_CURRENT_THREAD();

#if    defined(_PR_GLOBAL_THREADS_ONLY)
       /*
        * can create global threads only
        */
    if (scope == PR_LOCAL_THREAD)
       scope = PR_GLOBAL_THREAD;
#endif

       if (_native_threads_only)
              scope = PR_GLOBAL_THREAD;

    native = (((scope == PR_GLOBAL_THREAD)|| (scope == PR_GLOBAL_BOUND_THREAD))
                                                 && _PR_IS_NATIVE_THREAD_SUPPORTED());

    _PR_ADJUST_STACKSIZE(stackSize);

    if (native) {
    /*
     * clear the IDLE_THREAD flag which applies to LOCAL
     * threads only
     */
    flags &= ~_PR_IDLE_THREAD;
        flags |= _PR_GLOBAL_SCOPE;
        if (_PR_NUM_DEADNATIVE > 0) {
            _PR_DEADQ_LOCK;

            if (_PR_NUM_DEADNATIVE == 0) { /* Thread safe check */
                _PR_DEADQ_UNLOCK;
            } else {
                thread = _PR_THREAD_PTR(_PR_DEADNATIVEQ.next);
                PR_REMOVE_LINK(&thread->links);
                _PR_DEC_DEADNATIVE;
                _PR_DEADQ_UNLOCK;

                _PR_InitializeRecycledThread(thread);
                thread->startFunc = start;
                thread->arg = arg;
            thread->flags = (flags | _PR_GLOBAL_SCOPE);
            if (type == PR_SYSTEM_THREAD)
            {
                thread->flags |= _PR_SYSTEM;
                PR_AtomicIncrement(&_pr_systemActive);
            }
            else PR_AtomicIncrement(&_pr_userActive);

            if (state == PR_JOINABLE_THREAD) {
                if (!thread->term) 
                       thread->term = PR_NewCondVar(_pr_terminationCVLock);
            }
        else {
                if(thread->term) {
                    PR_DestroyCondVar(thread->term);
                        thread->term = 0;
            }
            }

                thread->priority = priority;
        _PR_MD_SET_PRIORITY(&(thread->md), priority);
        /* XXX what about stackSize? */
        thread->state = _PR_RUNNING;
                _PR_MD_WAKEUP_WAITER(thread);
        return thread;
            }
        }
        thread = _PR_NativeCreateThread(type, start, arg, priority, 
                                            scope, state, stackSize, flags);
    } else {
        if (_PR_NUM_DEADUSER > 0) {
            _PR_DEADQ_LOCK;

            if (_PR_NUM_DEADUSER == 0) {  /* thread safe check */
                _PR_DEADQ_UNLOCK;
            } else {
                PRCList *ptr;

                /* Go down list checking for a recycled thread with a 
                 * large enough stack.  XXXMB - this has a bad degenerate case.
                 */
                ptr = _PR_DEADUSERQ.next;
                while( ptr != &_PR_DEADUSERQ ) {
                    thread = _PR_THREAD_PTR(ptr);
                    if ((thread->stack->stackSize >= stackSize) &&
                (!thread->no_sched)) {
                        PR_REMOVE_LINK(&thread->links);
                        _PR_DEC_DEADUSER;
                        break;
                    } else {
                        ptr = ptr->next;
                        thread = NULL;
                    }
                } 

                _PR_DEADQ_UNLOCK;

               if (thread) {
                    _PR_InitializeRecycledThread(thread);
                    thread->startFunc = start;
                    thread->arg = arg;
                    thread->priority = priority;
            if (state == PR_JOINABLE_THREAD) {
            if (!thread->term) 
               thread->term = PR_NewCondVar(_pr_terminationCVLock);
            } else {
            if(thread->term) {
               PR_DestroyCondVar(thread->term);
                thread->term = 0;
            }
            }
                    useRecycled++;
                }
            }
        } 
        if (thread == NULL) {
#ifndef HAVE_CUSTOM_USER_THREADS
            stack = _PR_NewStack(stackSize);
            if (!stack) {
                PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
                return NULL;
            }

            /* Allocate thread object and per-thread data off the top of the stack*/
            top = stack->stackTop;
#ifdef HAVE_STACK_GROWING_UP
            thread = (PRThread*) top;
            top = top + sizeof(PRThread);
            /*
             * Make stack 64-byte aligned
             */
            if ((PRUptrdiff)top & 0x3f) {
                top = (char*)(((PRUptrdiff)top + 0x40) & ~0x3f);
            }
#else
            top = top - sizeof(PRThread);
            thread = (PRThread*) top;
            /*
             * Make stack 64-byte aligned
             */
            if ((PRUptrdiff)top & 0x3f) {
                top = (char*)((PRUptrdiff)top & ~0x3f);
            }
#endif
#if defined(GC_LEAK_DETECTOR)
            /*
             * sorry, it is not safe to allocate the thread on the stack,
             * because we assign to this object before the GC can learn
             * about this thread. we'll just leak thread objects instead.
             */
            thread = PR_NEW(PRThread);
#endif
            stack->thr = thread;
            memset(thread, 0, sizeof(PRThread));
            thread->threadAllocatedOnStack = 1;
#else
            thread = _PR_MD_CREATE_USER_THREAD(stackSize, start, arg);
            if (!thread) {
                PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
                return NULL;
            }
            thread->threadAllocatedOnStack = 0;
            stack = NULL;
            top = NULL;
#endif

            /* Initialize thread */
            thread->tpdLength = 0;
            thread->privateData = NULL;
            thread->stack = stack;
            thread->priority = priority;
            thread->startFunc = start;
            thread->arg = arg;
            PR_INIT_CLIST(&thread->lockList);

            if (_PR_MD_INIT_THREAD(thread) == PR_FAILURE) {
                if (thread->threadAllocatedOnStack == 1)
                    _PR_FreeStack(thread->stack);
                else {
                    PR_DELETE(thread);
                }
                PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
                return NULL;
            }

            if (_PR_MD_NEW_LOCK(&thread->threadLock) == PR_FAILURE) {
                if (thread->threadAllocatedOnStack == 1)
                    _PR_FreeStack(thread->stack);
                else {
                    PR_DELETE(thread->privateData);
                    PR_DELETE(thread);
                }
                PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
                return NULL;
            }

            _PR_MD_INIT_CONTEXT(thread, top, _PR_UserRunThread, &status);

            if (status == PR_FALSE) {
                _PR_MD_FREE_LOCK(&thread->threadLock);
                if (thread->threadAllocatedOnStack == 1)
                    _PR_FreeStack(thread->stack);
                else {
                    PR_DELETE(thread->privateData);
                    PR_DELETE(thread);
                }
                return NULL;
            }

            /* 
              Set thread flags related to scope and joinable state. If joinable
              thread, allocate a "termination" condition variable.
            */
            if (state == PR_JOINABLE_THREAD) {
                thread->term = PR_NewCondVar(_pr_terminationCVLock);
                if (thread->term == NULL) {
                    _PR_MD_FREE_LOCK(&thread->threadLock);
                    if (thread->threadAllocatedOnStack == 1)
                        _PR_FreeStack(thread->stack);
                    else {
                        PR_DELETE(thread->privateData);
                        PR_DELETE(thread);
                    }
                    return NULL;
                }
            }
  
        }
  
        /* Update thread type counter */
        PR_Lock(_pr_activeLock);
        thread->flags = flags;
        thread->id = ++_pr_utid;
        if (type == PR_SYSTEM_THREAD) {
            thread->flags |= _PR_SYSTEM;
            _pr_systemActive++;
        } else {
            _pr_userActive++;
        }

        /* Make thread runnable */
        thread->state = _PR_RUNNABLE;
    /*
     * Add to list of active threads
     */
        PR_Unlock(_pr_activeLock);

        if ((! (thread->flags & _PR_IDLE_THREAD)) && _PR_IS_NATIVE_THREAD(me) )
            thread->cpu = _PR_GetPrimordialCPU();
        else
            thread->cpu = _PR_MD_CURRENT_CPU();

        PR_ASSERT(!_PR_IS_NATIVE_THREAD(thread));

        if ((! (thread->flags & _PR_IDLE_THREAD)) && !_PR_IS_NATIVE_THREAD(me)) {
            _PR_INTSOFF(is);
            _PR_RUNQ_LOCK(thread->cpu);
            _PR_ADD_RUNQ(thread, thread->cpu, priority);
            _PR_RUNQ_UNLOCK(thread->cpu);
        }

        if (thread->flags & _PR_IDLE_THREAD) {
            /*
            ** If the creating thread is a kernel thread, we need to
            ** awaken the user thread idle thread somehow; potentially
            ** it could be sleeping in its idle loop, and we need to poke
            ** it.  To do so, wake the idle thread...  
            */
            _PR_MD_WAKEUP_WAITER(NULL);
        } else if (_PR_IS_NATIVE_THREAD(me)) {
            _PR_MD_WAKEUP_WAITER(thread);
        }
        if ((! (thread->flags & _PR_IDLE_THREAD)) && !_PR_IS_NATIVE_THREAD(me) )
            _PR_INTSON(is);
    }

    return thread;
}

Here is the call graph for this function:

Definition at line 1513 of file pruthr.c.

{
    /*
     * On IRIX, Solaris, and Windows, foreign threads are detached when
     * they terminate.
     */
#if !defined(IRIX) && !defined(WIN32) \
        && !(defined(SOLARIS) && defined(_PR_GLOBAL_THREADS_ONLY))
    PRThread *me;
    if (_pr_initialized) {
        me = _PR_MD_GET_ATTACHED_THREAD();
        if ((me != NULL) && (me->flags & _PR_ATTACHED))
            _PRI_DetachThread();
    }
#endif
}

Here is the call graph for this function:

Definition at line 1568 of file pruthr.c.

{
    PRIntn is;
    PRCondVar *term;
    PRThread *me = _PR_MD_CURRENT_THREAD();

    if (!_PR_IS_NATIVE_THREAD(me))
        _PR_INTSOFF(is);
    term = thread->term;
    /* can't join a non-joinable thread */
    if (term == NULL) {
        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
        goto ErrorExit;
    }

    /* multiple threads can't wait on the same joinable thread */
    if (term->condQ.next != &term->condQ) {
        goto ErrorExit;
    }
    if (!_PR_IS_NATIVE_THREAD(me))
        _PR_INTSON(is);

    /* wait for the target thread's termination cv invariant */
    PR_Lock (_pr_terminationCVLock);
    while (thread->state != _PR_JOIN_WAIT) {
        (void) PR_WaitCondVar(term, PR_INTERVAL_NO_TIMEOUT);
    }
    (void) PR_Unlock (_pr_terminationCVLock);
    
    /* 
     Remove target thread from global waiting to join Q; make it runnable
     again and put it back on its run Q.  When it gets scheduled later in
     _PR_RunThread code, it will clean up its stack.
    */    
    if (!_PR_IS_NATIVE_THREAD(me))
        _PR_INTSOFF(is);
    thread->state = _PR_RUNNABLE;
    if ( !_PR_IS_NATIVE_THREAD(thread) ) {
        _PR_THREAD_LOCK(thread);

        _PR_MISCQ_LOCK(thread->cpu);
        _PR_DEL_JOINQ(thread);
        _PR_MISCQ_UNLOCK(thread->cpu);

        _PR_AddThreadToRunQ(me, thread);
        _PR_THREAD_UNLOCK(thread);
    }
    if (!_PR_IS_NATIVE_THREAD(me))
        _PR_INTSON(is);

    _PR_MD_WAKEUP_WAITER(thread);

    return PR_SUCCESS;

ErrorExit:
    if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSON(is);
    return PR_FAILURE;   
}

Here is the call graph for this function:


Variable Documentation

Definition at line 62 of file prinit.c.

Definition at line 60 of file prinit.c.

Definition at line 57 of file pruthr.c.

PRCList _pr_deadNativeQ

Definition at line 78 of file pruthr.c.

Definition at line 75 of file pruthr.c.

PRCList _pr_deadUserQ

Definition at line 79 of file pruthr.c.

Definition at line 84 of file pruthr.c.

Definition at line 81 of file pruthr.c.

Definition at line 83 of file pruthr.c.

Definition at line 76 of file pruthr.c.

Definition at line 77 of file pruthr.c.

Definition at line 58 of file pruthr.c.

Definition at line 70 of file pruthr.c.

Definition at line 86 of file pruthr.c.

Definition at line 87 of file pruthr.c.