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

📄 ptthread.c

📁 Netscape NSPR库源码
💻 C
📖 第 1 页 / 共 3 页
字号:
static void suspend_signal_handler(PRIntn sig);#ifdef PT_NO_SIGTIMEDWAITstatic void null_signal_handler(PRIntn sig);#endif#endif /* defined(_PR_DCETHREADS) *//* * Linux pthreads use SIGUSR1 and SIGUSR2 internally, which * conflict with the use of these two signals in our GC support. * So we don't know how to support GC on Linux pthreads. */static void init_pthread_gc_support(void){    PRIntn rv;#if defined(_PR_DCETHREADS)	rv = sigemptyset(&javagc_vtalarm_sigmask);    PR_ASSERT(0 == rv);	rv = sigaddset(&javagc_vtalarm_sigmask, SIGVTALRM);    PR_ASSERT(0 == rv);#else  /* defined(_PR_DCETHREADS) */	{	    struct sigaction sigact_usr2;	    sigact_usr2.sa_handler = suspend_signal_handler;	    sigact_usr2.sa_flags = SA_RESTART;	    sigemptyset (&sigact_usr2.sa_mask);        rv = sigaction (SIGUSR2, &sigact_usr2, NULL);        PR_ASSERT(0 == rv);        sigemptyset (&sigwait_set);#if defined(PT_NO_SIGTIMEDWAIT)        sigaddset (&sigwait_set, SIGUSR1);#else        sigaddset (&sigwait_set, SIGUSR2);#endif  /* defined(PT_NO_SIGTIMEDWAIT) */	}#if defined(PT_NO_SIGTIMEDWAIT)	{	    struct sigaction sigact_null;	    sigact_null.sa_handler = null_signal_handler;	    sigact_null.sa_flags = SA_RESTART;	    sigemptyset (&sigact_null.sa_mask);        rv = sigaction (SIGUSR1, &sigact_null, NULL);	    PR_ASSERT(0 ==rv);     }#endif  /* defined(PT_NO_SIGTIMEDWAIT) */#endif /* defined(_PR_DCETHREADS) */}PR_IMPLEMENT(void) PR_SetThreadGCAble(void){    PR_Lock(pt_book.ml);	PR_CurrentThread()->state |= PT_THREAD_GCABLE;    PR_Unlock(pt_book.ml);}PR_IMPLEMENT(void) PR_ClearThreadGCAble(void){    PR_Lock(pt_book.ml);	PR_CurrentThread()->state &= (~PT_THREAD_GCABLE);    PR_Unlock(pt_book.ml);}#if defined(DEBUG)static PRBool suspendAllOn = PR_FALSE;#endifstatic PRBool suspendAllSuspended = PR_FALSE;PR_IMPLEMENT(PRStatus) PR_EnumerateThreads(PREnumerator func, void *arg){    PRIntn count = 0;    PRStatus rv = PR_SUCCESS;    PRThread* thred = pt_book.first;    PRThread *me = PR_CurrentThread();    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_EnumerateThreads\n"));    /*     * $$$     * Need to suspend all threads other than me before doing this.     * This is really a gross and disgusting thing to do. The only     * good thing is that since all other threads are suspended, holding     * the lock during a callback seems like child's play.     * $$$     */    PR_ASSERT(suspendAllOn);    while (thred != NULL)    {        /* 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".         */        PRThread* next = thred->next;        if (_PT_IS_GCABLE_THREAD(thred))        {#if !defined(_PR_DCETHREADS)            PR_ASSERT((thred == me) || (thred->suspend & PT_THREAD_SUSPENDED));#endif            PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,                    ("In PR_EnumerateThreads callback thread %X thid = %X\n",                     thred, thred->id));            rv = func(thred, count++, arg);            if (rv != PR_SUCCESS)                return rv;        }        thred = next;    }    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 	   ("End PR_EnumerateThreads count = %d \n", count));    return rv;}  /* PR_EnumerateThreads *//* * PR_SuspendAll and PR_ResumeAll are called during garbage collection.  The strategy  * we use is to send a SIGUSR2 signal to every gc able thread that we intend to suspend. * The signal handler will record the stack pointer and will block until resumed by * the resume call.  Since the signal handler is the last routine called for the * suspended thread, the stack pointer will also serve as a place where all the * registers have been saved on the stack for the previously executing routines. * * Through global variables, we also make sure that PR_Suspend and PR_Resume does not * proceed until the thread is suspended or resumed. */#if !defined(_PR_DCETHREADS)/* * In the signal handler, we can not use condition variable notify or wait. * This does not work consistently across all pthread platforms.  We also can not  * use locking since that does not seem to work reliably across platforms. * Only thing we can do is yielding while testing for a global condition * to change.  This does work on pthread supported platforms.  We may have * to play with priortities if there are any problems detected. */ /*   * In AIX, you cannot use ANY pthread calls in the signal handler except perhaps  * pthread_yield. But that is horribly inefficient. Hence we use only sigwait, no  * sigtimedwait is available. We need to use another user signal, SIGUSR1. Actually  * SIGUSR1 is also used by exec in Java. So our usage here breaks the exec in Java,  * for AIX. You cannot use pthread_cond_wait or pthread_delay_np in the signal  * handler as all synchronization mechanisms just break down.   */#if defined(PT_NO_SIGTIMEDWAIT)static void null_signal_handler(PRIntn sig){	return;}#endifstatic void suspend_signal_handler(PRIntn sig){	PRThread *me = PR_CurrentThread();	PR_ASSERT(me != NULL);	PR_ASSERT(_PT_IS_GCABLE_THREAD(me));	PR_ASSERT((me->suspend & PT_THREAD_SUSPENDED) == 0);	PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,         ("Begin suspend_signal_handler thred %X thread id = %X\n", 		me, me->id));	/*	 * save stack pointer	 */	me->sp = &me;	/* 	   At this point, the thread's stack pointer has been saved,	   And it is going to enter a wait loop until it is resumed.	   So it is _really_ suspended 	*/	me->suspend |= PT_THREAD_SUSPENDED;	/*	 * now, block current thread	 */#if defined(PT_NO_SIGTIMEDWAIT)	pthread_cond_signal(&me->suspendResumeCV);	while (me->suspend & PT_THREAD_SUSPENDED)	{#if !defined(FREEBSD) && !defined(NETBSD) && !defined(OPENBSD) \    && !defined(BSDI) && !defined(VMS) && !defined(UNIXWARE) && !defined(DARWIN)  /*XXX*/        PRIntn rv;	    sigwait(&sigwait_set, &rv);#endif	}	me->suspend |= PT_THREAD_RESUMED;	pthread_cond_signal(&me->suspendResumeCV);#else /* defined(PT_NO_SIGTIMEDWAIT) */	while (me->suspend & PT_THREAD_SUSPENDED)	{		PRIntn rv = sigtimedwait(&sigwait_set, NULL, &hundredmillisec);    	PR_ASSERT(-1 == rv);	}	me->suspend |= PT_THREAD_RESUMED;#endif    /*     * At this point, thread has been resumed, so set a global condition.     * The ResumeAll needs to know that this has really been resumed.      * So the signal handler sets a flag which PR_ResumeAll will reset.      * The PR_ResumeAll must reset this flag ...     */    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,         ("End suspend_signal_handler thred = %X tid = %X\n", me, me->id));}  /* suspend_signal_handler */static void pt_SuspendSet(PRThread *thred){    PRIntn rv;    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 	   ("pt_SuspendSet thred %X thread id = %X\n", thred, thred->id));    /*     * Check the thread state and signal the thread to suspend     */    PR_ASSERT((thred->suspend & PT_THREAD_SUSPENDED) == 0);    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 	   ("doing pthread_kill in pt_SuspendSet thred %X tid = %X\n",	   thred, thred->id));#if defined(VMS)    rv = thread_suspend(thred);#else    rv = pthread_kill (thred->id, SIGUSR2);#endif    PR_ASSERT(0 == rv);}static void pt_SuspendTest(PRThread *thred){    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 	   ("Begin pt_SuspendTest thred %X thread id = %X\n", thred, thred->id));    /*     * Wait for the thread to be really suspended. This happens when the     * suspend signal handler stores the stack pointer and sets the state     * to suspended.      */#if defined(PT_NO_SIGTIMEDWAIT)    pthread_mutex_lock(&thred->suspendResumeMutex);    while ((thred->suspend & PT_THREAD_SUSPENDED) == 0)    {	    pthread_cond_timedwait(	        &thred->suspendResumeCV, &thred->suspendResumeMutex, &onemillisec);	}	pthread_mutex_unlock(&thred->suspendResumeMutex);#else    while ((thred->suspend & PT_THREAD_SUSPENDED) == 0)    {		PRIntn rv = sigtimedwait(&sigwait_set, NULL, &onemillisec);    	PR_ASSERT(-1 == rv);	}#endif    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,        ("End pt_SuspendTest thred %X tid %X\n", thred, thred->id));}  /* pt_SuspendTest */static void pt_ResumeSet(PRThread *thred){    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 	   ("pt_ResumeSet thred %X thread id = %X\n", thred, thred->id));    /*     * Clear the global state and set the thread state so that it will     * continue past yield loop in the suspend signal handler     */    PR_ASSERT(thred->suspend & PT_THREAD_SUSPENDED);    thred->suspend &= ~PT_THREAD_SUSPENDED;#if defined(PT_NO_SIGTIMEDWAIT)#if defined(VMS)	thread_resume(thred);#else	pthread_kill(thred->id, SIGUSR1);#endif#endif}  /* pt_ResumeSet */static void pt_ResumeTest(PRThread *thred){    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 	   ("Begin pt_ResumeTest thred %X thread id = %X\n", thred, thred->id));    /*     * Wait for the threads resume state to change     * to indicate it is really resumed      */#if defined(PT_NO_SIGTIMEDWAIT)    pthread_mutex_lock(&thred->suspendResumeMutex);    while ((thred->suspend & PT_THREAD_RESUMED) == 0)    {	    pthread_cond_timedwait(	        &thred->suspendResumeCV, &thred->suspendResumeMutex, &onemillisec);    }    pthread_mutex_unlock(&thred->suspendResumeMutex);#else    while ((thred->suspend & PT_THREAD_RESUMED) == 0) {		PRIntn rv = sigtimedwait(&sigwait_set, NULL, &onemillisec);    	PR_ASSERT(-1 == rv);	}#endif    thred->suspend &= ~PT_THREAD_RESUMED;    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, (        "End pt_ResumeTest thred %X tid %X\n", thred, thred->id));}  /* pt_ResumeTest */static pthread_once_t pt_gc_support_control = PTHREAD_ONCE_INIT;PR_IMPLEMENT(void) PR_SuspendAll(void){#ifdef DEBUG    PRIntervalTime stime, etime;#endif    PRThread* thred = pt_book.first;    PRThread *me = PR_CurrentThread();    int rv;    rv = pthread_once(&pt_gc_support_control, init_pthread_gc_support);    PR_ASSERT(0 == rv);    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_SuspendAll\n"));    /*     * Stop all threads which are marked GC able.     */    PR_Lock(pt_book.ml);#ifdef DEBUG    suspendAllOn = PR_TRUE;    stime = PR_IntervalNow();#endif    while (thred != NULL)    {	    if ((thred != me) && _PT_IS_GCABLE_THREAD(thred))    		pt_SuspendSet(thred);        thred = thred->next;    }    /* Wait till they are really suspended */    thred = pt_book.first;    while (thred != NULL)    {	    if ((thred != me) && _PT_IS_GCABLE_THREAD(thred))            pt_SuspendTest(thred);        thred = thred->next;    }    suspendAllSuspended = PR_TRUE;#ifdef DEBUG    etime = PR_IntervalNow();    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,\        ("End PR_SuspendAll (time %dms)\n",        PR_IntervalToMilliseconds(etime - stime)));#endif}  /* PR_SuspendAll */PR_IMPLEMENT(void) PR_ResumeAll(void){#ifdef DEBUG    PRIntervalTime stime, etime;#endif    PRThread* thred = pt_book.first;    PRThread *me = PR_CurrentThread();    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_ResumeAll\n"));    /*     * Resume all previously suspended GC able threads.     */    suspendAllSuspended = PR_FALSE;#ifdef DEBUG    stime = PR_IntervalNow();#endif    while (thred != NULL)    {	    if ((thred != me) && _PT_IS_GCABLE_THREAD(thred))    	    pt_ResumeSet(thred);        thred = thred->next;    }    thred = pt_book.first;    while (thred != NULL)    {	    if ((thred != me) && _PT_IS_GCABLE_THREAD(thred))    	    pt_ResumeTest(thred);        thred = thred->next;    }    PR_Unlock(pt_book.ml);#ifdef DEBUG    suspendAllOn = PR_FALSE;    etime = PR_IntervalNow();    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,        ("End PR_ResumeAll (time %dms)\n",        PR_IntervalToMilliseconds(etime - stime)));#endif}  /* PR_ResumeAll *//* Return the stack pointer for the given thread- used by the GC */PR_IMPLEMENT(void *)PR_GetSP(PRThread *thred){    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 	    ("in PR_GetSP thred %X thid = %X, sp = %X \n", 	    thred, thred->id, thred->sp));    return thred->sp;}  /* PR_GetSP */#else /* !defined(_PR_DCETHREADS) */static pthread_once_t pt_gc_support_control = pthread_once_init;/* * For DCE threads, there is no pthread_kill or a way of suspending or resuming a * particular thread.  We will just disable the preemption (virtual timer alarm) and * let the executing thread finish the garbage collection.  This stops all other threads * (GC able or not) and is very inefficient but there is no other choice. */PR_IMPLEMENT(void) PR_SuspendAll(){    PRIntn rv;    rv = pthread_once(&pt_gc_support_control, init_pthread_gc_support);    PR_ASSERT(0 == rv);  /* returns -1 on failure */#ifdef DEBUG    suspendAllOn = PR_TRUE;#endif    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_SuspendAll\n"));    /*      * turn off preemption - i.e add virtual alarm signal to the set of      * blocking signals      */    rv = sigprocmask(        SIG_BLOCK, &javagc_vtalarm_sigmask, &javagc_intsoff_sigmask);    PR_ASSERT(0 == rv);    suspendAllSuspended = PR_TRUE;    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("End PR_SuspendAll\n"));}  /* PR_SuspendAll */PR_IMPLEMENT(void) PR_ResumeAll(){    PRIntn rv;        suspendAllSuspended = PR_FALSE;    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_ResumeAll\n"));    /* turn on preemption - i.e re-enable virtual alarm signal */    rv = sigprocmask(SIG_SETMASK, &javagc_intsoff_sigmask, (sigset_t *)NULL);    PR_ASSERT(0 == rv);#ifdef DEBUG    suspendAllOn = PR_FALSE;#endif    PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("End PR_ResumeAll\n"));}  /* PR_ResumeAll *//* Return the stack pointer for the given thread- used by the GC */PR_IMPLEMENT(void*)PR_GetSP(PRThread *thred){	pthread_t tid = thred->id;	char *thread_tcb, *top_sp;	/*	 * For HPUX DCE threads, pthread_t is a struct with the	 * following three fields (see pthread.h, dce/cma.h):	 *     cma_t_address       field1;	 *     short int           field2;	 *     short int           field3;	 * where cma_t_address is typedef'd to be either void*	 * or char*.	 */	PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_GetSP\n"));	thread_tcb = (char*)tid.field1;	top_sp = *(char**)(thread_tcb + 128);	PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("End PR_GetSP %X \n", top_sp));	return top_sp;}  /* PR_GetSP */#endif /* !defined(_PR_DCETHREADS) */#endif  /* defined(_PR_PTHREADS) || defined(_PR_DCETHREADS) *//* ptthread.c */

⌨️ 快捷键说明

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