📄 ptthread.c
字号:
}done: rv = _PT_PTHREAD_ATTR_DESTROY(&tattr); PR_ASSERT(0 == rv); return thred;} /* _PR_CreateThread */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, PR_FALSE);} /* PR_CreateThread */PR_IMPLEMENT(PRThread*) PR_CreateThreadGCAble( 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, PR_TRUE);} /* PR_CreateThreadGCAble */PR_IMPLEMENT(void*) GetExecutionEnvironment(PRThread *thred){ return thred->environment;} /* GetExecutionEnvironment */ PR_IMPLEMENT(void) SetExecutionEnvironment(PRThread *thred, void *env){ thred->environment = env;} /* SetExecutionEnvironment */PR_IMPLEMENT(PRThread*) PR_AttachThread( PRThreadType type, PRThreadPriority priority, PRThreadStack *stack){ return PR_GetCurrentThread();} /* PR_AttachThread */PR_IMPLEMENT(PRStatus) PR_JoinThread(PRThread *thred){ int rv = -1; void *result = NULL; PR_ASSERT(thred != NULL); if ((0xafafafaf == thred->state) || (PT_THREAD_DETACHED == (PT_THREAD_DETACHED & thred->state)) || (PT_THREAD_FOREIGN == (PT_THREAD_FOREIGN & thred->state))) { /* * This might be a bad address, but if it isn't, the state should * either be an unjoinable thread or it's already had the object * deleted. However, the client that called join on a detached * thread deserves all the rath I can muster.... */ PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); PR_LogPrint( "PR_JoinThread: 0x%X not joinable | already smashed\n", thred); } else { pthread_t id = thred->id; rv = pthread_join(id, &result); PR_ASSERT(rv == 0 && result == NULL); if (0 == rv) {#ifdef _PR_DCETHREADS rv = pthread_detach(&id); PR_ASSERT(0 == rv);#endif _pt_thread_death(thred); } else { PRErrorCode prerror; switch (rv) { case EINVAL: /* not a joinable thread */ case ESRCH: /* no thread with given ID */ prerror = PR_INVALID_ARGUMENT_ERROR; break; case EDEADLK: /* a thread joining with itself */ prerror = PR_DEADLOCK_ERROR; break; default: prerror = PR_UNKNOWN_ERROR; break; } PR_SetError(prerror, rv); } } return (0 == rv) ? PR_SUCCESS : PR_FAILURE;} /* PR_JoinThread */PR_IMPLEMENT(void) PR_DetachThread(void) { } /* PR_DetachThread */PR_IMPLEMENT(PRThread*) PR_GetCurrentThread(void){ void *thred; if (!_pr_initialized) _PR_ImplicitInitialization(); _PT_PTHREAD_GETSPECIFIC(pt_book.key, thred); if (NULL == thred) thred = pt_AttachThread(); PR_ASSERT(NULL != thred); return (PRThread*)thred;} /* PR_GetCurrentThread */PR_IMPLEMENT(PRThreadScope) PR_GetThreadScope(const PRThread *thred){ return (thred->state & PT_THREAD_BOUND) ? PR_GLOBAL_BOUND_THREAD : PR_GLOBAL_THREAD;} /* PR_GetThreadScope() */PR_IMPLEMENT(PRThreadType) PR_GetThreadType(const PRThread *thred){ return (thred->state & PT_THREAD_SYSTEM) ? PR_SYSTEM_THREAD : PR_USER_THREAD;}PR_IMPLEMENT(PRThreadState) PR_GetThreadState(const PRThread *thred){ return (thred->state & PT_THREAD_DETACHED) ? PR_UNJOINABLE_THREAD : PR_JOINABLE_THREAD;} /* PR_GetThreadState */PR_IMPLEMENT(PRThreadPriority) PR_GetThreadPriority(const PRThread *thred){ PR_ASSERT(thred != NULL); return thred->priority;} /* PR_GetThreadPriority */PR_IMPLEMENT(void) PR_SetThreadPriority(PRThread *thred, PRThreadPriority newPri){ PRIntn rv = -1; PR_ASSERT(NULL != thred); if ((PRIntn)PR_PRIORITY_FIRST > (PRIntn)newPri) newPri = PR_PRIORITY_FIRST; else if ((PRIntn)PR_PRIORITY_LAST < (PRIntn)newPri) newPri = PR_PRIORITY_LAST;#if defined(_PR_DCETHREADS) rv = pthread_setprio(thred->id, pt_PriorityMap(newPri)); /* pthread_setprio returns the old priority */#elif defined(_POSIX_THREAD_PRIORITY_SCHEDULING) if (EPERM != pt_schedpriv) { int policy; struct sched_param schedule; rv = pthread_getschedparam(thred->id, &policy, &schedule); if(0 == rv) { schedule.sched_priority = pt_PriorityMap(newPri); rv = pthread_setschedparam(thred->id, policy, &schedule); if (EPERM == rv) { pt_schedpriv = EPERM; PR_LOG(_pr_thread_lm, PR_LOG_MIN, ("PR_SetThreadPriority: no thread scheduling privilege")); } } if (rv != 0) rv = -1; }#endif thred->priority = newPri;} /* PR_SetThreadPriority */PR_IMPLEMENT(PRStatus) PR_Interrupt(PRThread *thred){ /* ** If the target thread indicates that it's waiting, ** find the condition and broadcast to it. Broadcast ** since we don't know which thread (if there are more ** than one). This sounds risky, but clients must ** test their invariants when resumed from a wait and ** I don't expect very many threads to be waiting on ** a single condition and I don't expect interrupt to ** be used very often. ** ** I don't know why I thought this would work. Must have ** been one of those weaker momements after I'd been ** smelling the vapors. ** ** Even with the followng changes it is possible that ** the pointer to the condition variable is pointing ** at a bogus value. Will the unerlying code detect ** that? */ PRCondVar *cv; PR_ASSERT(NULL != thred); if (NULL == thred) return PR_FAILURE; thred->state |= PT_THREAD_ABORTED; cv = thred->waiting; if ((NULL != cv) && !thred->interrupt_blocked) { PRIntn rv; (void)PR_AtomicIncrement(&cv->notify_pending); rv = pthread_cond_broadcast(&cv->cv); PR_ASSERT(0 == rv); if (0 > PR_AtomicDecrement(&cv->notify_pending)) PR_DestroyCondVar(cv); } return PR_SUCCESS;} /* PR_Interrupt */PR_IMPLEMENT(void) PR_ClearInterrupt(void){ PRThread *me = PR_CurrentThread(); me->state &= ~PT_THREAD_ABORTED;} /* PR_ClearInterrupt */PR_IMPLEMENT(void) PR_BlockInterrupt(void){ PRThread *me = PR_CurrentThread(); _PT_THREAD_BLOCK_INTERRUPT(me);} /* PR_BlockInterrupt */PR_IMPLEMENT(void) PR_UnblockInterrupt(void){ PRThread *me = PR_CurrentThread(); _PT_THREAD_UNBLOCK_INTERRUPT(me);} /* PR_UnblockInterrupt */PR_IMPLEMENT(PRStatus) PR_Yield(void){ static PRBool warning = PR_TRUE; if (warning) warning = _PR_Obsolete( "PR_Yield()", "PR_Sleep(PR_INTERVAL_NO_WAIT)"); return PR_Sleep(PR_INTERVAL_NO_WAIT);}PR_IMPLEMENT(PRStatus) PR_Sleep(PRIntervalTime ticks){ PRStatus rv = PR_SUCCESS; if (!_pr_initialized) _PR_ImplicitInitialization(); if (PR_INTERVAL_NO_WAIT == ticks) { _PT_PTHREAD_YIELD(); } else { PRCondVar *cv; PRIntervalTime timein; timein = PR_IntervalNow(); cv = PR_NewCondVar(_pr_sleeplock); PR_ASSERT(cv != NULL); PR_Lock(_pr_sleeplock); do { PRIntervalTime now = PR_IntervalNow(); PRIntervalTime delta = now - timein; if (delta > ticks) break; rv = PR_WaitCondVar(cv, ticks - delta); } while (PR_SUCCESS == rv); PR_Unlock(_pr_sleeplock); PR_DestroyCondVar(cv); } return rv;} /* PR_Sleep */static void _pt_thread_death(void *arg){ PRThread *thred = (PRThread*)arg; if (thred->state & PT_THREAD_FOREIGN) { PR_Lock(pt_book.ml); 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); } _PR_DestroyThreadPrivate(thred); PR_Free(thred->privateData); if (NULL != thred->errorString) PR_Free(thred->errorString); PR_Free(thred->stack); if (NULL != thred->syspoll_list) PR_Free(thred->syspoll_list);#if defined(_PR_POLL_WITH_SELECT) if (NULL != thred->selectfd_list) PR_Free(thred->selectfd_list);#endif#if defined(DEBUG) memset(thred, 0xaf, sizeof(PRThread));#endif /* defined(DEBUG) */ PR_Free(thred);} /* _pt_thread_death */void _PR_InitThreads( PRThreadType type, PRThreadPriority priority, PRUintn maxPTDs){ int rv; PRThread *thred;#ifdef _PR_NEED_PTHREAD_INIT /* * On BSD/OS (3.1 and 4.0), the pthread subsystem is lazily * initialized, but pthread_self() fails to initialize * pthreads and hence returns a null thread ID if invoked * by the primordial thread before any other pthread call. * So we explicitly initialize pthreads here. */ pthread_init();#endif#if defined(_PR_DCETHREADS) || defined(_POSIX_THREAD_PRIORITY_SCHEDULING)#if defined(FREEBSD) { pthread_attr_t attr; int policy; /* get the min and max priorities of the default policy */ pthread_attr_init(&attr); pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); pthread_attr_getschedpolicy(&attr, &policy); pt_book.minPrio = sched_get_priority_min(policy); PR_ASSERT(-1 != pt_book.minPrio); pt_book.maxPrio = sched_get_priority_max(policy); PR_ASSERT(-1 != pt_book.maxPrio); pthread_attr_destroy(&attr); }#else /* ** These might be function evaluations */ pt_book.minPrio = PT_PRIO_MIN; pt_book.maxPrio = PT_PRIO_MAX;#endif#endif PR_ASSERT(NULL == pt_book.ml); pt_book.ml = PR_NewLock(); PR_ASSERT(NULL != pt_book.ml); pt_book.cv = PR_NewCondVar(pt_book.ml); PR_ASSERT(NULL != pt_book.cv); thred = PR_NEWZAP(PRThread); PR_ASSERT(NULL != thred); thred->arg = NULL; thred->startFunc = NULL; thred->priority = priority; thred->id = pthread_self(); thred->state = (PT_THREAD_DETACHED | PT_THREAD_PRIMORD); if (PR_SYSTEM_THREAD == type) { thred->state |= PT_THREAD_SYSTEM; pt_book.system += 1; pt_book.this_many = 0; } else { pt_book.user += 1; pt_book.this_many = 1; } thred->next = thred->prev = NULL; pt_book.first = pt_book.last = thred; thred->stack = PR_NEWZAP(PRThreadStack); PR_ASSERT(thred->stack != NULL); thred->stack->stackSize = 0; thred->stack->thr = thred; _PR_InitializeStack(thred->stack); /* * Create a key for our use to store a backpointer in the pthread * to our PRThread object. This object gets deleted when the thread * returns from its root in the case of a detached thread. Other * threads delete the objects in Join. * * NB: The destructor logic seems to have a bug so it isn't used. * NBB: Oh really? I'm going to give it a spin - AOF 19 June 1998. * More info - the problem is that pthreads calls the destructor * eagerly as the thread returns from its root, rather than lazily * after the thread is joined. Therefore, threads that are joining * and holding PRThread references are actually holding pointers to * nothing. */ rv = _PT_PTHREAD_KEY_CREATE(&pt_book.key, _pt_thread_death); PR_ASSERT(0 == rv); rv = pthread_setspecific(pt_book.key, thred); PR_ASSERT(0 == rv); PR_SetThreadPriority(thred, priority);} /* _PR_InitThreads */PR_IMPLEMENT(PRStatus) PR_Cleanup(void){ PRThread *me = PR_CurrentThread(); PR_LOG(_pr_thread_lm, PR_LOG_MIN, ("PR_Cleanup: shutting down NSPR")); PR_ASSERT(me->state & PT_THREAD_PRIMORD); if (me->state & PT_THREAD_PRIMORD) { PR_Lock(pt_book.ml); while (pt_book.user > pt_book.this_many) PR_WaitCondVar(pt_book.cv, PR_INTERVAL_NO_TIMEOUT); PR_Unlock(pt_book.ml); _PR_CleanupMW(); _PR_CleanupDtoa(); _PR_CleanupCallOnce(); _PR_ShutdownLinker(); _PR_LogCleanup(); _PR_CleanupNet(); /* Close all the fd's before calling _PR_CleanupIO */ _PR_CleanupIO(); /* * I am not sure if it's safe to delete the cv and lock here, * since there may still be "system" threads around. If this * call isn't immediately prior to exiting, then there's a * problem. */ if (0 == pt_book.system) { PR_DestroyCondVar(pt_book.cv); pt_book.cv = NULL; PR_DestroyLock(pt_book.ml); pt_book.ml = NULL; } _pt_thread_death(me); PR_DestroyLock(_pr_sleeplock); _pr_sleeplock = NULL; _PR_CleanupLayerCache(); _PR_CleanupEnv();#ifdef _PR_ZONE_ALLOCATOR _PR_DestroyZones();#endif _pr_initialized = PR_FALSE; return PR_SUCCESS; } return PR_FAILURE;} /* PR_Cleanup */PR_IMPLEMENT(void) PR_ProcessExit(PRIntn status){ _exit(status);}PR_IMPLEMENT(PRUint32) PR_GetThreadID(PRThread *thred){#if defined(_PR_DCETHREADS) return (PRUint32)&thred->id; /* this is really a sham! */#else return (PRUint32)thred->id; /* and I don't know what they will do with it */#endif}/* * $$$ * The following two thread-to-processor affinity functions are not * yet implemented for pthreads. By the way, these functions should return * PRStatus rather than PRInt32 to indicate the success/failure status. * $$$ */PR_IMPLEMENT(PRInt32) PR_GetThreadAffinityMask(PRThread *thread, PRUint32 *mask){ return 0; /* not implemented */}PR_IMPLEMENT(PRInt32) PR_SetThreadAffinityMask(PRThread *thread, PRUint32 mask ){ return 0; /* not implemented */}PR_IMPLEMENT(void)PR_SetThreadDumpProc(PRThread* thread, PRThreadDumpProc dump, void *arg){ thread->dump = dump; thread->dumpArg = arg;}/* * Garbage collection support follows. */#if defined(_PR_DCETHREADS)/* * statics for Garbage Collection support. We don't need to protect these * signal masks since the garbage collector itself is protected by a lock * and multiple threads will not be garbage collecting at the same time. */static sigset_t javagc_vtalarm_sigmask;static sigset_t javagc_intsoff_sigmask;#else /* defined(_PR_DCETHREADS) *//* a bogus signal mask for forcing a timed wait *//* Not so bogus in AIX as we really do a sigwait */static sigset_t sigwait_set;static struct timespec onemillisec = {0, 1000000L};#ifndef PT_NO_SIGTIMEDWAITstatic struct timespec hundredmillisec = {0, 100000000L};#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -