Index: mozilla/nsprpub/pr/src/pthreads/ptthread.c |
=================================================================== |
--- mozilla/nsprpub/pr/src/pthreads/ptthread.c (revision 191424) |
+++ mozilla/nsprpub/pr/src/pthreads/ptthread.c (working copy) |
@@ -1,1704 +0,0 @@ |
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
-/* This Source Code Form is subject to the terms of the Mozilla Public |
- * License, v. 2.0. If a copy of the MPL was not distributed with this |
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
- |
-/* |
-** 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> |
-#include <dlfcn.h> |
- |
-#ifdef SYMBIAN |
-/* In Open C sched_get_priority_min/max do not work properly, so we undefine |
- * _POSIX_THREAD_PRIORITY_SCHEDULING here. |
- */ |
-#undef _POSIX_THREAD_PRIORITY_SCHEDULING |
-#endif |
- |
-/* |
- * 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; /* thread 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 _pt_thread_death_internal(void *arg, PRBool callDestructors); |
-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 |
- |
-/* |
-** 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 |
- ts->stackTop = ts->allocBase; |
- ts->stackBottom = ts->allocBase - ts->stackSize; |
-#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; |
- if (pt_book.last) |
- pt_book.last->next = thred; |
- else |
- pt_book.first = 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); |
- if (NULL == thred->prev) |
- pt_book.first = thred->next; |
- else |
- 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 destructor 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 destructor do the work. |
- */ |
- if (PR_FALSE == detached) |
- { |
- /* Call TPD destructors on this thread. */ |
- _PR_DestroyThreadPrivate(thred); |
- 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; |
- if (pt_book.last) |
- pt_book.last->next = thred; |
- else |
- pt_book.first = 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 stackSize is 0, we use the default pthread stack size. |
- */ |
- if (stackSize) |
- { |
-#ifdef _MD_MINIMUM_STACK_SIZE |
- if (stackSize < _MD_MINIMUM_STACK_SIZE) |
- stackSize = _MD_MINIMUM_STACK_SIZE; |
-#endif |
- rv = pthread_attr_setstacksize(&tattr, stackSize); |
- PR_ASSERT(0 == rv); |
- } |
- |
- 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); |
- } |
- } |
- |
-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: %p 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 |
- /* |
- * PR_FALSE, because the thread already called the TPD |
- * destructors before exiting _pt_root. |
- */ |
- _pt_thread_death_internal(thred, PR_FALSE); |
- } |
- 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) |
-{ |
- void *thred; |
- int rv; |
- |
- _PT_PTHREAD_GETSPECIFIC(pt_book.key, thred); |
- if (NULL == thred) return; |
- _pt_thread_death(thred); |
- rv = pthread_setspecific(pt_book.key, NULL); |
- PR_ASSERT(0 == rv); |
-} /* 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_ATOMIC_INCREMENT(&cv->notify_pending); |
- rv = pthread_cond_broadcast(&cv->cv); |
- PR_ASSERT(0 == rv); |
- if (0 > PR_ATOMIC_DECREMENT(&cv->notify_pending)) |
- PR_DestroyCondVar(cv); |
- } |
- return PR_SUCCESS; |
-} /* PR_Interrupt */ |
- |
-PR_IMPLEMENT(void) PR_ClearInterrupt(void) |
-{ |
- PRThread *me = PR_GetCurrentThread(); |
- me->state &= ~PT_THREAD_ABORTED; |
-} /* PR_ClearInterrupt */ |
- |
-PR_IMPLEMENT(void) PR_BlockInterrupt(void) |
-{ |
- PRThread *me = PR_GetCurrentThread(); |
- _PT_THREAD_BLOCK_INTERRUPT(me); |
-} /* PR_BlockInterrupt */ |
- |
-PR_IMPLEMENT(void) PR_UnblockInterrupt(void) |
-{ |
- PRThread *me = PR_GetCurrentThread(); |
- _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) |
-{ |
- void *thred; |
- int rv; |
- |
- _PT_PTHREAD_GETSPECIFIC(pt_book.key, thred); |
- if (NULL == thred) |
- { |
- /* |
- * Have PR_GetCurrentThread return the expected value to the |
- * destructors. |
- */ |
- rv = pthread_setspecific(pt_book.key, arg); |
- PR_ASSERT(0 == rv); |
- } |
- |
- /* PR_TRUE for: call destructors */ |
- _pt_thread_death_internal(arg, PR_TRUE); |
- |
- if (NULL == thred) |
- { |
- rv = pthread_setspecific(pt_book.key, NULL); |
- PR_ASSERT(0 == rv); |
- } |
-} |
- |
-static void _pt_thread_death_internal(void *arg, PRBool callDestructors) |
-{ |
- PRThread *thred = (PRThread*)arg; |
- |
- if (thred->state & (PT_THREAD_FOREIGN|PT_THREAD_PRIMORD)) |
- { |
- PR_Lock(pt_book.ml); |
- if (NULL == thred->prev) |
- pt_book.first = thred->next; |
- else |
- 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); |
- } |
- if (callDestructors) |
- _PR_DestroyThreadPrivate(thred); |
- PR_Free(thred->privateData); |
- if (NULL != thred->errorString) |
- PR_Free(thred->errorString); |
- if (NULL != thred->name) |
- PR_Free(thred->name); |
- 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 */ |
- |
-#ifdef __GNUC__ |
-/* |
- * GCC supports the constructor and destructor attributes as of |
- * version 2.5. |
- */ |
-static void _PR_Fini(void) __attribute__ ((destructor)); |
-#elif defined(__SUNPRO_C) |
-/* |
- * Sun Studio compiler |
- */ |
-#pragma fini(_PR_Fini) |
-static void _PR_Fini(void); |
-#elif defined(HPUX) |
-/* |
- * Current versions of HP C compiler define __HP_cc. |
- * HP C compiler A.11.01.20 doesn't define __HP_cc. |
- */ |
-#if defined(__ia64) || defined(_LP64) |
-#pragma FINI "_PR_Fini" |
-static void _PR_Fini(void); |
-#else |
-/* |
- * Only HP-UX 10.x style initializers are supported in 32-bit links. |
- * Need to use the +I PR_HPUX10xInit linker option. |
- */ |
-#include <dl.h> |
- |
-static void _PR_Fini(void); |
- |
-void PR_HPUX10xInit(shl_t handle, int loading) |
-{ |
- /* |
- * This function is called when a shared library is loaded as well |
- * as when the shared library is unloaded. Note that it may not |
- * be called when the user's program terminates. |
- * |
- * handle is the shl_load API handle for the shared library being |
- * initialized. |
- * |
- * loading is non-zero at startup and zero at termination. |
- */ |
- if (loading) { |
- /* ... do some initializations ... */ |
- } else { |
- _PR_Fini(); |
- } |
-} |
-#endif |
-#elif defined(AIX) |
-/* Need to use the -binitfini::_PR_Fini linker option. */ |
-#endif |
- |
-void _PR_Fini(void) |
-{ |
- void *thred; |
- int rv; |
- |
- if (!_pr_initialized) return; |
- |
- _PT_PTHREAD_GETSPECIFIC(pt_book.key, thred); |
- if (NULL != thred) |
- { |
- /* |
- * PR_FALSE, because it is unsafe to call back to the |
- * thread private data destructors at final cleanup. |
- */ |
- _pt_thread_death_internal(thred, PR_FALSE); |
- rv = pthread_setspecific(pt_book.key, NULL); |
- PR_ASSERT(0 == rv); |
- } |
- rv = pthread_key_delete(pt_book.key); |
- PR_ASSERT(0 == rv); |
- /* TODO: free other resources used by NSPR */ |
- /* _pr_initialized = PR_FALSE; */ |
-} /* _PR_Fini */ |
- |
-PR_IMPLEMENT(PRStatus) PR_Cleanup(void) |
-{ |
- PRThread *me = PR_GetCurrentThread(); |
- int rv; |
- 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); |
- if (me->state & PT_THREAD_SYSTEM) |
- pt_book.system -= 1; |
- else |
- pt_book.user -= 1; |
- PR_Unlock(pt_book.ml); |
- |
- _PR_MD_EARLY_CLEANUP(); |
- |
- _PR_CleanupMW(); |
- _PR_CleanupTime(); |
- _PR_CleanupDtoa(); |
- _PR_CleanupCallOnce(); |
- _PR_ShutdownLinker(); |
- _PR_LogCleanup(); |
- _PR_CleanupNet(); |
- /* Close all the fd's before calling _PR_CleanupIO */ |
- _PR_CleanupIO(); |
- _PR_CleanupCMon(); |
- |
- _pt_thread_death(me); |
- rv = pthread_setspecific(pt_book.key, NULL); |
- PR_ASSERT(0 == rv); |
- /* |
- * 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; |
- } |
- 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_SIGTIMEDWAIT |
-static struct timespec hundredmillisec = {0, 100000000L}; |
-#endif |
- |
-static void suspend_signal_handler(PRIntn sig); |
- |
-#ifdef PT_NO_SIGTIMEDWAIT |
-static 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) |
-{ |
-#ifndef SYMBIAN |
- 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) */ |
-#endif /* SYMBIAN */ |
-} |
- |
-PR_IMPLEMENT(void) PR_SetThreadGCAble(void) |
-{ |
- PR_Lock(pt_book.ml); |
- PR_GetCurrentThread()->state |= PT_THREAD_GCABLE; |
- PR_Unlock(pt_book.ml); |
-} |
- |
-PR_IMPLEMENT(void) PR_ClearThreadGCAble(void) |
-{ |
- PR_Lock(pt_book.ml); |
- PR_GetCurrentThread()->state &= (~PT_THREAD_GCABLE); |
- PR_Unlock(pt_book.ml); |
-} |
- |
-#if defined(DEBUG) |
-static PRBool suspendAllOn = PR_FALSE; |
-#endif |
- |
-static 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; |
- |
-#if defined(DEBUG) || defined(FORCE_PR_ASSERT) |
-#if !defined(_PR_DCETHREADS) |
- PRThread *me = PR_GetCurrentThread(); |
-#endif |
-#endif |
- |
- 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 %p 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; |
-} |
-#endif |
- |
-static void suspend_signal_handler(PRIntn sig) |
-{ |
- PRThread *me = PR_GetCurrentThread(); |
- |
- 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 %p 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(UNIXWARE) \ |
- && !defined(DARWIN) && !defined(RISCOS) \ |
- && !defined(SYMBIAN) /*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 = %p 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 %p 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 %p tid = %X\n", |
- thred, thred->id)); |
-#if defined(SYMBIAN) |
- /* All signal group functions are not implemented in Symbian OS */ |
- rv = 0; |
-#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 %p 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 %p 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 %p 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(SYMBIAN) |
- /* All signal group functions are not implemented in Symbian OS */ |
-#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 %p 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 %p 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_GetCurrentThread(); |
- 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_GetCurrentThread(); |
- 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 %p thid = %X, sp = %p\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 %p \n", top_sp)); |
- return top_sp; |
-} /* PR_GetSP */ |
- |
-#endif /* !defined(_PR_DCETHREADS) */ |
- |
-PR_IMPLEMENT(PRStatus) PR_SetCurrentThreadName(const char *name) |
-{ |
- PRThread *thread; |
- size_t nameLen; |
- int result; |
- |
- if (!name) { |
- PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); |
- return PR_FAILURE; |
- } |
- |
- thread = PR_GetCurrentThread(); |
- if (!thread) |
- return PR_FAILURE; |
- |
- PR_Free(thread->name); |
- nameLen = strlen(name); |
- thread->name = (char *)PR_Malloc(nameLen + 1); |
- if (!thread->name) |
- return PR_FAILURE; |
- memcpy(thread->name, name, nameLen + 1); |
- |
-#if defined(OPENBSD) || defined(FREEBSD) |
- result = pthread_set_name_np(thread->id, name); |
-#else /* not BSD */ |
- /* |
- * On OSX, pthread_setname_np is only available in 10.6 or later, so test |
- * for it at runtime. It also may not be available on all linux distros. |
- */ |
-#if defined(DARWIN) |
- int (*dynamic_pthread_setname_np)(const char*); |
-#else |
- int (*dynamic_pthread_setname_np)(pthread_t, const char*); |
-#endif |
- |
- *(void**)(&dynamic_pthread_setname_np) = |
- dlsym(RTLD_DEFAULT, "pthread_setname_np"); |
- if (!dynamic_pthread_setname_np) |
- return PR_SUCCESS; |
- |
- /* |
- * The 15-character name length limit is an experimentally determined |
- * length of a null-terminated string that most linux distros and OS X |
- * accept as an argument to pthread_setname_np. Otherwise the E2BIG |
- * error is returned by the function. |
- */ |
-#define SETNAME_LENGTH_CONSTRAINT 15 |
-#define SETNAME_FRAGMENT1_LENGTH (SETNAME_LENGTH_CONSTRAINT >> 1) |
-#define SETNAME_FRAGMENT2_LENGTH \ |
- (SETNAME_LENGTH_CONSTRAINT - SETNAME_FRAGMENT1_LENGTH - 1) |
- char name_dup[SETNAME_LENGTH_CONSTRAINT + 1]; |
- if (nameLen > SETNAME_LENGTH_CONSTRAINT) { |
- memcpy(name_dup, name, SETNAME_FRAGMENT1_LENGTH); |
- name_dup[SETNAME_FRAGMENT1_LENGTH] = '~'; |
- /* Note that this also copies the null terminator. */ |
- memcpy(name_dup + SETNAME_FRAGMENT1_LENGTH + 1, |
- name + nameLen - SETNAME_FRAGMENT2_LENGTH, |
- SETNAME_FRAGMENT2_LENGTH + 1); |
- name = name_dup; |
- } |
- |
-#if defined(DARWIN) |
- result = dynamic_pthread_setname_np(name); |
-#else |
- result = dynamic_pthread_setname_np(thread->id, name); |
-#endif |
-#endif /* not BSD */ |
- |
- if (result) { |
- PR_SetError(PR_UNKNOWN_ERROR, result); |
- return PR_FAILURE; |
- } |
- return PR_SUCCESS; |
-} |
- |
-PR_IMPLEMENT(const char *) PR_GetThreadName(const PRThread *thread) |
-{ |
- if (!thread) |
- return NULL; |
- return thread->name; |
-} |
- |
-#endif /* defined(_PR_PTHREADS) || defined(_PR_DCETHREADS) */ |
- |
-/* ptthread.c */ |