Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(403)

Unified Diff: nspr/pr/src/threads/combined/pruthr.c

Issue 2078763002: Delete bundled copy of NSS and replace with README. (Closed) Base URL: https://chromium.googlesource.com/chromium/deps/nss@master
Patch Set: Delete bundled copy of NSS and replace with README. Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « nspr/pr/src/threads/combined/prustack.c ('k') | nspr/pr/src/threads/prcmon.c » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: nspr/pr/src/threads/combined/pruthr.c
diff --git a/nspr/pr/src/threads/combined/pruthr.c b/nspr/pr/src/threads/combined/pruthr.c
deleted file mode 100644
index 4625ab2466e84146b79666029f8e73c91b465345..0000000000000000000000000000000000000000
--- a/nspr/pr/src/threads/combined/pruthr.c
+++ /dev/null
@@ -1,1889 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "primpl.h"
-#include <signal.h>
-#include <string.h>
-
-#if defined(WIN95)
-/*
-** Some local variables report warnings on Win95 because the code paths
-** using them are conditioned on HAVE_CUSTOME_USER_THREADS.
-** The pragma suppresses the warning.
-**
-*/
-#pragma warning(disable : 4101)
-#endif
-
-/* _pr_activeLock protects the following global variables */
-PRLock *_pr_activeLock;
-PRInt32 _pr_primordialExitCount; /* In PR_Cleanup(), the primordial thread
- * waits until all other user (non-system)
- * threads have terminated before it exits.
- * So whenever we decrement _pr_userActive,
- * it is compared with
- * _pr_primordialExitCount.
- * If the primordial thread is a system
- * thread, then _pr_primordialExitCount
- * is 0. If the primordial thread is
- * itself a user thread, then
- * _pr_primordialThread is 1.
- */
-PRCondVar *_pr_primordialExitCVar; /* When _pr_userActive is decremented to
- * _pr_primordialExitCount, this condition
- * variable is notified.
- */
-
-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;
-PRThread *suspendAllThread = NULL;
-
-extern PRCList _pr_active_global_threadQ;
-extern PRCList _pr_active_local_threadQ;
-
-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)
-{
- PRThread *thread;
- PRThreadStack *stack;
-
- PR_ASSERT(priority == PR_PRIORITY_NORMAL);
-
- _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*) ((((PRWord)&type) >> _pr_pageShift)
- << _pr_pageShift);
-#else
-#if defined(SOLARIS) || defined (UNIXWARE) && defined (USR_SVR4_THREADS)
- stack->stackTop = (char*) &thread;
-#else
- stack->stackTop = (char*) ((((PRWord)&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);
-}
-
-void _PR_CleanupThreads(void)
-{
- if (_pr_terminationCVLock) {
- PR_DestroyLock(_pr_terminationCVLock);
- _pr_terminationCVLock = NULL;
- }
- if (_pr_activeLock) {
- PR_DestroyLock(_pr_activeLock);
- _pr_activeLock = NULL;
- }
- if (_pr_primordialExitCVar) {
- PR_DestroyCondVar(_pr_primordialExitCVar);
- _pr_primordialExitCVar = NULL;
- }
- /* TODO _pr_dead{Native,User}Q need to be deleted */
- if (_pr_deadQLock) {
- PR_DestroyLock(_pr_deadQLock);
- _pr_deadQLock = NULL;
- }
-}
-
-/*
-** Initialize a stack for a native thread
-*/
-static void _PR_InitializeNativeStack(PRThreadStack *ts)
-{
- if( ts && (ts->stackTop == 0) ) {
- ts->allocSize = ts->stackSize;
-
- /*
- ** Setup stackTop and stackBottom values.
- */
-#ifdef HAVE_STACK_GROWING_UP
- ts->allocBase = (char*) ((((PRWord)&ts) >> _pr_pageShift)
- << _pr_pageShift);
- ts->stackBottom = ts->allocBase + ts->stackSize;
- ts->stackTop = ts->allocBase;
-#else
- ts->allocBase = (char*) ((((PRWord)&ts + _pr_pageSize - 1)
- >> _pr_pageShift) << _pr_pageShift);
- ts->stackTop = ts->allocBase;
- ts->stackBottom = ts->allocBase - ts->stackSize;
-#endif
- }
-}
-
-void _PR_NotifyJoinWaiters(PRThread *thread)
-{
- /*
- ** 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);
- }
-
-}
-
-/*
- * Zero some of the data members of a recycled thread.
- *
- * Note that we can do this either when a dead thread is added to
- * the dead thread queue or when it is reused. Here, we are doing
- * this lazily, when the thread is reused in _PR_CreateThread().
- */
-static void _PR_InitializeRecycledThread(PRThread *thread)
-{
- /*
- * 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);
- PR_ASSERT(thread->name == 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);
-}
-
-PRStatus _PR_RecycleThread(PRThread *thread)
-{
- if ( _PR_IS_NATIVE_THREAD(thread) &&
- _PR_NUM_DEADNATIVE < _pr_recycleThreads) {
- _PR_DEADQ_LOCK;
- PR_APPEND_LINK(&thread->links, &_PR_DEADNATIVEQ);
- _PR_INC_DEADNATIVE;
- _PR_DEADQ_UNLOCK;
- return (PR_SUCCESS);
- } else if ( !_PR_IS_NATIVE_THREAD(thread) &&
- _PR_NUM_DEADUSER < _pr_recycleThreads) {
- _PR_DEADQ_LOCK;
- PR_APPEND_LINK(&thread->links, &_PR_DEADUSERQ);
- _PR_INC_DEADUSER;
- _PR_DEADQ_UNLOCK;
- return (PR_SUCCESS);
- }
- return (PR_FAILURE);
-}
-
-/*
- * Decrement the active thread count, either _pr_systemActive or
- * _pr_userActive, depending on whether the thread is a system thread
- * or a user thread. If all the user threads, except possibly
- * the primordial thread, have terminated, we notify the primordial
- * thread of this condition.
- *
- * Since this function will lock _pr_activeLock, do not call this
- * function while holding the _pr_activeLock lock, as this will result
- * in a deadlock.
- */
-
-static void
-_PR_DecrActiveThreadCount(PRThread *thread)
-{
- PR_Lock(_pr_activeLock);
- if (thread->flags & _PR_SYSTEM) {
- _pr_systemActive--;
- } else {
- _pr_userActive--;
- if (_pr_userActive == _pr_primordialExitCount) {
- PR_NotifyCondVar(_pr_primordialExitCVar);
- }
- }
- PR_Unlock(_pr_activeLock);
-}
-
-/*
-** Detach thread structure
-*/
-static void
-_PR_DestroyThread(PRThread *thread)
-{
- _PR_MD_FREE_LOCK(&thread->threadLock);
- PR_DELETE(thread);
-}
-
-void
-_PR_NativeDestroyThread(PRThread *thread)
-{
- 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);
-}
-
-void
-_PR_UserDestroyThread(PRThread *thread)
-{
- 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
- }
-}
-
-
-/*
-** Run a thread's start function. When the start function returns the
-** thread is done executing and no longer needs the CPU. If there are no
-** more user threads running then we can exit the program.
-*/
-void _PR_NativeRunThread(void *arg)
-{
- 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);
- }
-}
-
-static void _PR_UserRunThread(void)
-{
- 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... */
- }
-}
-
-void _PR_SetThreadPriority(PRThread *thread, PRThreadPriority newPri)
-{
- 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);
-}
-
-/*
-** Suspend the named thread and copy its gc registers into regBuf
-*/
-static void _PR_Suspend(PRThread *thread)
-{
- 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);
-}
-
-static void _PR_Resume(PRThread *thread)
-{
- 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);
-
-}
-
-#if !defined(_PR_LOCAL_THREADS_ONLY) && defined(XP_UNIX)
-static PRThread *get_thread(_PRCPU *cpu, PRBool *wakeup_cpus)
-{
- PRThread *thread;
- PRIntn pri;
- PRUint32 r;
- PRCList *qp;
- PRIntn priMin, priMax;
-
- _PR_RUNQ_LOCK(cpu);
- 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
- */
- PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD));
- if (thread->no_sched) {
- thread = NULL;
- /*
- * Need to wakeup cpus to avoid missing a
- * runnable thread
- * Waking up all CPU's need happen only once.
- */
-
- *wakeup_cpus = PR_TRUE;
- continue;
- } else if (thread->flags & _PR_BOUND_THREAD) {
- /*
- * Thread bound to cpu 0
- */
-
- thread = NULL;
-#ifdef IRIX
- _PR_MD_WAKEUP_PRIMORDIAL_CPU();
-#endif
- continue;
- } else if (thread->io_pending == PR_TRUE) {
- /*
- * A thread that is blocked for I/O needs to run
- * on the same cpu on which it was blocked. This is because
- * the cpu's ioq is accessed without lock protection and scheduling
- * the thread on a different cpu would preclude this optimization.
- */
- thread = NULL;
- continue;
- } else {
- /* Pull thread off of its run queue */
- _PR_DEL_RUNQ(thread);
- _PR_RUNQ_UNLOCK(cpu);
- return(thread);
- }
- }
- }
- thread = NULL;
- }
- _PR_RUNQ_UNLOCK(cpu);
- return(thread);
-}
-#endif /* !defined(_PR_LOCAL_THREADS_ONLY) && defined(XP_UNIX) */
-
-/*
-** Schedule this native thread by finding the highest priority nspr
-** thread that is ready to run.
-**
-** Note- everyone really needs to call _PR_MD_SWITCH_CONTEXT (which calls
-** PR_Schedule() rather than calling PR_Schedule. Otherwise if there
-** is initialization required for switching from SWITCH_CONTEXT,
-** it will not get done!
-*/
-void _PR_Schedule(void)
-{
- 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
- */
- PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD));
- 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
-}
-
-/*
-** Attaches a thread.
-** Does not set the _PR_MD_CURRENT_THREAD.
-** Does not specify the scope of the thread.
-*/
-static PRThread *
-_PR_AttachThread(PRThreadType type, PRThreadPriority priority,
- PRThreadStack *stack)
-{
- 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;
-}
-
-
-
-PR_IMPLEMENT(PRThread*)
-_PR_NativeCreateThread(PRThreadType type,
- void (*start)(void *arg),
- void *arg,
- PRThreadPriority priority,
- PRThreadScope scope,
- PRThreadState state,
- PRUint32 stackSize,
- PRUint32 flags)
-{
- 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;
-}
-
-/************************************************************************/
-
-PR_IMPLEMENT(PRThread*) _PR_CreateThread(PRThreadType type,
- void (*start)(void *arg),
- void *arg,
- PRThreadPriority priority,
- PRThreadScope scope,
- PRThreadState state,
- PRUint32 stackSize,
- PRUint32 flags)
-{
- 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_ATOMIC_INCREMENT(&_pr_systemActive);
- }
- else PR_ATOMIC_INCREMENT(&_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
- 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;
-}
-
-PR_IMPLEMENT(PRThread*) PR_CreateThread(PRThreadType type,
- void (*start)(void *arg),
- void *arg,
- PRThreadPriority priority,
- PRThreadScope scope,
- PRThreadState state,
- PRUint32 stackSize)
-{
- return _PR_CreateThread(type, start, arg, priority, scope, state,
- stackSize, 0);
-}
-
-/*
-** Associate a thread object with an existing native thread.
-** "type" is the type of thread object to attach
-** "priority" is the priority to assign to the thread
-** "stack" defines the shape of the threads stack
-**
-** This can return NULL if some kind of error occurs, or if memory is
-** tight.
-**
-** This call is not normally needed unless you create your own native
-** thread. PR_Init does this automatically for the primordial thread.
-*/
-PRThread* _PRI_AttachThread(PRThreadType type,
- PRThreadPriority priority, PRThreadStack *stack, PRUint32 flags)
-{
- 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;
-}
-
-PR_IMPLEMENT(PRThread*) PR_AttachThread(PRThreadType type,
- PRThreadPriority priority, PRThreadStack *stack)
-{
- return PR_GetCurrentThread();
-}
-
-PR_IMPLEMENT(void) PR_DetachThread(void)
-{
- /*
- * 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
-}
-
-void _PRI_DetachThread(void)
-{
- PRThread *me = _PR_MD_CURRENT_THREAD();
-
- if (me->flags & _PR_PRIMORDIAL) {
- /*
- * ignore, if primordial thread
- */
- return;
- }
- PR_ASSERT(me->flags & _PR_ATTACHED);
- PR_ASSERT(_PR_IS_NATIVE_THREAD(me));
- _PR_CleanupThread(me);
- PR_DELETE(me->privateData);
-
- _PR_DecrActiveThreadCount(me);
-
- _PR_MD_CLEAN_THREAD(me);
- _PR_MD_SET_CURRENT_THREAD(NULL);
- if (!me->threadAllocatedOnStack)
- PR_DELETE(me->stack);
- _PR_MD_FREE_LOCK(&me->threadLock);
- PR_DELETE(me);
-}
-
-/*
-** Wait for thread termination:
-** "thread" is the target thread
-**
-** This can return PR_FAILURE if no joinable thread could be found
-** corresponding to the specified target thread.
-**
-** The calling thread is suspended until the target thread completes.
-** Several threads cannot wait for the same thread to complete; one thread
-** will complete successfully and others will terminate with an error PR_FAILURE.
-** The calling thread will not be blocked if the target thread has already
-** terminated.
-*/
-PR_IMPLEMENT(PRStatus) PR_JoinThread(PRThread *thread)
-{
- 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;
-}
-
-PR_IMPLEMENT(void) PR_SetThreadPriority(PRThread *thread,
- PRThreadPriority newPri)
-{
-
- /*
- 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 ((PRIntn)newPri > (PRIntn)PR_PRIORITY_LAST) {
- newPri = PR_PRIORITY_LAST;
- } else if ((PRIntn)newPri < (PRIntn)PR_PRIORITY_FIRST) {
- newPri = PR_PRIORITY_FIRST;
- }
-
- if ( _PR_IS_NATIVE_THREAD(thread) ) {
- thread->priority = newPri;
- _PR_MD_SET_PRIORITY(&(thread->md), newPri);
- } else _PR_SetThreadPriority(thread, newPri);
-}
-
-PR_IMPLEMENT(PRStatus) PR_SetCurrentThreadName(const char *name)
-{
- PRThread *thread;
- size_t nameLen;
-
- if (!name) {
- PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
- return PR_FAILURE;
- }
-
- thread = PR_GetCurrentThread();
- if (!thread)
- return PR_FAILURE;
-
- PR_Free(thread->name);
- nameLen = strlen(name);
- thread->name = (char *)PR_Malloc(nameLen + 1);
- if (!thread->name)
- return PR_FAILURE;
- memcpy(thread->name, name, nameLen + 1);
- _PR_MD_SET_CURRENT_THREAD_NAME(thread->name);
- return PR_SUCCESS;
-}
-
-PR_IMPLEMENT(const char *) PR_GetThreadName(const PRThread *thread)
-{
- if (!thread)
- return NULL;
- return thread->name;
-}
-
-
-/*
-** This routine prevents all other threads from running. This call is needed by
-** the garbage collector.
-*/
-PR_IMPLEMENT(void) PR_SuspendAll(void)
-{
- PRThread *me = _PR_MD_CURRENT_THREAD();
- PRCList *qp;
-
- /*
- * Stop all user and native threads which are marked GC able.
- */
- PR_Lock(_pr_activeLock);
- suspendAllOn = PR_TRUE;
- suspendAllThread = _PR_MD_CURRENT_THREAD();
- _PR_MD_BEGIN_SUSPEND_ALL();
- for (qp = _PR_ACTIVE_LOCAL_THREADQ().next;
- qp != &_PR_ACTIVE_LOCAL_THREADQ(); qp = qp->next) {
- if ((me != _PR_ACTIVE_THREAD_PTR(qp)) &&
- _PR_IS_GCABLE_THREAD(_PR_ACTIVE_THREAD_PTR(qp))) {
- _PR_Suspend(_PR_ACTIVE_THREAD_PTR(qp));
- PR_ASSERT((_PR_ACTIVE_THREAD_PTR(qp))->state != _PR_RUNNING);
- }
- }
- for (qp = _PR_ACTIVE_GLOBAL_THREADQ().next;
- qp != &_PR_ACTIVE_GLOBAL_THREADQ(); qp = qp->next) {
- if ((me != _PR_ACTIVE_THREAD_PTR(qp)) &&
- _PR_IS_GCABLE_THREAD(_PR_ACTIVE_THREAD_PTR(qp)))
- /* PR_Suspend(_PR_ACTIVE_THREAD_PTR(qp)); */
- _PR_MD_SUSPEND_THREAD(_PR_ACTIVE_THREAD_PTR(qp));
- }
- _PR_MD_END_SUSPEND_ALL();
-}
-
-/*
-** This routine unblocks all other threads that were suspended from running by
-** PR_SuspendAll(). This call is needed by the garbage collector.
-*/
-PR_IMPLEMENT(void) PR_ResumeAll(void)
-{
- PRThread *me = _PR_MD_CURRENT_THREAD();
- PRCList *qp;
-
- /*
- * Resume all user and native threads which are marked GC able.
- */
- _PR_MD_BEGIN_RESUME_ALL();
- for (qp = _PR_ACTIVE_LOCAL_THREADQ().next;
- qp != &_PR_ACTIVE_LOCAL_THREADQ(); qp = qp->next) {
- if ((me != _PR_ACTIVE_THREAD_PTR(qp)) &&
- _PR_IS_GCABLE_THREAD(_PR_ACTIVE_THREAD_PTR(qp)))
- _PR_Resume(_PR_ACTIVE_THREAD_PTR(qp));
- }
- for (qp = _PR_ACTIVE_GLOBAL_THREADQ().next;
- qp != &_PR_ACTIVE_GLOBAL_THREADQ(); qp = qp->next) {
- if ((me != _PR_ACTIVE_THREAD_PTR(qp)) &&
- _PR_IS_GCABLE_THREAD(_PR_ACTIVE_THREAD_PTR(qp)))
- _PR_MD_RESUME_THREAD(_PR_ACTIVE_THREAD_PTR(qp));
- }
- _PR_MD_END_RESUME_ALL();
- suspendAllThread = NULL;
- suspendAllOn = PR_FALSE;
- PR_Unlock(_pr_activeLock);
-}
-
-PR_IMPLEMENT(PRStatus) PR_EnumerateThreads(PREnumerator func, void *arg)
-{
- PRCList *qp, *qp_next;
- PRIntn i = 0;
- PRStatus rv = PR_SUCCESS;
- PRThread* t;
-
- /*
- ** Currently Enumerate threads happen only with suspension and
- ** pr_activeLock held
- */
- PR_ASSERT(suspendAllOn);
-
- /* Steve Morse, 4-23-97: Note that we can't walk a queue by taking
- * qp->next after applying the function "func". In particular, "func"
- * might remove the thread from the queue and put it into another one in
- * which case qp->next no longer points to the next entry in the original
- * queue.
- *
- * To get around this problem, we save qp->next in qp_next before applying
- * "func" and use that saved value as the next value after applying "func".
- */
-
- /*
- * Traverse the list of local and global threads
- */
- for (qp = _PR_ACTIVE_LOCAL_THREADQ().next;
- qp != &_PR_ACTIVE_LOCAL_THREADQ(); qp = qp_next)
- {
- qp_next = qp->next;
- t = _PR_ACTIVE_THREAD_PTR(qp);
- if (_PR_IS_GCABLE_THREAD(t))
- {
- rv = (*func)(t, i, arg);
- if (rv != PR_SUCCESS)
- return rv;
- i++;
- }
- }
- for (qp = _PR_ACTIVE_GLOBAL_THREADQ().next;
- qp != &_PR_ACTIVE_GLOBAL_THREADQ(); qp = qp_next)
- {
- qp_next = qp->next;
- t = _PR_ACTIVE_THREAD_PTR(qp);
- if (_PR_IS_GCABLE_THREAD(t))
- {
- rv = (*func)(t, i, arg);
- if (rv != PR_SUCCESS)
- return rv;
- i++;
- }
- }
- return rv;
-}
-
-/* FUNCTION: _PR_AddSleepQ
-** DESCRIPTION:
-** Adds a thread to the sleep/pauseQ.
-** RESTRICTIONS:
-** Caller must have the RUNQ lock.
-** Caller must be a user level thread
-*/
-PR_IMPLEMENT(void)
-_PR_AddSleepQ(PRThread *thread, PRIntervalTime timeout)
-{
- _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;
- }
-}
-
-/* FUNCTION: _PR_DelSleepQ
-** DESCRIPTION:
-** Removes a thread from the sleep/pauseQ.
-** INPUTS:
-** If propogate_time is true, then the thread following the deleted
-** thread will be get the time from the deleted thread. This is used
-** when deleting a sleeper that has not timed out.
-** RESTRICTIONS:
-** Caller must have the RUNQ lock.
-** Caller must be a user level thread
-*/
-PR_IMPLEMENT(void)
-_PR_DelSleepQ(PRThread *thread, PRBool propogate_time)
-{
- _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);
-}
-
-void
-_PR_AddThreadToRunQ(
- PRThread *me, /* the current thread */
- PRThread *thread) /* the local thread to be added to a run queue */
-{
- 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
-}
« no previous file with comments | « nspr/pr/src/threads/combined/prustack.c ('k') | nspr/pr/src/threads/prcmon.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698