diff options
author | cvs2hg <devnull@localhost> | 1999-08-05 01:09:52 +0000 |
---|---|---|
committer | cvs2hg <devnull@localhost> | 1999-08-05 01:09:52 +0000 |
commit | 2237a8cf73256cc0f4e920302f47d596d0a89a72 (patch) | |
tree | 13cb5769a592b958520a65b0abbba1163113043b | |
parent | 63b7612a829ee834b8d93d313ac8eddab3f89db4 (diff) | |
download | nspr-hg-2237a8cf73256cc0f4e920302f47d596d0a89a72.tar.gz |
fixup commit for branch 'unlabeled-3.19.12.2.4'
-rw-r--r-- | pr/src/pthreads/ptthread.c | 1462 |
1 files changed, 0 insertions, 1462 deletions
diff --git a/pr/src/pthreads/ptthread.c b/pr/src/pthreads/ptthread.c deleted file mode 100644 index 6e06e652..00000000 --- a/pr/src/pthreads/ptthread.c +++ /dev/null @@ -1,1462 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* - * The contents of this file are subject to the Netscape Public License - * Version 1.1 (the "NPL"); you may not use this file except in - * compliance with the NPL. You may obtain a copy of the NPL at - * http://www.mozilla.org/NPL/ - * - * Software distributed under the NPL is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL - * for the specific language governing rights and limitations under the - * NPL. - * - * The Initial Developer of this code under the NPL is Netscape - * Communications Corporation. Portions created by Netscape are - * Copyright (C) 1998 Netscape Communications Corporation. All Rights - * Reserved. - */ - -/* -** 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 */ - pthread_key_t highwater; /* ordinal value of next key to be allocated */ - 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) -{ - return pt_book.minPrio + - pri * (pt_book.maxPrio - pt_book.minPrio) / PR_PRIORITY_LAST; -} -#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; - 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); - 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; - - /* - * 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); - } - 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; - void *privateData = 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 = 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); -#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 */ - /* - * 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 = 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 = 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 = 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); - - PR_ASSERT(!"Illegal thread join attempt"); - } - 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() { } /* PR_DetachThread */ - -PR_IMPLEMENT(PRThread*) PR_GetCurrentThread() -{ - void *thred; - - if (!_pr_initialized) _PR_ImplicitInitialization(); - - 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; - - 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 */ - PR_ASSERT(-1 != rv); -#elif defined(_POSIX_THREAD_PRIORITY_SCHEDULING) - if (EPERM != pt_schedpriv) - { - int policy; - struct sched_param schedule; - - rv = pthread_getschedparam(thred->id, &policy, &schedule); - PR_ASSERT(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")); - } - } -#endif - - thred->priority = newPri; -} /* PR_SetThreadPriority */ - -#if 0 -PR_IMPLEMENT(PRStatus) PR_NewThreadPrivateIndex( - PRUintn *newIndex, PRThreadPrivateDTOR destructor) -{ - int rv; - - if (!_pr_initialized) _PR_ImplicitInitialization(); - - rv = PTHREAD_KEY_CREATE((pthread_key_t*)newIndex, destructor); - - if (0 == rv) - { - PR_Lock(pt_book.ml); - if (*newIndex >= pt_book.highwater) - pt_book.highwater = *newIndex + 1; - PR_Unlock(pt_book.ml); - return PR_SUCCESS; - } - PR_SetError(PR_UNKNOWN_ERROR, rv); - return PR_FAILURE; -} /* PR_NewThreadPrivateIndex */ - -PR_IMPLEMENT(PRStatus) PR_SetThreadPrivate(PRUintn index, void *priv) -{ - PRIntn rv; - if ((pthread_key_t)index >= pt_book.highwater) - { - PR_SetError(PR_TPD_RANGE_ERROR, 0); - return PR_FAILURE; - } - rv = pthread_setspecific((pthread_key_t)index, priv); - PR_ASSERT(0 == rv); - if (0 == rv) return PR_SUCCESS; - - PR_SetError(PR_UNKNOWN_ERROR, rv); - return PR_FAILURE; -} /* PR_SetThreadPrivate */ - -PR_IMPLEMENT(void*) PR_GetThreadPrivate(PRUintn index) -{ - void *result = NULL; - if ((pthread_key_t)index < pt_book.highwater) - PTHREAD_GETSPECIFIC((pthread_key_t)index, result); - return result; -} /* PR_GetThreadPrivate */ -#endif - -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) - { - PRIntn rv = pthread_cond_broadcast(&cv->cv); - PR_ASSERT(0 == rv); - } - return PR_SUCCESS; -} /* PR_Interrupt */ - -PR_IMPLEMENT(void) PR_ClearInterrupt() -{ - PRThread *me = PR_CurrentThread(); - me->state &= ~PT_THREAD_ABORTED; -} /* PR_ClearInterrupt */ - -PR_IMPLEMENT(PRStatus) PR_Yield() -{ - 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; - - if (!_pr_initialized) _PR_ImplicitInitialization(); - - if (PR_INTERVAL_NO_WAIT == ticks) - { - PTHREAD_YIELD(); - rv = PR_SUCCESS; - } - 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); - if (NULL != thred->errorString) - PR_Free(thred->errorString); - if (NULL != thred->io_cv) - PR_DestroyCondVar(thred->io_cv); - PR_Free(thred->stack); -#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) - /* - ** These might be function evaluations - */ - pt_book.minPrio = PT_PRIO_MIN; - pt_book.maxPrio = PT_PRIO_MAX; -#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 = 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() -{ - 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_LogCleanup(); - /* Close all the fd's before calling _PR_CleanupFdCache */ - _PR_CleanupFdCache(); - - /* - * 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_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}; -static struct timespec hundredmillisec = {0, 100000000L}; - -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() -{ - 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 = {0}; - - 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 = {0}; - 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() -{ - PR_Lock(pt_book.ml); - PR_CurrentThread()->state |= PT_THREAD_GCABLE; - PR_Unlock(pt_book.ml); -} - -PR_IMPLEMENT(void) PR_ClearThreadGCAble() -{ - PR_Lock(pt_book.ml); - PR_CurrentThread()->state &= (~PT_THREAD_GCABLE); - PR_Unlock(pt_book.ml); -} - -#if defined(DEBUG) -static PRBool suspendAllOn = PR_FALSE; -#endif - -static PRBool suspendAllSuspended = PR_FALSE; - -/* Are all GCAble threads (except gc'ing thread) suspended? */ -PR_IMPLEMENT(PRBool) PR_SuspendAllSuspended() -{ - return suspendAllSuspended; -} /* PR_SuspendAllSuspended */ - -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 (thred->state & PT_THREAD_GCABLE) - { -#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; -} -#endif - -static void suspend_signal_handler(PRIntn sig) -{ - PRThread *me = PR_CurrentThread(); - - PR_ASSERT(me != NULL); - PR_ASSERT(me->state & PT_THREAD_GCABLE); - 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) /*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 PR_SuspendSet(PRThread *thred) -{ - PRIntn rv; - - PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, - ("PR_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 PR_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 PR_SuspendTest(PRThread *thred) -{ - PRIntn rv; - - PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, - ("Begin PR_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) - { - rv = sigtimedwait(&sigwait_set, NULL, &onemillisec); - PR_ASSERT(-1 == rv); - } -#endif - - PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, - ("End PR_SuspendTest thred %X tid %X\n", thred, thred->id)); -} /* PR_SuspendTest */ - -PR_IMPLEMENT(void) PR_ResumeSet(PRThread *thred) -{ - PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, - ("PR_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 - -} /* PR_ResumeSet */ - -PR_IMPLEMENT(void) PR_ResumeTest(PRThread *thred) -{ - PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, - ("Begin PR_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 PR_ResumeTest thred %X tid %X\n", thred, thred->id)); -} /* PR_ResumeTest */ - -static pthread_once_t pt_gc_support_control = PTHREAD_ONCE_INIT; - -PR_IMPLEMENT(void) PR_SuspendAll() -{ -#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) && (thred->state & PT_THREAD_GCABLE)) - PR_SuspendSet(thred); - thred = thred->next; - } - - /* Wait till they are really suspended */ - thred = pt_book.first; - while (thred != NULL) - { - if ((thred != me) && (thred->state & PT_THREAD_GCABLE)) - PR_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() -{ -#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) && (thred->state & PT_THREAD_GCABLE)) - PR_ResumeSet(thred); - thred = thred->next; - } - - thred = pt_book.first; - while (thred != NULL) - { - if ((thred != me) && (thred->state & PT_THREAD_GCABLE)) - PR_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 */ |