1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/nsprpub/pr/src/pthreads/ptthread.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1814 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/* 1.10 +** File: ptthread.c 1.11 +** Descritpion: Implemenation for threds using pthreds 1.12 +** Exports: ptthread.h 1.13 +*/ 1.14 + 1.15 +#if defined(_PR_PTHREADS) || defined(_PR_DCETHREADS) 1.16 + 1.17 +#include "prlog.h" 1.18 +#include "primpl.h" 1.19 +#include "prpdce.h" 1.20 + 1.21 +#include <pthread.h> 1.22 +#include <unistd.h> 1.23 +#include <string.h> 1.24 +#include <signal.h> 1.25 +#include <dlfcn.h> 1.26 + 1.27 +#ifdef SYMBIAN 1.28 +/* In Open C sched_get_priority_min/max do not work properly, so we undefine 1.29 + * _POSIX_THREAD_PRIORITY_SCHEDULING here. 1.30 + */ 1.31 +#undef _POSIX_THREAD_PRIORITY_SCHEDULING 1.32 +#endif 1.33 + 1.34 +#ifdef _PR_NICE_PRIORITY_SCHEDULING 1.35 +#undef _POSIX_THREAD_PRIORITY_SCHEDULING 1.36 +#include <sys/resource.h> 1.37 +#ifndef HAVE_GETTID 1.38 +#define gettid() (syscall(SYS_gettid)) 1.39 +#endif 1.40 +#endif 1.41 + 1.42 +/* 1.43 + * Record whether or not we have the privilege to set the scheduling 1.44 + * policy and priority of threads. 0 means that privilege is available. 1.45 + * EPERM means that privilege is not available. 1.46 + */ 1.47 + 1.48 +static PRIntn pt_schedpriv = 0; 1.49 +extern PRLock *_pr_sleeplock; 1.50 + 1.51 +static struct _PT_Bookeeping 1.52 +{ 1.53 + PRLock *ml; /* a lock to protect ourselves */ 1.54 + PRCondVar *cv; /* used to signal global things */ 1.55 + PRInt32 system, user; /* a count of the two different types */ 1.56 + PRUintn this_many; /* number of threads allowed for exit */ 1.57 + pthread_key_t key; /* thread private data key */ 1.58 + PRBool keyCreated; /* whether 'key' should be deleted */ 1.59 + PRThread *first, *last; /* list of threads we know about */ 1.60 +#if defined(_PR_DCETHREADS) || defined(_POSIX_THREAD_PRIORITY_SCHEDULING) 1.61 + PRInt32 minPrio, maxPrio; /* range of scheduling priorities */ 1.62 +#endif 1.63 +} pt_book = {0}; 1.64 + 1.65 +static void _pt_thread_death(void *arg); 1.66 +static void _pt_thread_death_internal(void *arg, PRBool callDestructors); 1.67 +static void init_pthread_gc_support(void); 1.68 + 1.69 +#if defined(_PR_DCETHREADS) || defined(_POSIX_THREAD_PRIORITY_SCHEDULING) 1.70 +static PRIntn pt_PriorityMap(PRThreadPriority pri) 1.71 +{ 1.72 +#ifdef NTO 1.73 + /* This priority algorithm causes lots of problems on Neutrino 1.74 + * for now I have just hard coded everything to run at priority 10 1.75 + * until I can come up with a new algorithm. 1.76 + * Jerry.Kirk@Nexwarecorp.com 1.77 + */ 1.78 + return 10; 1.79 +#else 1.80 + return pt_book.minPrio + 1.81 + pri * (pt_book.maxPrio - pt_book.minPrio) / PR_PRIORITY_LAST; 1.82 +#endif 1.83 +} 1.84 +#elif defined(_PR_NICE_PRIORITY_SCHEDULING) 1.85 +/* 1.86 + * This functions maps higher priorities to lower nice values relative to the 1.87 + * nice value specified in the |nice| parameter. The corresponding relative 1.88 + * adjustments are: 1.89 + * 1.90 + * PR_PRIORITY_LOW +1 1.91 + * PR_PRIORITY_NORMAL 0 1.92 + * PR_PRIORITY_HIGH -1 1.93 + * PR_PRIORITY_URGENT -2 1.94 + */ 1.95 +static int pt_RelativePriority(int nice, PRThreadPriority pri) 1.96 +{ 1.97 + return nice + (1 - pri); 1.98 +} 1.99 +#endif 1.100 + 1.101 +/* 1.102 +** Initialize a stack for a native pthread thread 1.103 +*/ 1.104 +static void _PR_InitializeStack(PRThreadStack *ts) 1.105 +{ 1.106 + if( ts && (ts->stackTop == 0) ) { 1.107 + ts->allocBase = (char *) &ts; 1.108 + ts->allocSize = ts->stackSize; 1.109 + 1.110 + /* 1.111 + ** Setup stackTop and stackBottom values. 1.112 + */ 1.113 +#ifdef HAVE_STACK_GROWING_UP 1.114 + ts->stackBottom = ts->allocBase + ts->stackSize; 1.115 + ts->stackTop = ts->allocBase; 1.116 +#else 1.117 + ts->stackTop = ts->allocBase; 1.118 + ts->stackBottom = ts->allocBase - ts->stackSize; 1.119 +#endif 1.120 + } 1.121 +} 1.122 + 1.123 +static void *_pt_root(void *arg) 1.124 +{ 1.125 + PRIntn rv; 1.126 + PRThread *thred = (PRThread*)arg; 1.127 + PRBool detached = (thred->state & PT_THREAD_DETACHED) ? PR_TRUE : PR_FALSE; 1.128 + pthread_t id = pthread_self(); 1.129 +#ifdef _PR_NICE_PRIORITY_SCHEDULING 1.130 + pid_t tid; 1.131 +#endif 1.132 + 1.133 +#ifdef _PR_NICE_PRIORITY_SCHEDULING 1.134 + /* 1.135 + * We need to know the kernel thread ID of each thread in order to 1.136 + * set its nice value hence we do it here instead of at creation time. 1.137 + */ 1.138 + tid = gettid(); 1.139 + errno = 0; 1.140 + rv = getpriority(PRIO_PROCESS, 0); 1.141 + 1.142 + /* If we cannot read the main thread's nice value don't try to change the 1.143 + * new thread's nice value. */ 1.144 + if (errno == 0) { 1.145 + setpriority(PRIO_PROCESS, tid, 1.146 + pt_RelativePriority(rv, thred->priority)); 1.147 + } 1.148 +#endif 1.149 + 1.150 + /* 1.151 + ** DCE Threads can't detach during creation, so do it late. 1.152 + ** I would like to do it only here, but that doesn't seem 1.153 + ** to work. 1.154 + */ 1.155 +#if defined(_PR_DCETHREADS) 1.156 + if (detached) 1.157 + { 1.158 + /* pthread_detach() modifies its argument, so we must pass a copy */ 1.159 + pthread_t self = id; 1.160 + rv = pthread_detach(&self); 1.161 + PR_ASSERT(0 == rv); 1.162 + } 1.163 +#endif /* defined(_PR_DCETHREADS) */ 1.164 + 1.165 + /* Set up the thread stack information */ 1.166 + _PR_InitializeStack(thred->stack); 1.167 + 1.168 + /* 1.169 + * Set within the current thread the pointer to our object. 1.170 + * This object will be deleted when the thread termintates, 1.171 + * whether in a join or detached (see _PR_InitThreads()). 1.172 + */ 1.173 + rv = pthread_setspecific(pt_book.key, thred); 1.174 + PR_ASSERT(0 == rv); 1.175 + 1.176 + /* make the thread visible to the rest of the runtime */ 1.177 + PR_Lock(pt_book.ml); 1.178 + /* 1.179 + * Both the parent thread and this new thread set thred->id. 1.180 + * The new thread must ensure that thred->id is set before 1.181 + * it executes its startFunc. The parent thread must ensure 1.182 + * that thred->id is set before PR_CreateThread() returns. 1.183 + * Both threads set thred->id while holding pt_book.ml and 1.184 + * use thred->idSet to ensure thred->id is written only once. 1.185 + */ 1.186 + if (!thred->idSet) 1.187 + { 1.188 + thred->id = id; 1.189 + thred->idSet = PR_TRUE; 1.190 + } 1.191 + else 1.192 + { 1.193 + PR_ASSERT(pthread_equal(thred->id, id)); 1.194 + } 1.195 + 1.196 +#ifdef _PR_NICE_PRIORITY_SCHEDULING 1.197 + thred->tid = tid; 1.198 + PR_NotifyAllCondVar(pt_book.cv); 1.199 +#endif 1.200 + 1.201 + /* If this is a GCABLE thread, set its state appropriately */ 1.202 + if (thred->suspend & PT_THREAD_SETGCABLE) 1.203 + thred->state |= PT_THREAD_GCABLE; 1.204 + thred->suspend = 0; 1.205 + 1.206 + thred->prev = pt_book.last; 1.207 + if (pt_book.last) 1.208 + pt_book.last->next = thred; 1.209 + else 1.210 + pt_book.first = thred; 1.211 + thred->next = NULL; 1.212 + pt_book.last = thred; 1.213 + PR_Unlock(pt_book.ml); 1.214 + 1.215 + thred->startFunc(thred->arg); /* make visible to the client */ 1.216 + 1.217 + /* unhook the thread from the runtime */ 1.218 + PR_Lock(pt_book.ml); 1.219 + /* 1.220 + * At this moment, PR_CreateThread() may not have set thred->id yet. 1.221 + * It is safe for a detached thread to free thred only after 1.222 + * PR_CreateThread() has accessed thred->id and thred->idSet. 1.223 + */ 1.224 + if (detached) 1.225 + { 1.226 + while (!thred->okToDelete) 1.227 + PR_WaitCondVar(pt_book.cv, PR_INTERVAL_NO_TIMEOUT); 1.228 + } 1.229 + 1.230 + if (thred->state & PT_THREAD_SYSTEM) 1.231 + pt_book.system -= 1; 1.232 + else if (--pt_book.user == pt_book.this_many) 1.233 + PR_NotifyAllCondVar(pt_book.cv); 1.234 + if (NULL == thred->prev) 1.235 + pt_book.first = thred->next; 1.236 + else 1.237 + thred->prev->next = thred->next; 1.238 + if (NULL == thred->next) 1.239 + pt_book.last = thred->prev; 1.240 + else 1.241 + thred->next->prev = thred->prev; 1.242 + PR_Unlock(pt_book.ml); 1.243 + 1.244 + /* 1.245 + * Here we set the pthread's backpointer to the PRThread to NULL. 1.246 + * Otherwise the destructor would get called eagerly as the thread 1.247 + * returns to the pthread runtime. The joining thread would them be 1.248 + * the proud possessor of a dangling reference. However, this is the 1.249 + * last chance to delete the object if the thread is detached, so 1.250 + * just let the destructor do the work. 1.251 + */ 1.252 + if (PR_FALSE == detached) 1.253 + { 1.254 + /* Call TPD destructors on this thread. */ 1.255 + _PR_DestroyThreadPrivate(thred); 1.256 + rv = pthread_setspecific(pt_book.key, NULL); 1.257 + PR_ASSERT(0 == rv); 1.258 + } 1.259 + 1.260 + return NULL; 1.261 +} /* _pt_root */ 1.262 + 1.263 +static PRThread* pt_AttachThread(void) 1.264 +{ 1.265 + PRThread *thred = NULL; 1.266 + 1.267 + /* 1.268 + * NSPR must have been initialized when PR_AttachThread is called. 1.269 + * We cannot have PR_AttachThread call implicit initialization 1.270 + * because if multiple threads call PR_AttachThread simultaneously, 1.271 + * NSPR may be initialized more than once. 1.272 + * We can't call any function that calls PR_GetCurrentThread() 1.273 + * either (e.g., PR_SetError()) as that will result in infinite 1.274 + * recursion. 1.275 + */ 1.276 + if (!_pr_initialized) return NULL; 1.277 + 1.278 + /* PR_NEWZAP must not call PR_GetCurrentThread() */ 1.279 + thred = PR_NEWZAP(PRThread); 1.280 + if (NULL != thred) 1.281 + { 1.282 + int rv; 1.283 + 1.284 + thred->priority = PR_PRIORITY_NORMAL; 1.285 + thred->id = pthread_self(); 1.286 + thred->idSet = PR_TRUE; 1.287 +#ifdef _PR_NICE_PRIORITY_SCHEDULING 1.288 + thred->tid = gettid(); 1.289 +#endif 1.290 + rv = pthread_setspecific(pt_book.key, thred); 1.291 + PR_ASSERT(0 == rv); 1.292 + 1.293 + thred->state = PT_THREAD_GLOBAL | PT_THREAD_FOREIGN; 1.294 + PR_Lock(pt_book.ml); 1.295 + 1.296 + /* then put it into the list */ 1.297 + thred->prev = pt_book.last; 1.298 + if (pt_book.last) 1.299 + pt_book.last->next = thred; 1.300 + else 1.301 + pt_book.first = thred; 1.302 + thred->next = NULL; 1.303 + pt_book.last = thred; 1.304 + PR_Unlock(pt_book.ml); 1.305 + 1.306 + } 1.307 + return thred; /* may be NULL */ 1.308 +} /* pt_AttachThread */ 1.309 + 1.310 +static PRThread* _PR_CreateThread( 1.311 + PRThreadType type, void (*start)(void *arg), 1.312 + void *arg, PRThreadPriority priority, PRThreadScope scope, 1.313 + PRThreadState state, PRUint32 stackSize, PRBool isGCAble) 1.314 +{ 1.315 + int rv; 1.316 + PRThread *thred; 1.317 + pthread_attr_t tattr; 1.318 + 1.319 + if (!_pr_initialized) _PR_ImplicitInitialization(); 1.320 + 1.321 + if ((PRIntn)PR_PRIORITY_FIRST > (PRIntn)priority) 1.322 + priority = PR_PRIORITY_FIRST; 1.323 + else if ((PRIntn)PR_PRIORITY_LAST < (PRIntn)priority) 1.324 + priority = PR_PRIORITY_LAST; 1.325 + 1.326 + rv = _PT_PTHREAD_ATTR_INIT(&tattr); 1.327 + PR_ASSERT(0 == rv); 1.328 + 1.329 + if (EPERM != pt_schedpriv) 1.330 + { 1.331 +#if !defined(_PR_DCETHREADS) && defined(_POSIX_THREAD_PRIORITY_SCHEDULING) 1.332 + struct sched_param schedule; 1.333 +#endif 1.334 + 1.335 +#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) 1.336 + rv = pthread_attr_setinheritsched(&tattr, PTHREAD_EXPLICIT_SCHED); 1.337 + PR_ASSERT(0 == rv); 1.338 +#endif 1.339 + 1.340 + /* Use the default scheduling policy */ 1.341 + 1.342 +#if defined(_PR_DCETHREADS) 1.343 + rv = pthread_attr_setprio(&tattr, pt_PriorityMap(priority)); 1.344 + PR_ASSERT(0 == rv); 1.345 +#elif defined(_POSIX_THREAD_PRIORITY_SCHEDULING) 1.346 + rv = pthread_attr_getschedparam(&tattr, &schedule); 1.347 + PR_ASSERT(0 == rv); 1.348 + schedule.sched_priority = pt_PriorityMap(priority); 1.349 + rv = pthread_attr_setschedparam(&tattr, &schedule); 1.350 + PR_ASSERT(0 == rv); 1.351 +#ifdef NTO 1.352 + rv = pthread_attr_setschedpolicy(&tattr, SCHED_RR); /* Round Robin */ 1.353 + PR_ASSERT(0 == rv); 1.354 +#endif 1.355 +#endif /* !defined(_PR_DCETHREADS) */ 1.356 + } 1.357 + 1.358 + /* 1.359 + * DCE threads can't set detach state before creating the thread. 1.360 + * AIX can't set detach late. Why can't we all just get along? 1.361 + */ 1.362 +#if !defined(_PR_DCETHREADS) 1.363 + rv = pthread_attr_setdetachstate(&tattr, 1.364 + ((PR_JOINABLE_THREAD == state) ? 1.365 + PTHREAD_CREATE_JOINABLE : PTHREAD_CREATE_DETACHED)); 1.366 + PR_ASSERT(0 == rv); 1.367 +#endif /* !defined(_PR_DCETHREADS) */ 1.368 + 1.369 + /* 1.370 + * If stackSize is 0, we use the default pthread stack size. 1.371 + */ 1.372 + if (stackSize) 1.373 + { 1.374 +#ifdef _MD_MINIMUM_STACK_SIZE 1.375 + if (stackSize < _MD_MINIMUM_STACK_SIZE) 1.376 + stackSize = _MD_MINIMUM_STACK_SIZE; 1.377 +#endif 1.378 + rv = pthread_attr_setstacksize(&tattr, stackSize); 1.379 + PR_ASSERT(0 == rv); 1.380 + } 1.381 + 1.382 + thred = PR_NEWZAP(PRThread); 1.383 + if (NULL == thred) 1.384 + { 1.385 + PR_SetError(PR_OUT_OF_MEMORY_ERROR, errno); 1.386 + goto done; 1.387 + } 1.388 + else 1.389 + { 1.390 + pthread_t id; 1.391 + 1.392 + thred->arg = arg; 1.393 + thred->startFunc = start; 1.394 + thred->priority = priority; 1.395 + if (PR_UNJOINABLE_THREAD == state) 1.396 + thred->state |= PT_THREAD_DETACHED; 1.397 + 1.398 + if (PR_LOCAL_THREAD == scope) 1.399 + scope = PR_GLOBAL_THREAD; 1.400 + 1.401 + if (PR_GLOBAL_BOUND_THREAD == scope) { 1.402 +#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) 1.403 + rv = pthread_attr_setscope(&tattr, PTHREAD_SCOPE_SYSTEM); 1.404 + if (rv) { 1.405 + /* 1.406 + * system scope not supported 1.407 + */ 1.408 + scope = PR_GLOBAL_THREAD; 1.409 + /* 1.410 + * reset scope 1.411 + */ 1.412 + rv = pthread_attr_setscope(&tattr, PTHREAD_SCOPE_PROCESS); 1.413 + PR_ASSERT(0 == rv); 1.414 + } 1.415 +#endif 1.416 + } 1.417 + if (PR_GLOBAL_THREAD == scope) 1.418 + thred->state |= PT_THREAD_GLOBAL; 1.419 + else if (PR_GLOBAL_BOUND_THREAD == scope) 1.420 + thred->state |= (PT_THREAD_GLOBAL | PT_THREAD_BOUND); 1.421 + else /* force it global */ 1.422 + thred->state |= PT_THREAD_GLOBAL; 1.423 + if (PR_SYSTEM_THREAD == type) 1.424 + thred->state |= PT_THREAD_SYSTEM; 1.425 + 1.426 + thred->suspend =(isGCAble) ? PT_THREAD_SETGCABLE : 0; 1.427 + 1.428 + thred->stack = PR_NEWZAP(PRThreadStack); 1.429 + if (thred->stack == NULL) { 1.430 + PRIntn oserr = errno; 1.431 + PR_Free(thred); /* all that work ... poof! */ 1.432 + PR_SetError(PR_OUT_OF_MEMORY_ERROR, oserr); 1.433 + thred = NULL; /* and for what? */ 1.434 + goto done; 1.435 + } 1.436 + thred->stack->stackSize = stackSize; 1.437 + thred->stack->thr = thred; 1.438 + 1.439 +#ifdef PT_NO_SIGTIMEDWAIT 1.440 + pthread_mutex_init(&thred->suspendResumeMutex,NULL); 1.441 + pthread_cond_init(&thred->suspendResumeCV,NULL); 1.442 +#endif 1.443 + 1.444 + /* make the thread counted to the rest of the runtime */ 1.445 + PR_Lock(pt_book.ml); 1.446 + if (PR_SYSTEM_THREAD == type) 1.447 + pt_book.system += 1; 1.448 + else pt_book.user += 1; 1.449 + PR_Unlock(pt_book.ml); 1.450 + 1.451 + /* 1.452 + * We pass a pointer to a local copy (instead of thred->id) 1.453 + * to pthread_create() because who knows what wacky things 1.454 + * pthread_create() may be doing to its argument. 1.455 + */ 1.456 + rv = _PT_PTHREAD_CREATE(&id, tattr, _pt_root, thred); 1.457 + 1.458 +#if !defined(_PR_DCETHREADS) 1.459 + if (EPERM == rv) 1.460 + { 1.461 +#if defined(IRIX) 1.462 + if (PR_GLOBAL_BOUND_THREAD == scope) { 1.463 + /* 1.464 + * SCOPE_SYSTEM requires appropriate privilege 1.465 + * reset to process scope and try again 1.466 + */ 1.467 + rv = pthread_attr_setscope(&tattr, PTHREAD_SCOPE_PROCESS); 1.468 + PR_ASSERT(0 == rv); 1.469 + thred->state &= ~PT_THREAD_BOUND; 1.470 + } 1.471 +#else 1.472 + /* Remember that we don't have thread scheduling privilege. */ 1.473 + pt_schedpriv = EPERM; 1.474 + PR_LOG(_pr_thread_lm, PR_LOG_MIN, 1.475 + ("_PR_CreateThread: no thread scheduling privilege")); 1.476 + /* Try creating the thread again without setting priority. */ 1.477 +#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) 1.478 + rv = pthread_attr_setinheritsched(&tattr, PTHREAD_INHERIT_SCHED); 1.479 + PR_ASSERT(0 == rv); 1.480 +#endif 1.481 +#endif /* IRIX */ 1.482 + rv = _PT_PTHREAD_CREATE(&id, tattr, _pt_root, thred); 1.483 + } 1.484 +#endif 1.485 + 1.486 + if (0 != rv) 1.487 + { 1.488 +#if defined(_PR_DCETHREADS) 1.489 + PRIntn oserr = errno; 1.490 +#else 1.491 + PRIntn oserr = rv; 1.492 +#endif 1.493 + PR_Lock(pt_book.ml); 1.494 + if (thred->state & PT_THREAD_SYSTEM) 1.495 + pt_book.system -= 1; 1.496 + else if (--pt_book.user == pt_book.this_many) 1.497 + PR_NotifyAllCondVar(pt_book.cv); 1.498 + PR_Unlock(pt_book.ml); 1.499 + 1.500 + PR_Free(thred->stack); 1.501 + PR_Free(thred); /* all that work ... poof! */ 1.502 + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, oserr); 1.503 + thred = NULL; /* and for what? */ 1.504 + goto done; 1.505 + } 1.506 + 1.507 + PR_Lock(pt_book.ml); 1.508 + /* 1.509 + * Both the parent thread and this new thread set thred->id. 1.510 + * The parent thread must ensure that thred->id is set before 1.511 + * PR_CreateThread() returns. (See comments in _pt_root().) 1.512 + */ 1.513 + if (!thred->idSet) 1.514 + { 1.515 + thred->id = id; 1.516 + thred->idSet = PR_TRUE; 1.517 + } 1.518 + else 1.519 + { 1.520 + PR_ASSERT(pthread_equal(thred->id, id)); 1.521 + } 1.522 + 1.523 + /* 1.524 + * If the new thread is detached, tell it that PR_CreateThread() has 1.525 + * accessed thred->id and thred->idSet so it's ok to delete thred. 1.526 + */ 1.527 + if (PR_UNJOINABLE_THREAD == state) 1.528 + { 1.529 + thred->okToDelete = PR_TRUE; 1.530 + PR_NotifyAllCondVar(pt_book.cv); 1.531 + } 1.532 + PR_Unlock(pt_book.ml); 1.533 + } 1.534 + 1.535 +done: 1.536 + rv = _PT_PTHREAD_ATTR_DESTROY(&tattr); 1.537 + PR_ASSERT(0 == rv); 1.538 + 1.539 + return thred; 1.540 +} /* _PR_CreateThread */ 1.541 + 1.542 +PR_IMPLEMENT(PRThread*) PR_CreateThread( 1.543 + PRThreadType type, void (*start)(void *arg), void *arg, 1.544 + PRThreadPriority priority, PRThreadScope scope, 1.545 + PRThreadState state, PRUint32 stackSize) 1.546 +{ 1.547 + return _PR_CreateThread( 1.548 + type, start, arg, priority, scope, state, stackSize, PR_FALSE); 1.549 +} /* PR_CreateThread */ 1.550 + 1.551 +PR_IMPLEMENT(PRThread*) PR_CreateThreadGCAble( 1.552 + PRThreadType type, void (*start)(void *arg), void *arg, 1.553 + PRThreadPriority priority, PRThreadScope scope, 1.554 + PRThreadState state, PRUint32 stackSize) 1.555 +{ 1.556 + return _PR_CreateThread( 1.557 + type, start, arg, priority, scope, state, stackSize, PR_TRUE); 1.558 +} /* PR_CreateThreadGCAble */ 1.559 + 1.560 +PR_IMPLEMENT(void*) GetExecutionEnvironment(PRThread *thred) 1.561 +{ 1.562 + return thred->environment; 1.563 +} /* GetExecutionEnvironment */ 1.564 + 1.565 +PR_IMPLEMENT(void) SetExecutionEnvironment(PRThread *thred, void *env) 1.566 +{ 1.567 + thred->environment = env; 1.568 +} /* SetExecutionEnvironment */ 1.569 + 1.570 +PR_IMPLEMENT(PRThread*) PR_AttachThread( 1.571 + PRThreadType type, PRThreadPriority priority, PRThreadStack *stack) 1.572 +{ 1.573 + return PR_GetCurrentThread(); 1.574 +} /* PR_AttachThread */ 1.575 + 1.576 + 1.577 +PR_IMPLEMENT(PRStatus) PR_JoinThread(PRThread *thred) 1.578 +{ 1.579 + int rv = -1; 1.580 + void *result = NULL; 1.581 + PR_ASSERT(thred != NULL); 1.582 + 1.583 + if ((0xafafafaf == thred->state) 1.584 + || (PT_THREAD_DETACHED == (PT_THREAD_DETACHED & thred->state)) 1.585 + || (PT_THREAD_FOREIGN == (PT_THREAD_FOREIGN & thred->state))) 1.586 + { 1.587 + /* 1.588 + * This might be a bad address, but if it isn't, the state should 1.589 + * either be an unjoinable thread or it's already had the object 1.590 + * deleted. However, the client that called join on a detached 1.591 + * thread deserves all the rath I can muster.... 1.592 + */ 1.593 + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); 1.594 + PR_LogPrint( 1.595 + "PR_JoinThread: %p not joinable | already smashed\n", thred); 1.596 + } 1.597 + else 1.598 + { 1.599 + pthread_t id = thred->id; 1.600 + rv = pthread_join(id, &result); 1.601 + PR_ASSERT(rv == 0 && result == NULL); 1.602 + if (0 == rv) 1.603 + { 1.604 +#ifdef _PR_DCETHREADS 1.605 + rv = pthread_detach(&id); 1.606 + PR_ASSERT(0 == rv); 1.607 +#endif 1.608 + /* 1.609 + * PR_FALSE, because the thread already called the TPD 1.610 + * destructors before exiting _pt_root. 1.611 + */ 1.612 + _pt_thread_death_internal(thred, PR_FALSE); 1.613 + } 1.614 + else 1.615 + { 1.616 + PRErrorCode prerror; 1.617 + switch (rv) 1.618 + { 1.619 + case EINVAL: /* not a joinable thread */ 1.620 + case ESRCH: /* no thread with given ID */ 1.621 + prerror = PR_INVALID_ARGUMENT_ERROR; 1.622 + break; 1.623 + case EDEADLK: /* a thread joining with itself */ 1.624 + prerror = PR_DEADLOCK_ERROR; 1.625 + break; 1.626 + default: 1.627 + prerror = PR_UNKNOWN_ERROR; 1.628 + break; 1.629 + } 1.630 + PR_SetError(prerror, rv); 1.631 + } 1.632 + } 1.633 + return (0 == rv) ? PR_SUCCESS : PR_FAILURE; 1.634 +} /* PR_JoinThread */ 1.635 + 1.636 +PR_IMPLEMENT(void) PR_DetachThread(void) 1.637 +{ 1.638 + void *thred; 1.639 + int rv; 1.640 + 1.641 + _PT_PTHREAD_GETSPECIFIC(pt_book.key, thred); 1.642 + if (NULL == thred) return; 1.643 + _pt_thread_death(thred); 1.644 + rv = pthread_setspecific(pt_book.key, NULL); 1.645 + PR_ASSERT(0 == rv); 1.646 +} /* PR_DetachThread */ 1.647 + 1.648 +PR_IMPLEMENT(PRThread*) PR_GetCurrentThread(void) 1.649 +{ 1.650 + void *thred; 1.651 + 1.652 + if (!_pr_initialized) _PR_ImplicitInitialization(); 1.653 + 1.654 + _PT_PTHREAD_GETSPECIFIC(pt_book.key, thred); 1.655 + if (NULL == thred) thred = pt_AttachThread(); 1.656 + PR_ASSERT(NULL != thred); 1.657 + return (PRThread*)thred; 1.658 +} /* PR_GetCurrentThread */ 1.659 + 1.660 +PR_IMPLEMENT(PRThreadScope) PR_GetThreadScope(const PRThread *thred) 1.661 +{ 1.662 + return (thred->state & PT_THREAD_BOUND) ? 1.663 + PR_GLOBAL_BOUND_THREAD : PR_GLOBAL_THREAD; 1.664 +} /* PR_GetThreadScope() */ 1.665 + 1.666 +PR_IMPLEMENT(PRThreadType) PR_GetThreadType(const PRThread *thred) 1.667 +{ 1.668 + return (thred->state & PT_THREAD_SYSTEM) ? 1.669 + PR_SYSTEM_THREAD : PR_USER_THREAD; 1.670 +} 1.671 + 1.672 +PR_IMPLEMENT(PRThreadState) PR_GetThreadState(const PRThread *thred) 1.673 +{ 1.674 + return (thred->state & PT_THREAD_DETACHED) ? 1.675 + PR_UNJOINABLE_THREAD : PR_JOINABLE_THREAD; 1.676 +} /* PR_GetThreadState */ 1.677 + 1.678 +PR_IMPLEMENT(PRThreadPriority) PR_GetThreadPriority(const PRThread *thred) 1.679 +{ 1.680 + PR_ASSERT(thred != NULL); 1.681 + return thred->priority; 1.682 +} /* PR_GetThreadPriority */ 1.683 + 1.684 +PR_IMPLEMENT(void) PR_SetThreadPriority(PRThread *thred, PRThreadPriority newPri) 1.685 +{ 1.686 + PRIntn rv = -1; 1.687 + 1.688 + PR_ASSERT(NULL != thred); 1.689 + 1.690 + if ((PRIntn)PR_PRIORITY_FIRST > (PRIntn)newPri) 1.691 + newPri = PR_PRIORITY_FIRST; 1.692 + else if ((PRIntn)PR_PRIORITY_LAST < (PRIntn)newPri) 1.693 + newPri = PR_PRIORITY_LAST; 1.694 + 1.695 +#if defined(_PR_DCETHREADS) 1.696 + rv = pthread_setprio(thred->id, pt_PriorityMap(newPri)); 1.697 + /* pthread_setprio returns the old priority */ 1.698 +#elif defined(_POSIX_THREAD_PRIORITY_SCHEDULING) 1.699 + if (EPERM != pt_schedpriv) 1.700 + { 1.701 + int policy; 1.702 + struct sched_param schedule; 1.703 + 1.704 + rv = pthread_getschedparam(thred->id, &policy, &schedule); 1.705 + if(0 == rv) { 1.706 + schedule.sched_priority = pt_PriorityMap(newPri); 1.707 + rv = pthread_setschedparam(thred->id, policy, &schedule); 1.708 + if (EPERM == rv) 1.709 + { 1.710 + pt_schedpriv = EPERM; 1.711 + PR_LOG(_pr_thread_lm, PR_LOG_MIN, 1.712 + ("PR_SetThreadPriority: no thread scheduling privilege")); 1.713 + } 1.714 + } 1.715 + if (rv != 0) 1.716 + rv = -1; 1.717 + } 1.718 +#elif defined(_PR_NICE_PRIORITY_SCHEDULING) 1.719 + PR_Lock(pt_book.ml); 1.720 + while (thred->tid == 0) 1.721 + PR_WaitCondVar(pt_book.cv, PR_INTERVAL_NO_TIMEOUT); 1.722 + PR_Unlock(pt_book.ml); 1.723 + 1.724 + errno = 0; 1.725 + rv = getpriority(PRIO_PROCESS, 0); 1.726 + 1.727 + /* Do not proceed unless we know the main thread's nice value. */ 1.728 + if (errno == 0) { 1.729 + rv = setpriority(PRIO_PROCESS, thred->tid, 1.730 + pt_RelativePriority(rv, newPri)); 1.731 + 1.732 + if (rv == -1) 1.733 + { 1.734 + /* We don't set pt_schedpriv to EPERM in case errno == EPERM 1.735 + * because adjusting the nice value might be permitted for certain 1.736 + * ranges but not for others. */ 1.737 + PR_LOG(_pr_thread_lm, PR_LOG_MIN, 1.738 + ("PR_SetThreadPriority: setpriority failed with error %d", 1.739 + errno)); 1.740 + } 1.741 + } 1.742 +#endif 1.743 + 1.744 + thred->priority = newPri; 1.745 +} /* PR_SetThreadPriority */ 1.746 + 1.747 +PR_IMPLEMENT(PRStatus) PR_Interrupt(PRThread *thred) 1.748 +{ 1.749 + /* 1.750 + ** If the target thread indicates that it's waiting, 1.751 + ** find the condition and broadcast to it. Broadcast 1.752 + ** since we don't know which thread (if there are more 1.753 + ** than one). This sounds risky, but clients must 1.754 + ** test their invariants when resumed from a wait and 1.755 + ** I don't expect very many threads to be waiting on 1.756 + ** a single condition and I don't expect interrupt to 1.757 + ** be used very often. 1.758 + ** 1.759 + ** I don't know why I thought this would work. Must have 1.760 + ** been one of those weaker momements after I'd been 1.761 + ** smelling the vapors. 1.762 + ** 1.763 + ** Even with the followng changes it is possible that 1.764 + ** the pointer to the condition variable is pointing 1.765 + ** at a bogus value. Will the unerlying code detect 1.766 + ** that? 1.767 + */ 1.768 + PRCondVar *cv; 1.769 + PR_ASSERT(NULL != thred); 1.770 + if (NULL == thred) return PR_FAILURE; 1.771 + 1.772 + thred->state |= PT_THREAD_ABORTED; 1.773 + 1.774 + cv = thred->waiting; 1.775 + if ((NULL != cv) && !thred->interrupt_blocked) 1.776 + { 1.777 + PRIntn rv; 1.778 + (void)PR_ATOMIC_INCREMENT(&cv->notify_pending); 1.779 + rv = pthread_cond_broadcast(&cv->cv); 1.780 + PR_ASSERT(0 == rv); 1.781 + if (0 > PR_ATOMIC_DECREMENT(&cv->notify_pending)) 1.782 + PR_DestroyCondVar(cv); 1.783 + } 1.784 + return PR_SUCCESS; 1.785 +} /* PR_Interrupt */ 1.786 + 1.787 +PR_IMPLEMENT(void) PR_ClearInterrupt(void) 1.788 +{ 1.789 + PRThread *me = PR_GetCurrentThread(); 1.790 + me->state &= ~PT_THREAD_ABORTED; 1.791 +} /* PR_ClearInterrupt */ 1.792 + 1.793 +PR_IMPLEMENT(void) PR_BlockInterrupt(void) 1.794 +{ 1.795 + PRThread *me = PR_GetCurrentThread(); 1.796 + _PT_THREAD_BLOCK_INTERRUPT(me); 1.797 +} /* PR_BlockInterrupt */ 1.798 + 1.799 +PR_IMPLEMENT(void) PR_UnblockInterrupt(void) 1.800 +{ 1.801 + PRThread *me = PR_GetCurrentThread(); 1.802 + _PT_THREAD_UNBLOCK_INTERRUPT(me); 1.803 +} /* PR_UnblockInterrupt */ 1.804 + 1.805 +PR_IMPLEMENT(PRStatus) PR_Yield(void) 1.806 +{ 1.807 + static PRBool warning = PR_TRUE; 1.808 + if (warning) warning = _PR_Obsolete( 1.809 + "PR_Yield()", "PR_Sleep(PR_INTERVAL_NO_WAIT)"); 1.810 + return PR_Sleep(PR_INTERVAL_NO_WAIT); 1.811 +} 1.812 + 1.813 +PR_IMPLEMENT(PRStatus) PR_Sleep(PRIntervalTime ticks) 1.814 +{ 1.815 + PRStatus rv = PR_SUCCESS; 1.816 + 1.817 + if (!_pr_initialized) _PR_ImplicitInitialization(); 1.818 + 1.819 + if (PR_INTERVAL_NO_WAIT == ticks) 1.820 + { 1.821 + _PT_PTHREAD_YIELD(); 1.822 + } 1.823 + else 1.824 + { 1.825 + PRCondVar *cv; 1.826 + PRIntervalTime timein; 1.827 + 1.828 + timein = PR_IntervalNow(); 1.829 + cv = PR_NewCondVar(_pr_sleeplock); 1.830 + PR_ASSERT(cv != NULL); 1.831 + PR_Lock(_pr_sleeplock); 1.832 + do 1.833 + { 1.834 + PRIntervalTime now = PR_IntervalNow(); 1.835 + PRIntervalTime delta = now - timein; 1.836 + if (delta > ticks) break; 1.837 + rv = PR_WaitCondVar(cv, ticks - delta); 1.838 + } while (PR_SUCCESS == rv); 1.839 + PR_Unlock(_pr_sleeplock); 1.840 + PR_DestroyCondVar(cv); 1.841 + } 1.842 + return rv; 1.843 +} /* PR_Sleep */ 1.844 + 1.845 +static void _pt_thread_death(void *arg) 1.846 +{ 1.847 + void *thred; 1.848 + int rv; 1.849 + 1.850 + _PT_PTHREAD_GETSPECIFIC(pt_book.key, thred); 1.851 + if (NULL == thred) 1.852 + { 1.853 + /* 1.854 + * Have PR_GetCurrentThread return the expected value to the 1.855 + * destructors. 1.856 + */ 1.857 + rv = pthread_setspecific(pt_book.key, arg); 1.858 + PR_ASSERT(0 == rv); 1.859 + } 1.860 + 1.861 + /* PR_TRUE for: call destructors */ 1.862 + _pt_thread_death_internal(arg, PR_TRUE); 1.863 + 1.864 + if (NULL == thred) 1.865 + { 1.866 + rv = pthread_setspecific(pt_book.key, NULL); 1.867 + PR_ASSERT(0 == rv); 1.868 + } 1.869 +} 1.870 + 1.871 +static void _pt_thread_death_internal(void *arg, PRBool callDestructors) 1.872 +{ 1.873 + PRThread *thred = (PRThread*)arg; 1.874 + 1.875 + if (thred->state & (PT_THREAD_FOREIGN|PT_THREAD_PRIMORD)) 1.876 + { 1.877 + PR_Lock(pt_book.ml); 1.878 + if (NULL == thred->prev) 1.879 + pt_book.first = thred->next; 1.880 + else 1.881 + thred->prev->next = thred->next; 1.882 + if (NULL == thred->next) 1.883 + pt_book.last = thred->prev; 1.884 + else 1.885 + thred->next->prev = thred->prev; 1.886 + PR_Unlock(pt_book.ml); 1.887 + } 1.888 + if (callDestructors) 1.889 + _PR_DestroyThreadPrivate(thred); 1.890 + PR_Free(thred->privateData); 1.891 + if (NULL != thred->errorString) 1.892 + PR_Free(thred->errorString); 1.893 + if (NULL != thred->name) 1.894 + PR_Free(thred->name); 1.895 + PR_Free(thred->stack); 1.896 + if (NULL != thred->syspoll_list) 1.897 + PR_Free(thred->syspoll_list); 1.898 +#if defined(_PR_POLL_WITH_SELECT) 1.899 + if (NULL != thred->selectfd_list) 1.900 + PR_Free(thred->selectfd_list); 1.901 +#endif 1.902 +#if defined(DEBUG) 1.903 + memset(thred, 0xaf, sizeof(PRThread)); 1.904 +#endif /* defined(DEBUG) */ 1.905 + PR_Free(thred); 1.906 +} /* _pt_thread_death */ 1.907 + 1.908 +void _PR_InitThreads( 1.909 + PRThreadType type, PRThreadPriority priority, PRUintn maxPTDs) 1.910 +{ 1.911 + int rv; 1.912 + PRThread *thred; 1.913 + 1.914 + PR_ASSERT(priority == PR_PRIORITY_NORMAL); 1.915 + 1.916 +#ifdef _PR_NEED_PTHREAD_INIT 1.917 + /* 1.918 + * On BSD/OS (3.1 and 4.0), the pthread subsystem is lazily 1.919 + * initialized, but pthread_self() fails to initialize 1.920 + * pthreads and hence returns a null thread ID if invoked 1.921 + * by the primordial thread before any other pthread call. 1.922 + * So we explicitly initialize pthreads here. 1.923 + */ 1.924 + pthread_init(); 1.925 +#endif 1.926 + 1.927 +#if defined(_PR_DCETHREADS) || defined(_POSIX_THREAD_PRIORITY_SCHEDULING) 1.928 +#if defined(FREEBSD) 1.929 + { 1.930 + pthread_attr_t attr; 1.931 + int policy; 1.932 + /* get the min and max priorities of the default policy */ 1.933 + pthread_attr_init(&attr); 1.934 + pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); 1.935 + pthread_attr_getschedpolicy(&attr, &policy); 1.936 + pt_book.minPrio = sched_get_priority_min(policy); 1.937 + PR_ASSERT(-1 != pt_book.minPrio); 1.938 + pt_book.maxPrio = sched_get_priority_max(policy); 1.939 + PR_ASSERT(-1 != pt_book.maxPrio); 1.940 + pthread_attr_destroy(&attr); 1.941 + } 1.942 +#else 1.943 + /* 1.944 + ** These might be function evaluations 1.945 + */ 1.946 + pt_book.minPrio = PT_PRIO_MIN; 1.947 + pt_book.maxPrio = PT_PRIO_MAX; 1.948 +#endif 1.949 +#endif 1.950 + 1.951 + PR_ASSERT(NULL == pt_book.ml); 1.952 + pt_book.ml = PR_NewLock(); 1.953 + PR_ASSERT(NULL != pt_book.ml); 1.954 + pt_book.cv = PR_NewCondVar(pt_book.ml); 1.955 + PR_ASSERT(NULL != pt_book.cv); 1.956 + thred = PR_NEWZAP(PRThread); 1.957 + PR_ASSERT(NULL != thred); 1.958 + thred->arg = NULL; 1.959 + thred->startFunc = NULL; 1.960 + thred->priority = priority; 1.961 + thred->id = pthread_self(); 1.962 + thred->idSet = PR_TRUE; 1.963 +#ifdef _PR_NICE_PRIORITY_SCHEDULING 1.964 + thred->tid = gettid(); 1.965 +#endif 1.966 + 1.967 + thred->state = (PT_THREAD_DETACHED | PT_THREAD_PRIMORD); 1.968 + if (PR_SYSTEM_THREAD == type) 1.969 + { 1.970 + thred->state |= PT_THREAD_SYSTEM; 1.971 + pt_book.system += 1; 1.972 + pt_book.this_many = 0; 1.973 + } 1.974 + else 1.975 + { 1.976 + pt_book.user += 1; 1.977 + pt_book.this_many = 1; 1.978 + } 1.979 + thred->next = thred->prev = NULL; 1.980 + pt_book.first = pt_book.last = thred; 1.981 + 1.982 + thred->stack = PR_NEWZAP(PRThreadStack); 1.983 + PR_ASSERT(thred->stack != NULL); 1.984 + thred->stack->stackSize = 0; 1.985 + thred->stack->thr = thred; 1.986 + _PR_InitializeStack(thred->stack); 1.987 + 1.988 + /* 1.989 + * Create a key for our use to store a backpointer in the pthread 1.990 + * to our PRThread object. This object gets deleted when the thread 1.991 + * returns from its root in the case of a detached thread. Other 1.992 + * threads delete the objects in Join. 1.993 + * 1.994 + * NB: The destructor logic seems to have a bug so it isn't used. 1.995 + * NBB: Oh really? I'm going to give it a spin - AOF 19 June 1998. 1.996 + * More info - the problem is that pthreads calls the destructor 1.997 + * eagerly as the thread returns from its root, rather than lazily 1.998 + * after the thread is joined. Therefore, threads that are joining 1.999 + * and holding PRThread references are actually holding pointers to 1.1000 + * nothing. 1.1001 + */ 1.1002 + rv = _PT_PTHREAD_KEY_CREATE(&pt_book.key, _pt_thread_death); 1.1003 + if (0 != rv) 1.1004 + PR_Assert("0 == rv", __FILE__, __LINE__); 1.1005 + pt_book.keyCreated = PR_TRUE; 1.1006 + rv = pthread_setspecific(pt_book.key, thred); 1.1007 + PR_ASSERT(0 == rv); 1.1008 +} /* _PR_InitThreads */ 1.1009 + 1.1010 +#ifdef __GNUC__ 1.1011 +/* 1.1012 + * GCC supports the constructor and destructor attributes as of 1.1013 + * version 2.5. 1.1014 + */ 1.1015 +static void _PR_Fini(void) __attribute__ ((destructor)); 1.1016 +#elif defined(__SUNPRO_C) 1.1017 +/* 1.1018 + * Sun Studio compiler 1.1019 + */ 1.1020 +#pragma fini(_PR_Fini) 1.1021 +static void _PR_Fini(void); 1.1022 +#elif defined(HPUX) 1.1023 +/* 1.1024 + * Current versions of HP C compiler define __HP_cc. 1.1025 + * HP C compiler A.11.01.20 doesn't define __HP_cc. 1.1026 + */ 1.1027 +#if defined(__ia64) || defined(_LP64) 1.1028 +#pragma FINI "_PR_Fini" 1.1029 +static void _PR_Fini(void); 1.1030 +#else 1.1031 +/* 1.1032 + * Only HP-UX 10.x style initializers are supported in 32-bit links. 1.1033 + * Need to use the +I PR_HPUX10xInit linker option. 1.1034 + */ 1.1035 +#include <dl.h> 1.1036 + 1.1037 +static void _PR_Fini(void); 1.1038 + 1.1039 +void PR_HPUX10xInit(shl_t handle, int loading) 1.1040 +{ 1.1041 + /* 1.1042 + * This function is called when a shared library is loaded as well 1.1043 + * as when the shared library is unloaded. Note that it may not 1.1044 + * be called when the user's program terminates. 1.1045 + * 1.1046 + * handle is the shl_load API handle for the shared library being 1.1047 + * initialized. 1.1048 + * 1.1049 + * loading is non-zero at startup and zero at termination. 1.1050 + */ 1.1051 + if (loading) { 1.1052 + /* ... do some initializations ... */ 1.1053 + } else { 1.1054 + _PR_Fini(); 1.1055 + } 1.1056 +} 1.1057 +#endif 1.1058 +#elif defined(AIX) 1.1059 +/* Need to use the -binitfini::_PR_Fini linker option. */ 1.1060 +#endif 1.1061 + 1.1062 +void _PR_Fini(void) 1.1063 +{ 1.1064 + void *thred; 1.1065 + int rv; 1.1066 + 1.1067 + if (!_pr_initialized) { 1.1068 + /* Either NSPR was never successfully initialized or 1.1069 + * PR_Cleanup has been called already. */ 1.1070 + if (pt_book.keyCreated) 1.1071 + { 1.1072 + rv = pthread_key_delete(pt_book.key); 1.1073 + PR_ASSERT(0 == rv); 1.1074 + pt_book.keyCreated = PR_FALSE; 1.1075 + } 1.1076 + return; 1.1077 + } 1.1078 + 1.1079 + _PT_PTHREAD_GETSPECIFIC(pt_book.key, thred); 1.1080 + if (NULL != thred) 1.1081 + { 1.1082 + /* 1.1083 + * PR_FALSE, because it is unsafe to call back to the 1.1084 + * thread private data destructors at final cleanup. 1.1085 + */ 1.1086 + _pt_thread_death_internal(thred, PR_FALSE); 1.1087 + rv = pthread_setspecific(pt_book.key, NULL); 1.1088 + PR_ASSERT(0 == rv); 1.1089 + } 1.1090 + rv = pthread_key_delete(pt_book.key); 1.1091 + PR_ASSERT(0 == rv); 1.1092 + pt_book.keyCreated = PR_FALSE; 1.1093 + /* TODO: free other resources used by NSPR */ 1.1094 + /* _pr_initialized = PR_FALSE; */ 1.1095 +} /* _PR_Fini */ 1.1096 + 1.1097 +PR_IMPLEMENT(PRStatus) PR_Cleanup(void) 1.1098 +{ 1.1099 + PRThread *me = PR_GetCurrentThread(); 1.1100 + int rv; 1.1101 + PR_LOG(_pr_thread_lm, PR_LOG_MIN, ("PR_Cleanup: shutting down NSPR")); 1.1102 + PR_ASSERT(me->state & PT_THREAD_PRIMORD); 1.1103 + if (me->state & PT_THREAD_PRIMORD) 1.1104 + { 1.1105 + PR_Lock(pt_book.ml); 1.1106 + while (pt_book.user > pt_book.this_many) 1.1107 + PR_WaitCondVar(pt_book.cv, PR_INTERVAL_NO_TIMEOUT); 1.1108 + if (me->state & PT_THREAD_SYSTEM) 1.1109 + pt_book.system -= 1; 1.1110 + else 1.1111 + pt_book.user -= 1; 1.1112 + PR_Unlock(pt_book.ml); 1.1113 + 1.1114 + _PR_MD_EARLY_CLEANUP(); 1.1115 + 1.1116 + _PR_CleanupMW(); 1.1117 + _PR_CleanupTime(); 1.1118 + _PR_CleanupDtoa(); 1.1119 + _PR_CleanupCallOnce(); 1.1120 + _PR_ShutdownLinker(); 1.1121 + _PR_LogCleanup(); 1.1122 + _PR_CleanupNet(); 1.1123 + /* Close all the fd's before calling _PR_CleanupIO */ 1.1124 + _PR_CleanupIO(); 1.1125 + _PR_CleanupCMon(); 1.1126 + 1.1127 + _pt_thread_death(me); 1.1128 + rv = pthread_setspecific(pt_book.key, NULL); 1.1129 + PR_ASSERT(0 == rv); 1.1130 + /* 1.1131 + * I am not sure if it's safe to delete the cv and lock here, 1.1132 + * since there may still be "system" threads around. If this 1.1133 + * call isn't immediately prior to exiting, then there's a 1.1134 + * problem. 1.1135 + */ 1.1136 + if (0 == pt_book.system) 1.1137 + { 1.1138 + PR_DestroyCondVar(pt_book.cv); pt_book.cv = NULL; 1.1139 + PR_DestroyLock(pt_book.ml); pt_book.ml = NULL; 1.1140 + } 1.1141 + PR_DestroyLock(_pr_sleeplock); 1.1142 + _pr_sleeplock = NULL; 1.1143 + _PR_CleanupLayerCache(); 1.1144 + _PR_CleanupEnv(); 1.1145 +#ifdef _PR_ZONE_ALLOCATOR 1.1146 + _PR_DestroyZones(); 1.1147 +#endif 1.1148 + _pr_initialized = PR_FALSE; 1.1149 + return PR_SUCCESS; 1.1150 + } 1.1151 + return PR_FAILURE; 1.1152 +} /* PR_Cleanup */ 1.1153 + 1.1154 +PR_IMPLEMENT(void) PR_ProcessExit(PRIntn status) 1.1155 +{ 1.1156 + _exit(status); 1.1157 +} 1.1158 + 1.1159 +PR_IMPLEMENT(PRUint32) PR_GetThreadID(PRThread *thred) 1.1160 +{ 1.1161 +#if defined(_PR_DCETHREADS) 1.1162 + return (PRUint32)&thred->id; /* this is really a sham! */ 1.1163 +#else 1.1164 + return (PRUint32)thred->id; /* and I don't know what they will do with it */ 1.1165 +#endif 1.1166 +} 1.1167 + 1.1168 +/* 1.1169 + * $$$ 1.1170 + * The following two thread-to-processor affinity functions are not 1.1171 + * yet implemented for pthreads. By the way, these functions should return 1.1172 + * PRStatus rather than PRInt32 to indicate the success/failure status. 1.1173 + * $$$ 1.1174 + */ 1.1175 + 1.1176 +PR_IMPLEMENT(PRInt32) PR_GetThreadAffinityMask(PRThread *thread, PRUint32 *mask) 1.1177 +{ 1.1178 + return 0; /* not implemented */ 1.1179 +} 1.1180 + 1.1181 +PR_IMPLEMENT(PRInt32) PR_SetThreadAffinityMask(PRThread *thread, PRUint32 mask ) 1.1182 +{ 1.1183 + return 0; /* not implemented */ 1.1184 +} 1.1185 + 1.1186 +PR_IMPLEMENT(void) 1.1187 +PR_SetThreadDumpProc(PRThread* thread, PRThreadDumpProc dump, void *arg) 1.1188 +{ 1.1189 + thread->dump = dump; 1.1190 + thread->dumpArg = arg; 1.1191 +} 1.1192 + 1.1193 +/* 1.1194 + * Garbage collection support follows. 1.1195 + */ 1.1196 + 1.1197 +#if defined(_PR_DCETHREADS) 1.1198 + 1.1199 +/* 1.1200 + * statics for Garbage Collection support. We don't need to protect these 1.1201 + * signal masks since the garbage collector itself is protected by a lock 1.1202 + * and multiple threads will not be garbage collecting at the same time. 1.1203 + */ 1.1204 +static sigset_t javagc_vtalarm_sigmask; 1.1205 +static sigset_t javagc_intsoff_sigmask; 1.1206 + 1.1207 +#else /* defined(_PR_DCETHREADS) */ 1.1208 + 1.1209 +/* a bogus signal mask for forcing a timed wait */ 1.1210 +/* Not so bogus in AIX as we really do a sigwait */ 1.1211 +static sigset_t sigwait_set; 1.1212 + 1.1213 +static struct timespec onemillisec = {0, 1000000L}; 1.1214 +#ifndef PT_NO_SIGTIMEDWAIT 1.1215 +static struct timespec hundredmillisec = {0, 100000000L}; 1.1216 +#endif 1.1217 + 1.1218 +static void suspend_signal_handler(PRIntn sig); 1.1219 + 1.1220 +#ifdef PT_NO_SIGTIMEDWAIT 1.1221 +static void null_signal_handler(PRIntn sig); 1.1222 +#endif 1.1223 + 1.1224 +#endif /* defined(_PR_DCETHREADS) */ 1.1225 + 1.1226 +/* 1.1227 + * Linux pthreads use SIGUSR1 and SIGUSR2 internally, which 1.1228 + * conflict with the use of these two signals in our GC support. 1.1229 + * So we don't know how to support GC on Linux pthreads. 1.1230 + */ 1.1231 +static void init_pthread_gc_support(void) 1.1232 +{ 1.1233 +#ifndef SYMBIAN 1.1234 + PRIntn rv; 1.1235 + 1.1236 +#if defined(_PR_DCETHREADS) 1.1237 + rv = sigemptyset(&javagc_vtalarm_sigmask); 1.1238 + PR_ASSERT(0 == rv); 1.1239 + rv = sigaddset(&javagc_vtalarm_sigmask, SIGVTALRM); 1.1240 + PR_ASSERT(0 == rv); 1.1241 +#else /* defined(_PR_DCETHREADS) */ 1.1242 + { 1.1243 + struct sigaction sigact_usr2; 1.1244 + 1.1245 + sigact_usr2.sa_handler = suspend_signal_handler; 1.1246 + sigact_usr2.sa_flags = SA_RESTART; 1.1247 + sigemptyset (&sigact_usr2.sa_mask); 1.1248 + 1.1249 + rv = sigaction (SIGUSR2, &sigact_usr2, NULL); 1.1250 + PR_ASSERT(0 == rv); 1.1251 + 1.1252 + sigemptyset (&sigwait_set); 1.1253 +#if defined(PT_NO_SIGTIMEDWAIT) 1.1254 + sigaddset (&sigwait_set, SIGUSR1); 1.1255 +#else 1.1256 + sigaddset (&sigwait_set, SIGUSR2); 1.1257 +#endif /* defined(PT_NO_SIGTIMEDWAIT) */ 1.1258 + } 1.1259 +#if defined(PT_NO_SIGTIMEDWAIT) 1.1260 + { 1.1261 + struct sigaction sigact_null; 1.1262 + sigact_null.sa_handler = null_signal_handler; 1.1263 + sigact_null.sa_flags = SA_RESTART; 1.1264 + sigemptyset (&sigact_null.sa_mask); 1.1265 + rv = sigaction (SIGUSR1, &sigact_null, NULL); 1.1266 + PR_ASSERT(0 ==rv); 1.1267 + } 1.1268 +#endif /* defined(PT_NO_SIGTIMEDWAIT) */ 1.1269 +#endif /* defined(_PR_DCETHREADS) */ 1.1270 +#endif /* SYMBIAN */ 1.1271 +} 1.1272 + 1.1273 +PR_IMPLEMENT(void) PR_SetThreadGCAble(void) 1.1274 +{ 1.1275 + PR_Lock(pt_book.ml); 1.1276 + PR_GetCurrentThread()->state |= PT_THREAD_GCABLE; 1.1277 + PR_Unlock(pt_book.ml); 1.1278 +} 1.1279 + 1.1280 +PR_IMPLEMENT(void) PR_ClearThreadGCAble(void) 1.1281 +{ 1.1282 + PR_Lock(pt_book.ml); 1.1283 + PR_GetCurrentThread()->state &= (~PT_THREAD_GCABLE); 1.1284 + PR_Unlock(pt_book.ml); 1.1285 +} 1.1286 + 1.1287 +#if defined(DEBUG) 1.1288 +static PRBool suspendAllOn = PR_FALSE; 1.1289 +#endif 1.1290 + 1.1291 +static PRBool suspendAllSuspended = PR_FALSE; 1.1292 + 1.1293 +PR_IMPLEMENT(PRStatus) PR_EnumerateThreads(PREnumerator func, void *arg) 1.1294 +{ 1.1295 + PRIntn count = 0; 1.1296 + PRStatus rv = PR_SUCCESS; 1.1297 + PRThread* thred = pt_book.first; 1.1298 + 1.1299 +#if defined(DEBUG) || defined(FORCE_PR_ASSERT) 1.1300 +#if !defined(_PR_DCETHREADS) 1.1301 + PRThread *me = PR_GetCurrentThread(); 1.1302 +#endif 1.1303 +#endif 1.1304 + 1.1305 + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_EnumerateThreads\n")); 1.1306 + /* 1.1307 + * $$$ 1.1308 + * Need to suspend all threads other than me before doing this. 1.1309 + * This is really a gross and disgusting thing to do. The only 1.1310 + * good thing is that since all other threads are suspended, holding 1.1311 + * the lock during a callback seems like child's play. 1.1312 + * $$$ 1.1313 + */ 1.1314 + PR_ASSERT(suspendAllOn); 1.1315 + 1.1316 + while (thred != NULL) 1.1317 + { 1.1318 + /* Steve Morse, 4-23-97: Note that we can't walk a queue by taking 1.1319 + * qp->next after applying the function "func". In particular, "func" 1.1320 + * might remove the thread from the queue and put it into another one in 1.1321 + * which case qp->next no longer points to the next entry in the original 1.1322 + * queue. 1.1323 + * 1.1324 + * To get around this problem, we save qp->next in qp_next before applying 1.1325 + * "func" and use that saved value as the next value after applying "func". 1.1326 + */ 1.1327 + PRThread* next = thred->next; 1.1328 + 1.1329 + if (_PT_IS_GCABLE_THREAD(thred)) 1.1330 + { 1.1331 +#if !defined(_PR_DCETHREADS) 1.1332 + PR_ASSERT((thred == me) || (thred->suspend & PT_THREAD_SUSPENDED)); 1.1333 +#endif 1.1334 + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 1.1335 + ("In PR_EnumerateThreads callback thread %p thid = %X\n", 1.1336 + thred, thred->id)); 1.1337 + 1.1338 + rv = func(thred, count++, arg); 1.1339 + if (rv != PR_SUCCESS) 1.1340 + return rv; 1.1341 + } 1.1342 + thred = next; 1.1343 + } 1.1344 + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 1.1345 + ("End PR_EnumerateThreads count = %d \n", count)); 1.1346 + return rv; 1.1347 +} /* PR_EnumerateThreads */ 1.1348 + 1.1349 +/* 1.1350 + * PR_SuspendAll and PR_ResumeAll are called during garbage collection. The strategy 1.1351 + * we use is to send a SIGUSR2 signal to every gc able thread that we intend to suspend. 1.1352 + * The signal handler will record the stack pointer and will block until resumed by 1.1353 + * the resume call. Since the signal handler is the last routine called for the 1.1354 + * suspended thread, the stack pointer will also serve as a place where all the 1.1355 + * registers have been saved on the stack for the previously executing routines. 1.1356 + * 1.1357 + * Through global variables, we also make sure that PR_Suspend and PR_Resume does not 1.1358 + * proceed until the thread is suspended or resumed. 1.1359 + */ 1.1360 + 1.1361 +#if !defined(_PR_DCETHREADS) 1.1362 + 1.1363 +/* 1.1364 + * In the signal handler, we can not use condition variable notify or wait. 1.1365 + * This does not work consistently across all pthread platforms. We also can not 1.1366 + * use locking since that does not seem to work reliably across platforms. 1.1367 + * Only thing we can do is yielding while testing for a global condition 1.1368 + * to change. This does work on pthread supported platforms. We may have 1.1369 + * to play with priortities if there are any problems detected. 1.1370 + */ 1.1371 + 1.1372 + /* 1.1373 + * In AIX, you cannot use ANY pthread calls in the signal handler except perhaps 1.1374 + * pthread_yield. But that is horribly inefficient. Hence we use only sigwait, no 1.1375 + * sigtimedwait is available. We need to use another user signal, SIGUSR1. Actually 1.1376 + * SIGUSR1 is also used by exec in Java. So our usage here breaks the exec in Java, 1.1377 + * for AIX. You cannot use pthread_cond_wait or pthread_delay_np in the signal 1.1378 + * handler as all synchronization mechanisms just break down. 1.1379 + */ 1.1380 + 1.1381 +#if defined(PT_NO_SIGTIMEDWAIT) 1.1382 +static void null_signal_handler(PRIntn sig) 1.1383 +{ 1.1384 + return; 1.1385 +} 1.1386 +#endif 1.1387 + 1.1388 +static void suspend_signal_handler(PRIntn sig) 1.1389 +{ 1.1390 + PRThread *me = PR_GetCurrentThread(); 1.1391 + 1.1392 + PR_ASSERT(me != NULL); 1.1393 + PR_ASSERT(_PT_IS_GCABLE_THREAD(me)); 1.1394 + PR_ASSERT((me->suspend & PT_THREAD_SUSPENDED) == 0); 1.1395 + 1.1396 + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 1.1397 + ("Begin suspend_signal_handler thred %p thread id = %X\n", 1.1398 + me, me->id)); 1.1399 + 1.1400 + /* 1.1401 + * save stack pointer 1.1402 + */ 1.1403 + me->sp = &me; 1.1404 + 1.1405 + /* 1.1406 + At this point, the thread's stack pointer has been saved, 1.1407 + And it is going to enter a wait loop until it is resumed. 1.1408 + So it is _really_ suspended 1.1409 + */ 1.1410 + 1.1411 + me->suspend |= PT_THREAD_SUSPENDED; 1.1412 + 1.1413 + /* 1.1414 + * now, block current thread 1.1415 + */ 1.1416 +#if defined(PT_NO_SIGTIMEDWAIT) 1.1417 + pthread_cond_signal(&me->suspendResumeCV); 1.1418 + while (me->suspend & PT_THREAD_SUSPENDED) 1.1419 + { 1.1420 +#if !defined(FREEBSD) && !defined(NETBSD) && !defined(OPENBSD) \ 1.1421 + && !defined(BSDI) && !defined(UNIXWARE) \ 1.1422 + && !defined(DARWIN) && !defined(RISCOS) \ 1.1423 + && !defined(SYMBIAN) /*XXX*/ 1.1424 + PRIntn rv; 1.1425 + sigwait(&sigwait_set, &rv); 1.1426 +#endif 1.1427 + } 1.1428 + me->suspend |= PT_THREAD_RESUMED; 1.1429 + pthread_cond_signal(&me->suspendResumeCV); 1.1430 +#else /* defined(PT_NO_SIGTIMEDWAIT) */ 1.1431 + while (me->suspend & PT_THREAD_SUSPENDED) 1.1432 + { 1.1433 + PRIntn rv = sigtimedwait(&sigwait_set, NULL, &hundredmillisec); 1.1434 + PR_ASSERT(-1 == rv); 1.1435 + } 1.1436 + me->suspend |= PT_THREAD_RESUMED; 1.1437 +#endif 1.1438 + 1.1439 + /* 1.1440 + * At this point, thread has been resumed, so set a global condition. 1.1441 + * The ResumeAll needs to know that this has really been resumed. 1.1442 + * So the signal handler sets a flag which PR_ResumeAll will reset. 1.1443 + * The PR_ResumeAll must reset this flag ... 1.1444 + */ 1.1445 + 1.1446 + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 1.1447 + ("End suspend_signal_handler thred = %p tid = %X\n", me, me->id)); 1.1448 +} /* suspend_signal_handler */ 1.1449 + 1.1450 +static void pt_SuspendSet(PRThread *thred) 1.1451 +{ 1.1452 + PRIntn rv; 1.1453 + 1.1454 + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 1.1455 + ("pt_SuspendSet thred %p thread id = %X\n", thred, thred->id)); 1.1456 + 1.1457 + 1.1458 + /* 1.1459 + * Check the thread state and signal the thread to suspend 1.1460 + */ 1.1461 + 1.1462 + PR_ASSERT((thred->suspend & PT_THREAD_SUSPENDED) == 0); 1.1463 + 1.1464 + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 1.1465 + ("doing pthread_kill in pt_SuspendSet thred %p tid = %X\n", 1.1466 + thred, thred->id)); 1.1467 +#if defined(SYMBIAN) 1.1468 + /* All signal group functions are not implemented in Symbian OS */ 1.1469 + rv = 0; 1.1470 +#else 1.1471 + rv = pthread_kill (thred->id, SIGUSR2); 1.1472 +#endif 1.1473 + PR_ASSERT(0 == rv); 1.1474 +} 1.1475 + 1.1476 +static void pt_SuspendTest(PRThread *thred) 1.1477 +{ 1.1478 + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 1.1479 + ("Begin pt_SuspendTest thred %p thread id = %X\n", thred, thred->id)); 1.1480 + 1.1481 + 1.1482 + /* 1.1483 + * Wait for the thread to be really suspended. This happens when the 1.1484 + * suspend signal handler stores the stack pointer and sets the state 1.1485 + * to suspended. 1.1486 + */ 1.1487 + 1.1488 +#if defined(PT_NO_SIGTIMEDWAIT) 1.1489 + pthread_mutex_lock(&thred->suspendResumeMutex); 1.1490 + while ((thred->suspend & PT_THREAD_SUSPENDED) == 0) 1.1491 + { 1.1492 + pthread_cond_timedwait( 1.1493 + &thred->suspendResumeCV, &thred->suspendResumeMutex, &onemillisec); 1.1494 + } 1.1495 + pthread_mutex_unlock(&thred->suspendResumeMutex); 1.1496 +#else 1.1497 + while ((thred->suspend & PT_THREAD_SUSPENDED) == 0) 1.1498 + { 1.1499 + PRIntn rv = sigtimedwait(&sigwait_set, NULL, &onemillisec); 1.1500 + PR_ASSERT(-1 == rv); 1.1501 + } 1.1502 +#endif 1.1503 + 1.1504 + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 1.1505 + ("End pt_SuspendTest thred %p tid %X\n", thred, thred->id)); 1.1506 +} /* pt_SuspendTest */ 1.1507 + 1.1508 +static void pt_ResumeSet(PRThread *thred) 1.1509 +{ 1.1510 + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 1.1511 + ("pt_ResumeSet thred %p thread id = %X\n", thred, thred->id)); 1.1512 + 1.1513 + /* 1.1514 + * Clear the global state and set the thread state so that it will 1.1515 + * continue past yield loop in the suspend signal handler 1.1516 + */ 1.1517 + 1.1518 + PR_ASSERT(thred->suspend & PT_THREAD_SUSPENDED); 1.1519 + 1.1520 + 1.1521 + thred->suspend &= ~PT_THREAD_SUSPENDED; 1.1522 + 1.1523 +#if defined(PT_NO_SIGTIMEDWAIT) 1.1524 +#if defined(SYMBIAN) 1.1525 + /* All signal group functions are not implemented in Symbian OS */ 1.1526 +#else 1.1527 + pthread_kill(thred->id, SIGUSR1); 1.1528 +#endif 1.1529 +#endif 1.1530 + 1.1531 +} /* pt_ResumeSet */ 1.1532 + 1.1533 +static void pt_ResumeTest(PRThread *thred) 1.1534 +{ 1.1535 + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 1.1536 + ("Begin pt_ResumeTest thred %p thread id = %X\n", thred, thred->id)); 1.1537 + 1.1538 + /* 1.1539 + * Wait for the threads resume state to change 1.1540 + * to indicate it is really resumed 1.1541 + */ 1.1542 +#if defined(PT_NO_SIGTIMEDWAIT) 1.1543 + pthread_mutex_lock(&thred->suspendResumeMutex); 1.1544 + while ((thred->suspend & PT_THREAD_RESUMED) == 0) 1.1545 + { 1.1546 + pthread_cond_timedwait( 1.1547 + &thred->suspendResumeCV, &thred->suspendResumeMutex, &onemillisec); 1.1548 + } 1.1549 + pthread_mutex_unlock(&thred->suspendResumeMutex); 1.1550 +#else 1.1551 + while ((thred->suspend & PT_THREAD_RESUMED) == 0) { 1.1552 + PRIntn rv = sigtimedwait(&sigwait_set, NULL, &onemillisec); 1.1553 + PR_ASSERT(-1 == rv); 1.1554 + } 1.1555 +#endif 1.1556 + 1.1557 + thred->suspend &= ~PT_THREAD_RESUMED; 1.1558 + 1.1559 + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ( 1.1560 + "End pt_ResumeTest thred %p tid %X\n", thred, thred->id)); 1.1561 +} /* pt_ResumeTest */ 1.1562 + 1.1563 +static pthread_once_t pt_gc_support_control = PTHREAD_ONCE_INIT; 1.1564 + 1.1565 +PR_IMPLEMENT(void) PR_SuspendAll(void) 1.1566 +{ 1.1567 +#ifdef DEBUG 1.1568 + PRIntervalTime stime, etime; 1.1569 +#endif 1.1570 + PRThread* thred = pt_book.first; 1.1571 + PRThread *me = PR_GetCurrentThread(); 1.1572 + int rv; 1.1573 + 1.1574 + rv = pthread_once(&pt_gc_support_control, init_pthread_gc_support); 1.1575 + PR_ASSERT(0 == rv); 1.1576 + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_SuspendAll\n")); 1.1577 + /* 1.1578 + * Stop all threads which are marked GC able. 1.1579 + */ 1.1580 + PR_Lock(pt_book.ml); 1.1581 +#ifdef DEBUG 1.1582 + suspendAllOn = PR_TRUE; 1.1583 + stime = PR_IntervalNow(); 1.1584 +#endif 1.1585 + while (thred != NULL) 1.1586 + { 1.1587 + if ((thred != me) && _PT_IS_GCABLE_THREAD(thred)) 1.1588 + pt_SuspendSet(thred); 1.1589 + thred = thred->next; 1.1590 + } 1.1591 + 1.1592 + /* Wait till they are really suspended */ 1.1593 + thred = pt_book.first; 1.1594 + while (thred != NULL) 1.1595 + { 1.1596 + if ((thred != me) && _PT_IS_GCABLE_THREAD(thred)) 1.1597 + pt_SuspendTest(thred); 1.1598 + thred = thred->next; 1.1599 + } 1.1600 + 1.1601 + suspendAllSuspended = PR_TRUE; 1.1602 + 1.1603 +#ifdef DEBUG 1.1604 + etime = PR_IntervalNow(); 1.1605 + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,\ 1.1606 + ("End PR_SuspendAll (time %dms)\n", 1.1607 + PR_IntervalToMilliseconds(etime - stime))); 1.1608 +#endif 1.1609 +} /* PR_SuspendAll */ 1.1610 + 1.1611 +PR_IMPLEMENT(void) PR_ResumeAll(void) 1.1612 +{ 1.1613 +#ifdef DEBUG 1.1614 + PRIntervalTime stime, etime; 1.1615 +#endif 1.1616 + PRThread* thred = pt_book.first; 1.1617 + PRThread *me = PR_GetCurrentThread(); 1.1618 + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_ResumeAll\n")); 1.1619 + /* 1.1620 + * Resume all previously suspended GC able threads. 1.1621 + */ 1.1622 + suspendAllSuspended = PR_FALSE; 1.1623 +#ifdef DEBUG 1.1624 + stime = PR_IntervalNow(); 1.1625 +#endif 1.1626 + 1.1627 + while (thred != NULL) 1.1628 + { 1.1629 + if ((thred != me) && _PT_IS_GCABLE_THREAD(thred)) 1.1630 + pt_ResumeSet(thred); 1.1631 + thred = thred->next; 1.1632 + } 1.1633 + 1.1634 + thred = pt_book.first; 1.1635 + while (thred != NULL) 1.1636 + { 1.1637 + if ((thred != me) && _PT_IS_GCABLE_THREAD(thred)) 1.1638 + pt_ResumeTest(thred); 1.1639 + thred = thred->next; 1.1640 + } 1.1641 + 1.1642 + PR_Unlock(pt_book.ml); 1.1643 +#ifdef DEBUG 1.1644 + suspendAllOn = PR_FALSE; 1.1645 + etime = PR_IntervalNow(); 1.1646 + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 1.1647 + ("End PR_ResumeAll (time %dms)\n", 1.1648 + PR_IntervalToMilliseconds(etime - stime))); 1.1649 +#endif 1.1650 +} /* PR_ResumeAll */ 1.1651 + 1.1652 +/* Return the stack pointer for the given thread- used by the GC */ 1.1653 +PR_IMPLEMENT(void *)PR_GetSP(PRThread *thred) 1.1654 +{ 1.1655 + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 1.1656 + ("in PR_GetSP thred %p thid = %X, sp = %p\n", 1.1657 + thred, thred->id, thred->sp)); 1.1658 + return thred->sp; 1.1659 +} /* PR_GetSP */ 1.1660 + 1.1661 +#else /* !defined(_PR_DCETHREADS) */ 1.1662 + 1.1663 +static pthread_once_t pt_gc_support_control = pthread_once_init; 1.1664 + 1.1665 +/* 1.1666 + * For DCE threads, there is no pthread_kill or a way of suspending or resuming a 1.1667 + * particular thread. We will just disable the preemption (virtual timer alarm) and 1.1668 + * let the executing thread finish the garbage collection. This stops all other threads 1.1669 + * (GC able or not) and is very inefficient but there is no other choice. 1.1670 + */ 1.1671 +PR_IMPLEMENT(void) PR_SuspendAll() 1.1672 +{ 1.1673 + PRIntn rv; 1.1674 + 1.1675 + rv = pthread_once(&pt_gc_support_control, init_pthread_gc_support); 1.1676 + PR_ASSERT(0 == rv); /* returns -1 on failure */ 1.1677 +#ifdef DEBUG 1.1678 + suspendAllOn = PR_TRUE; 1.1679 +#endif 1.1680 + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_SuspendAll\n")); 1.1681 + /* 1.1682 + * turn off preemption - i.e add virtual alarm signal to the set of 1.1683 + * blocking signals 1.1684 + */ 1.1685 + rv = sigprocmask( 1.1686 + SIG_BLOCK, &javagc_vtalarm_sigmask, &javagc_intsoff_sigmask); 1.1687 + PR_ASSERT(0 == rv); 1.1688 + suspendAllSuspended = PR_TRUE; 1.1689 + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("End PR_SuspendAll\n")); 1.1690 +} /* PR_SuspendAll */ 1.1691 + 1.1692 +PR_IMPLEMENT(void) PR_ResumeAll() 1.1693 +{ 1.1694 + PRIntn rv; 1.1695 + 1.1696 + suspendAllSuspended = PR_FALSE; 1.1697 + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_ResumeAll\n")); 1.1698 + /* turn on preemption - i.e re-enable virtual alarm signal */ 1.1699 + 1.1700 + rv = sigprocmask(SIG_SETMASK, &javagc_intsoff_sigmask, (sigset_t *)NULL); 1.1701 + PR_ASSERT(0 == rv); 1.1702 +#ifdef DEBUG 1.1703 + suspendAllOn = PR_FALSE; 1.1704 +#endif 1.1705 + 1.1706 + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("End PR_ResumeAll\n")); 1.1707 +} /* PR_ResumeAll */ 1.1708 + 1.1709 +/* Return the stack pointer for the given thread- used by the GC */ 1.1710 +PR_IMPLEMENT(void*)PR_GetSP(PRThread *thred) 1.1711 +{ 1.1712 + pthread_t tid = thred->id; 1.1713 + char *thread_tcb, *top_sp; 1.1714 + 1.1715 + /* 1.1716 + * For HPUX DCE threads, pthread_t is a struct with the 1.1717 + * following three fields (see pthread.h, dce/cma.h): 1.1718 + * cma_t_address field1; 1.1719 + * short int field2; 1.1720 + * short int field3; 1.1721 + * where cma_t_address is typedef'd to be either void* 1.1722 + * or char*. 1.1723 + */ 1.1724 + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_GetSP\n")); 1.1725 + thread_tcb = (char*)tid.field1; 1.1726 + top_sp = *(char**)(thread_tcb + 128); 1.1727 + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("End PR_GetSP %p \n", top_sp)); 1.1728 + return top_sp; 1.1729 +} /* PR_GetSP */ 1.1730 + 1.1731 +#endif /* !defined(_PR_DCETHREADS) */ 1.1732 + 1.1733 +PR_IMPLEMENT(PRStatus) PR_SetCurrentThreadName(const char *name) 1.1734 +{ 1.1735 + PRThread *thread; 1.1736 + size_t nameLen; 1.1737 + int result; 1.1738 + 1.1739 + if (!name) { 1.1740 + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); 1.1741 + return PR_FAILURE; 1.1742 + } 1.1743 + 1.1744 + thread = PR_GetCurrentThread(); 1.1745 + if (!thread) 1.1746 + return PR_FAILURE; 1.1747 + 1.1748 + PR_Free(thread->name); 1.1749 + nameLen = strlen(name); 1.1750 + thread->name = (char *)PR_Malloc(nameLen + 1); 1.1751 + if (!thread->name) 1.1752 + return PR_FAILURE; 1.1753 + memcpy(thread->name, name, nameLen + 1); 1.1754 + 1.1755 +#if defined(OPENBSD) || defined(FREEBSD) 1.1756 + result = pthread_set_name_np(thread->id, name); 1.1757 +#else /* not BSD */ 1.1758 + /* 1.1759 + * On OSX, pthread_setname_np is only available in 10.6 or later, so test 1.1760 + * for it at runtime. It also may not be available on all linux distros. 1.1761 + */ 1.1762 +#if defined(DARWIN) 1.1763 + int (*dynamic_pthread_setname_np)(const char*); 1.1764 +#else 1.1765 + int (*dynamic_pthread_setname_np)(pthread_t, const char*); 1.1766 +#endif 1.1767 + 1.1768 + *(void**)(&dynamic_pthread_setname_np) = 1.1769 + dlsym(RTLD_DEFAULT, "pthread_setname_np"); 1.1770 + if (!dynamic_pthread_setname_np) 1.1771 + return PR_SUCCESS; 1.1772 + 1.1773 + /* 1.1774 + * The 15-character name length limit is an experimentally determined 1.1775 + * length of a null-terminated string that most linux distros and OS X 1.1776 + * accept as an argument to pthread_setname_np. Otherwise the E2BIG 1.1777 + * error is returned by the function. 1.1778 + */ 1.1779 +#define SETNAME_LENGTH_CONSTRAINT 15 1.1780 +#define SETNAME_FRAGMENT1_LENGTH (SETNAME_LENGTH_CONSTRAINT >> 1) 1.1781 +#define SETNAME_FRAGMENT2_LENGTH \ 1.1782 + (SETNAME_LENGTH_CONSTRAINT - SETNAME_FRAGMENT1_LENGTH - 1) 1.1783 + char name_dup[SETNAME_LENGTH_CONSTRAINT + 1]; 1.1784 + if (nameLen > SETNAME_LENGTH_CONSTRAINT) { 1.1785 + memcpy(name_dup, name, SETNAME_FRAGMENT1_LENGTH); 1.1786 + name_dup[SETNAME_FRAGMENT1_LENGTH] = '~'; 1.1787 + /* Note that this also copies the null terminator. */ 1.1788 + memcpy(name_dup + SETNAME_FRAGMENT1_LENGTH + 1, 1.1789 + name + nameLen - SETNAME_FRAGMENT2_LENGTH, 1.1790 + SETNAME_FRAGMENT2_LENGTH + 1); 1.1791 + name = name_dup; 1.1792 + } 1.1793 + 1.1794 +#if defined(DARWIN) 1.1795 + result = dynamic_pthread_setname_np(name); 1.1796 +#else 1.1797 + result = dynamic_pthread_setname_np(thread->id, name); 1.1798 +#endif 1.1799 +#endif /* not BSD */ 1.1800 + 1.1801 + if (result) { 1.1802 + PR_SetError(PR_UNKNOWN_ERROR, result); 1.1803 + return PR_FAILURE; 1.1804 + } 1.1805 + return PR_SUCCESS; 1.1806 +} 1.1807 + 1.1808 +PR_IMPLEMENT(const char *) PR_GetThreadName(const PRThread *thread) 1.1809 +{ 1.1810 + if (!thread) 1.1811 + return NULL; 1.1812 + return thread->name; 1.1813 +} 1.1814 + 1.1815 +#endif /* defined(_PR_PTHREADS) || defined(_PR_DCETHREADS) */ 1.1816 + 1.1817 +/* ptthread.c */