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

📄 ptthread.c

📁 Netscape NSPR库源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* -*- 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. *//*** File:            ptthread.c** Descritpion:        Implemenation for threds using pthreds** Exports:            ptthread.h*/#if defined(_PR_PTHREADS) || defined(_PR_DCETHREADS)#include "prlog.h"#include "primpl.h"#include "prpdce.h"#include <pthread.h>#include <unistd.h>#include <string.h>#include <signal.h>/* * Record whether or not we have the privilege to set the scheduling * policy and priority of threads.  0 means that privilege is available. * EPERM means that privilege is not available. */static PRIntn pt_schedpriv = 0;extern PRLock *_pr_sleeplock;static struct _PT_Bookeeping{    PRLock *ml;                 /* a lock to protect ourselves */    PRCondVar *cv;              /* used to signal global things */    PRInt32 system, user;       /* a count of the two different types */    PRUintn this_many;          /* number of threads allowed for exit */    pthread_key_t key;          /* private private data key */    PRThread *first, *last;     /* list of threads we know about */#if defined(_PR_DCETHREADS) || defined(_POSIX_THREAD_PRIORITY_SCHEDULING)    PRInt32 minPrio, maxPrio;   /* range of scheduling priorities */#endif} pt_book = {0};static void _pt_thread_death(void *arg);static void init_pthread_gc_support(void);#if defined(_PR_DCETHREADS) || defined(_POSIX_THREAD_PRIORITY_SCHEDULING)static PRIntn pt_PriorityMap(PRThreadPriority pri){#ifdef NTO    /* This priority algorithm causes lots of problems on Neutrino     * for now I have just hard coded everything to run at priority 10     * until I can come up with a new algorithm.     *     Jerry.Kirk@Nexwarecorp.com     */    return 10;#else    return pt_book.minPrio +	    pri * (pt_book.maxPrio - pt_book.minPrio) / PR_PRIORITY_LAST;#endif}#endif#if defined(GC_LEAK_DETECTOR) && (__GLIBC__ >= 2) && defined(__i386__) #include <setjmp.h>typedef struct stack_frame stack_frame;struct stack_frame {    stack_frame* next;    void* pc;};static stack_frame* GetStackFrame(){    jmp_buf jb;    stack_frame* currentFrame;    setjmp(jb);    currentFrame = (stack_frame*)(jb[0].__jmpbuf[JB_BP]);    currentFrame = currentFrame->next;    return currentFrame;}static void* GetStackTop(){    stack_frame* frame;    frame = GetStackFrame();    while (frame != NULL)    {        ptrdiff_t pc = (ptrdiff_t)frame->pc;        if ((pc < 0x08000000) || (pc > 0x7fffffff) || (frame->next < frame))            return frame;        frame = frame->next;    }    return NULL;}#endif /* GC_LEAK_DETECTOR && (__GLIBC__ >= 2) && __i386__ *//*** Initialize a stack for a native pthread thread*/static void _PR_InitializeStack(PRThreadStack *ts){    if( ts && (ts->stackTop == 0) ) {        ts->allocBase = (char *) &ts;        ts->allocSize = ts->stackSize;        /*        ** Setup stackTop and stackBottom values.        */#ifdef HAVE_STACK_GROWING_UP        ts->stackBottom = ts->allocBase + ts->stackSize;        ts->stackTop = ts->allocBase;#else#ifdef GC_LEAK_DETECTOR        ts->stackTop    = GetStackTop();        ts->stackBottom = ts->stackTop - ts->stackSize;#else        ts->stackTop    = ts->allocBase;        ts->stackBottom = ts->allocBase - ts->stackSize;#endif#endif    }}static void *_pt_root(void *arg){    PRIntn rv;    PRThread *thred = (PRThread*)arg;    PRBool detached = (thred->state & PT_THREAD_DETACHED) ? PR_TRUE : PR_FALSE;    /*     * Both the parent thread and this new thread set thred->id.     * The new thread must ensure that thred->id is set before     * it executes its startFunc.  The parent thread must ensure     * that thred->id is set before PR_CreateThread() returns.     * Both threads set thred->id without holding a lock.  Since     * they are writing the same value, this unprotected double     * write should be safe.     */    thred->id = pthread_self();    /*    ** DCE Threads can't detach during creation, so do it late.    ** I would like to do it only here, but that doesn't seem    ** to work.    */#if defined(_PR_DCETHREADS)    if (detached)    {        /* pthread_detach() modifies its argument, so we must pass a copy */        pthread_t self = thred->id;        rv = pthread_detach(&self);        PR_ASSERT(0 == rv);    }#endif /* defined(_PR_DCETHREADS) */    /* Set up the thread stack information */    _PR_InitializeStack(thred->stack);    /*     * Set within the current thread the pointer to our object.     * This object will be deleted when the thread termintates,     * whether in a join or detached (see _PR_InitThreads()).     */    rv = pthread_setspecific(pt_book.key, thred);    PR_ASSERT(0 == rv);    /* make the thread visible to the rest of the runtime */    PR_Lock(pt_book.ml);    /* If this is a GCABLE thread, set its state appropriately */    if (thred->suspend & PT_THREAD_SETGCABLE)	    thred->state |= PT_THREAD_GCABLE;    thred->suspend = 0;    thred->prev = pt_book.last;    pt_book.last->next = thred;    thred->next = NULL;    pt_book.last = thred;    PR_Unlock(pt_book.ml);    thred->startFunc(thred->arg);  /* make visible to the client */    /* unhook the thread from the runtime */    PR_Lock(pt_book.ml);    /*     * At this moment, PR_CreateThread() may not have set thred->id yet.     * It is safe for a detached thread to free thred only after     * PR_CreateThread() has set thred->id.     */    if (detached)    {        while (!thred->okToDelete)            PR_WaitCondVar(pt_book.cv, PR_INTERVAL_NO_TIMEOUT);    }    if (thred->state & PT_THREAD_SYSTEM)        pt_book.system -= 1;    else if (--pt_book.user == pt_book.this_many)        PR_NotifyAllCondVar(pt_book.cv);    thred->prev->next = thred->next;    if (NULL == thred->next)        pt_book.last = thred->prev;    else        thred->next->prev = thred->prev;    PR_Unlock(pt_book.ml);    /*    * Here we set the pthread's backpointer to the PRThread to NULL.    * Otherwise the desctructor would get called eagerly as the thread    * returns to the pthread runtime. The joining thread would them be    * the proud possessor of a dangling reference. However, this is the    * last chance to delete the object if the thread is detached, so    * just let the destuctor do the work.    */    if (PR_FALSE == detached)    {        rv = pthread_setspecific(pt_book.key, NULL);        PR_ASSERT(0 == rv);    }    return NULL;}  /* _pt_root */static PRThread* pt_AttachThread(void){    PRThread *thred = NULL;    /*     * NSPR must have been initialized when PR_AttachThread is called.     * We cannot have PR_AttachThread call implicit initialization     * because if multiple threads call PR_AttachThread simultaneously,     * NSPR may be initialized more than once.     * We can't call any function that calls PR_GetCurrentThread()     * either (e.g., PR_SetError()) as that will result in infinite     * recursion.     */    if (!_pr_initialized) return NULL;    /* PR_NEWZAP must not call PR_GetCurrentThread() */    thred = PR_NEWZAP(PRThread);    if (NULL != thred)    {        int rv;        thred->priority = PR_PRIORITY_NORMAL;        thred->id = pthread_self();        rv = pthread_setspecific(pt_book.key, thred);        PR_ASSERT(0 == rv);        thred->state = PT_THREAD_GLOBAL | PT_THREAD_FOREIGN;        PR_Lock(pt_book.ml);        /* then put it into the list */        thred->prev = pt_book.last;	    pt_book.last->next = thred;        thred->next = NULL;        pt_book.last = thred;        PR_Unlock(pt_book.ml);    }    return thred;  /* may be NULL */}  /* pt_AttachThread */static PRThread* _PR_CreateThread(    PRThreadType type, void (*start)(void *arg),    void *arg, PRThreadPriority priority, PRThreadScope scope,    PRThreadState state, PRUint32 stackSize, PRBool isGCAble){    int rv;    PRThread *thred;    pthread_attr_t tattr;    if (!_pr_initialized) _PR_ImplicitInitialization();    if ((PRIntn)PR_PRIORITY_FIRST > (PRIntn)priority)        priority = PR_PRIORITY_FIRST;    else if ((PRIntn)PR_PRIORITY_LAST < (PRIntn)priority)        priority = PR_PRIORITY_LAST;    rv = _PT_PTHREAD_ATTR_INIT(&tattr);    PR_ASSERT(0 == rv);    if (EPERM != pt_schedpriv)    {#if !defined(_PR_DCETHREADS) && defined(_POSIX_THREAD_PRIORITY_SCHEDULING)        struct sched_param schedule;#endif#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING)        rv = pthread_attr_setinheritsched(&tattr, PTHREAD_EXPLICIT_SCHED);        PR_ASSERT(0 == rv);#endif        /* Use the default scheduling policy */#if defined(_PR_DCETHREADS)        rv = pthread_attr_setprio(&tattr, pt_PriorityMap(priority));        PR_ASSERT(0 == rv);#elif defined(_POSIX_THREAD_PRIORITY_SCHEDULING)        rv = pthread_attr_getschedparam(&tattr, &schedule);        PR_ASSERT(0 == rv);        schedule.sched_priority = pt_PriorityMap(priority);        rv = pthread_attr_setschedparam(&tattr, &schedule);        PR_ASSERT(0 == rv);#ifdef NTO        rv = pthread_attr_setschedpolicy(&tattr, SCHED_RR); /* Round Robin */        PR_ASSERT(0 == rv);#endif#endif /* !defined(_PR_DCETHREADS) */    }    /*     * DCE threads can't set detach state before creating the thread.     * AIX can't set detach late. Why can't we all just get along?     */#if !defined(_PR_DCETHREADS)    rv = pthread_attr_setdetachstate(&tattr,        ((PR_JOINABLE_THREAD == state) ?            PTHREAD_CREATE_JOINABLE : PTHREAD_CREATE_DETACHED));    PR_ASSERT(0 == rv);#endif /* !defined(_PR_DCETHREADS) */    if (0 == stackSize) stackSize = (64 * 1024);  /* default == 64K */#ifdef _MD_MINIMUM_STACK_SIZE    if (stackSize < _MD_MINIMUM_STACK_SIZE) stackSize = _MD_MINIMUM_STACK_SIZE;#endif    /*     * Linux doesn't have pthread_attr_setstacksize.     */#ifndef LINUX    rv = pthread_attr_setstacksize(&tattr, stackSize);    PR_ASSERT(0 == rv);#endif    thred = PR_NEWZAP(PRThread);    if (NULL == thred)    {        PR_SetError(PR_OUT_OF_MEMORY_ERROR, errno);        goto done;    }    else    {        pthread_t id;        thred->arg = arg;        thred->startFunc = start;        thred->priority = priority;        if (PR_UNJOINABLE_THREAD == state)            thred->state |= PT_THREAD_DETACHED;        if (PR_LOCAL_THREAD == scope)        	scope = PR_GLOBAL_THREAD;			        if (PR_GLOBAL_BOUND_THREAD == scope) {#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING)    		rv = pthread_attr_setscope(&tattr, PTHREAD_SCOPE_SYSTEM);			if (rv) {				/*				 * system scope not supported				 */        		scope = PR_GLOBAL_THREAD;				/*				 * reset scope				 */    			rv = pthread_attr_setscope(&tattr, PTHREAD_SCOPE_PROCESS);    			PR_ASSERT(0 == rv);			}#endif		}        if (PR_GLOBAL_THREAD == scope)            thred->state |= PT_THREAD_GLOBAL;        else if (PR_GLOBAL_BOUND_THREAD == scope)            thred->state |= (PT_THREAD_GLOBAL | PT_THREAD_BOUND);		else	/* force it global */            thred->state |= PT_THREAD_GLOBAL;        if (PR_SYSTEM_THREAD == type)            thred->state |= PT_THREAD_SYSTEM;        thred->suspend =(isGCAble) ? PT_THREAD_SETGCABLE : 0;        thred->stack = PR_NEWZAP(PRThreadStack);        if (thred->stack == NULL) {            PRIntn oserr = errno;            PR_Free(thred);  /* all that work ... poof! */            PR_SetError(PR_OUT_OF_MEMORY_ERROR, oserr);            thred = NULL;  /* and for what? */            goto done;        }        thred->stack->stackSize = stackSize;        thred->stack->thr = thred;#ifdef PT_NO_SIGTIMEDWAIT        pthread_mutex_init(&thred->suspendResumeMutex,NULL);        pthread_cond_init(&thred->suspendResumeCV,NULL);#endif        /* make the thread counted to the rest of the runtime */        PR_Lock(pt_book.ml);        if (PR_SYSTEM_THREAD == type)            pt_book.system += 1;        else pt_book.user += 1;        PR_Unlock(pt_book.ml);        /*         * We pass a pointer to a local copy (instead of thred->id)         * to pthread_create() because who knows what wacky things         * pthread_create() may be doing to its argument.         */        rv = _PT_PTHREAD_CREATE(&id, tattr, _pt_root, thred);#if !defined(_PR_DCETHREADS)        if (EPERM == rv)        {#if defined(IRIX)        	if (PR_GLOBAL_BOUND_THREAD == scope) {				/*				 * SCOPE_SYSTEM requires appropriate privilege				 * reset to process scope and try again				 */    			rv = pthread_attr_setscope(&tattr, PTHREAD_SCOPE_PROCESS);    			PR_ASSERT(0 == rv);            	thred->state &= ~PT_THREAD_BOUND;			}#else            /* Remember that we don't have thread scheduling privilege. */            pt_schedpriv = EPERM;            PR_LOG(_pr_thread_lm, PR_LOG_MIN,                ("_PR_CreateThread: no thread scheduling privilege"));            /* Try creating the thread again without setting priority. */#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING)            rv = pthread_attr_setinheritsched(&tattr, PTHREAD_INHERIT_SCHED);            PR_ASSERT(0 == rv);#endif#endif	/* IRIX */            rv = _PT_PTHREAD_CREATE(&id, tattr, _pt_root, thred);        }#endif        if (0 != rv)        {#if defined(_PR_DCETHREADS)            PRIntn oserr = errno;#else            PRIntn oserr = rv;#endif            PR_Lock(pt_book.ml);            if (thred->state & PT_THREAD_SYSTEM)                pt_book.system -= 1;            else if (--pt_book.user == pt_book.this_many)                PR_NotifyAllCondVar(pt_book.cv);            PR_Unlock(pt_book.ml);            PR_Free(thred->stack);            PR_Free(thred);  /* all that work ... poof! */            PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, oserr);            thred = NULL;  /* and for what? */            goto done;        }        /*         * Both the parent thread and this new thread set thred->id.         * The parent thread must ensure that thred->id is set before         * PR_CreateThread() returns.  (See comments in _pt_root().)         */        thred->id = id;        /*         * If the new thread is detached, tell it that PR_CreateThread()         * has set thred->id so it's ok to delete thred.         */        if (PR_UNJOINABLE_THREAD == state)        {            PR_Lock(pt_book.ml);            thred->okToDelete = PR_TRUE;            PR_NotifyAllCondVar(pt_book.cv);            PR_Unlock(pt_book.ml);        }

⌨️ 快捷键说明

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