⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pruthr.c

📁 Netscape NSPR库源码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- *//*  * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ *  * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. *  * The Original Code is the Netscape Portable Runtime (NSPR). *  * The Initial Developer of the Original Code is Netscape * Communications Corporation.  Portions created by Netscape are  * Copyright (C) 1998-2000 Netscape Communications Corporation.  All * Rights Reserved. *  * Contributor(s): *  * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL"), in which case the provisions of the GPL are applicable  * instead of those above.  If you wish to allow use of your  * version of this file only under the terms of the GPL and not to * allow others to use your version of this file under the MPL, * indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by * the GPL.  If you do not delete the provisions above, a recipient * may use your version of this file under either the MPL or the * GPL. */#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          #if defined(XP_MAC)#include <LowMem.h>#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){#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);}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*) ((((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    }}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);    /* 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.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -