📄 ptthread.c
字号:
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 + -