1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/nsprpub/pr/src/bthreads/btthread.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,662 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 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 +#include <kernel/OS.h> 1.10 +#include <support/TLS.h> 1.11 + 1.12 +#include "prlog.h" 1.13 +#include "primpl.h" 1.14 +#include "prcvar.h" 1.15 +#include "prpdce.h" 1.16 + 1.17 +#include <stdlib.h> 1.18 +#include <string.h> 1.19 +#include <signal.h> 1.20 + 1.21 +/* values for PRThread.state */ 1.22 +#define BT_THREAD_PRIMORD 0x01 /* this is the primordial thread */ 1.23 +#define BT_THREAD_SYSTEM 0x02 /* this is a system thread */ 1.24 +#define BT_THREAD_JOINABLE 0x04 /* this is a joinable thread */ 1.25 + 1.26 +struct _BT_Bookeeping 1.27 +{ 1.28 + PRLock *ml; /* a lock to protect ourselves */ 1.29 + sem_id cleanUpSem; /* the primoridal thread will block on this 1.30 + sem while waiting for the user threads */ 1.31 + PRInt32 threadCount; /* user thred count */ 1.32 + 1.33 +} bt_book = { NULL, B_ERROR, 0 }; 1.34 + 1.35 + 1.36 +#define BT_TPD_LIMIT 128 /* number of TPD slots we'll provide (arbitrary) */ 1.37 + 1.38 +/* these will be used to map an index returned by PR_NewThreadPrivateIndex() 1.39 + to the corresponding beos native TLS slot number, and to the destructor 1.40 + for that slot - note that, because it is allocated globally, this data 1.41 + will be automatically zeroed for us when the program begins */ 1.42 +static int32 tpd_beosTLSSlots[BT_TPD_LIMIT]; 1.43 +static PRThreadPrivateDTOR tpd_dtors[BT_TPD_LIMIT]; 1.44 + 1.45 +static vint32 tpd_slotsUsed=0; /* number of currently-allocated TPD slots */ 1.46 +static int32 tls_prThreadSlot; /* TLS slot in which PRThread will be stored */ 1.47 + 1.48 +/* this mutex will be used to synchronize access to every 1.49 + PRThread.md.joinSem and PRThread.md.is_joining (we could 1.50 + actually allocate one per thread, but that seems a bit excessive, 1.51 + especially considering that there will probably be little 1.52 + contention, PR_JoinThread() is allowed to block anyway, and the code 1.53 + protected by the mutex is short/fast) */ 1.54 +static PRLock *joinSemLock; 1.55 + 1.56 +static PRUint32 _bt_MapNSPRToNativePriority( PRThreadPriority priority ); 1.57 +static PRThreadPriority _bt_MapNativeToNSPRPriority( PRUint32 priority ); 1.58 +static void _bt_CleanupThread(void *arg); 1.59 +static PRThread *_bt_AttachThread(); 1.60 + 1.61 +void 1.62 +_PR_InitThreads (PRThreadType type, PRThreadPriority priority, 1.63 + PRUintn maxPTDs) 1.64 +{ 1.65 + PRThread *primordialThread; 1.66 + PRUint32 beThreadPriority; 1.67 + 1.68 + /* allocate joinSem mutex */ 1.69 + joinSemLock = PR_NewLock(); 1.70 + if (joinSemLock == NULL) 1.71 + { 1.72 + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); 1.73 + return; 1.74 + } 1.75 + 1.76 + /* 1.77 + ** Create and initialize NSPR structure for our primordial thread. 1.78 + */ 1.79 + 1.80 + primordialThread = PR_NEWZAP(PRThread); 1.81 + if( NULL == primordialThread ) 1.82 + { 1.83 + PR_SetError( PR_OUT_OF_MEMORY_ERROR, 0 ); 1.84 + return; 1.85 + } 1.86 + 1.87 + primordialThread->md.joinSem = B_ERROR; 1.88 + 1.89 + /* 1.90 + ** Set the priority to the desired level. 1.91 + */ 1.92 + 1.93 + beThreadPriority = _bt_MapNSPRToNativePriority( priority ); 1.94 + 1.95 + set_thread_priority( find_thread( NULL ), beThreadPriority ); 1.96 + 1.97 + primordialThread->priority = priority; 1.98 + 1.99 + 1.100 + /* set the thread's state - note that the thread is not joinable */ 1.101 + primordialThread->state |= BT_THREAD_PRIMORD; 1.102 + if (type == PR_SYSTEM_THREAD) 1.103 + primordialThread->state |= BT_THREAD_SYSTEM; 1.104 + 1.105 + /* 1.106 + ** Allocate a TLS slot for the PRThread structure (just using 1.107 + ** native TLS, as opposed to NSPR TPD, will make PR_GetCurrentThread() 1.108 + ** somewhat faster, and will leave one more TPD slot for our client) 1.109 + */ 1.110 + 1.111 + tls_prThreadSlot = tls_allocate(); 1.112 + 1.113 + /* 1.114 + ** Stuff our new PRThread structure into our thread specific 1.115 + ** slot. 1.116 + */ 1.117 + 1.118 + tls_set(tls_prThreadSlot, primordialThread); 1.119 + 1.120 + /* allocate lock for bt_book */ 1.121 + bt_book.ml = PR_NewLock(); 1.122 + if( NULL == bt_book.ml ) 1.123 + { 1.124 + PR_SetError( PR_OUT_OF_MEMORY_ERROR, 0 ); 1.125 + return; 1.126 + } 1.127 +} 1.128 + 1.129 +PRUint32 1.130 +_bt_MapNSPRToNativePriority( PRThreadPriority priority ) 1.131 + { 1.132 + switch( priority ) 1.133 + { 1.134 + case PR_PRIORITY_LOW: return( B_LOW_PRIORITY ); 1.135 + case PR_PRIORITY_NORMAL: return( B_NORMAL_PRIORITY ); 1.136 + case PR_PRIORITY_HIGH: return( B_DISPLAY_PRIORITY ); 1.137 + case PR_PRIORITY_URGENT: return( B_URGENT_DISPLAY_PRIORITY ); 1.138 + default: return( B_NORMAL_PRIORITY ); 1.139 + } 1.140 +} 1.141 + 1.142 +PRThreadPriority 1.143 +_bt_MapNativeToNSPRPriority(PRUint32 priority) 1.144 + { 1.145 + if (priority < B_NORMAL_PRIORITY) 1.146 + return PR_PRIORITY_LOW; 1.147 + if (priority < B_DISPLAY_PRIORITY) 1.148 + return PR_PRIORITY_NORMAL; 1.149 + if (priority < B_URGENT_DISPLAY_PRIORITY) 1.150 + return PR_PRIORITY_HIGH; 1.151 + return PR_PRIORITY_URGENT; 1.152 +} 1.153 + 1.154 +PRUint32 1.155 +_bt_mapNativeToNSPRPriority( int32 priority ) 1.156 +{ 1.157 + switch( priority ) 1.158 + { 1.159 + case PR_PRIORITY_LOW: return( B_LOW_PRIORITY ); 1.160 + case PR_PRIORITY_NORMAL: return( B_NORMAL_PRIORITY ); 1.161 + case PR_PRIORITY_HIGH: return( B_DISPLAY_PRIORITY ); 1.162 + case PR_PRIORITY_URGENT: return( B_URGENT_DISPLAY_PRIORITY ); 1.163 + default: return( B_NORMAL_PRIORITY ); 1.164 + } 1.165 +} 1.166 + 1.167 +/* This method is called by all NSPR threads as they exit */ 1.168 +void _bt_CleanupThread(void *arg) 1.169 +{ 1.170 + PRThread *me = PR_GetCurrentThread(); 1.171 + int32 i; 1.172 + 1.173 + /* first, clean up all thread-private data */ 1.174 + for (i = 0; i < tpd_slotsUsed; i++) 1.175 + { 1.176 + void *oldValue = tls_get(tpd_beosTLSSlots[i]); 1.177 + if ( oldValue != NULL && tpd_dtors[i] != NULL ) 1.178 + (*tpd_dtors[i])(oldValue); 1.179 + } 1.180 + 1.181 + /* if this thread is joinable, wait for someone to join it */ 1.182 + if (me->state & BT_THREAD_JOINABLE) 1.183 + { 1.184 + /* protect access to our joinSem */ 1.185 + PR_Lock(joinSemLock); 1.186 + 1.187 + if (me->md.is_joining) 1.188 + { 1.189 + /* someone is already waiting to join us (they've 1.190 + allocated a joinSem for us) - let them know we're 1.191 + ready */ 1.192 + delete_sem(me->md.joinSem); 1.193 + 1.194 + PR_Unlock(joinSemLock); 1.195 + 1.196 + } 1.197 + else 1.198 + { 1.199 + /* noone is currently waiting for our demise - it 1.200 + is our responsibility to allocate the joinSem 1.201 + and block on it */ 1.202 + me->md.joinSem = create_sem(0, "join sem"); 1.203 + 1.204 + /* we're done accessing our joinSem */ 1.205 + PR_Unlock(joinSemLock); 1.206 + 1.207 + /* wait for someone to join us */ 1.208 + while (acquire_sem(me->md.joinSem) == B_INTERRUPTED); 1.209 + } 1.210 + } 1.211 + 1.212 + /* if this is a user thread, we must update our books */ 1.213 + if ((me->state & BT_THREAD_SYSTEM) == 0) 1.214 + { 1.215 + /* synchronize access to bt_book */ 1.216 + PR_Lock( bt_book.ml ); 1.217 + 1.218 + /* decrement the number of currently-alive user threads */ 1.219 + bt_book.threadCount--; 1.220 + 1.221 + if (bt_book.threadCount == 0 && bt_book.cleanUpSem != B_ERROR) { 1.222 + /* we are the last user thread, and the primordial thread is 1.223 + blocked in PR_Cleanup() waiting for us to finish - notify 1.224 + it */ 1.225 + delete_sem(bt_book.cleanUpSem); 1.226 + } 1.227 + 1.228 + PR_Unlock( bt_book.ml ); 1.229 + } 1.230 + 1.231 + /* finally, delete this thread's PRThread */ 1.232 + PR_DELETE(me); 1.233 +} 1.234 + 1.235 +/** 1.236 + * This is a wrapper that all threads invoke that allows us to set some 1.237 + * things up prior to a thread's invocation and clean up after a thread has 1.238 + * exited. 1.239 + */ 1.240 +static void* 1.241 +_bt_root (void* arg) 1.242 + { 1.243 + PRThread *thred = (PRThread*)arg; 1.244 + PRIntn rv; 1.245 + void *privData; 1.246 + status_t result; 1.247 + int i; 1.248 + 1.249 + /* save our PRThread object into our TLS */ 1.250 + tls_set(tls_prThreadSlot, thred); 1.251 + 1.252 + thred->startFunc(thred->arg); /* run the dang thing */ 1.253 + 1.254 + /* clean up */ 1.255 + _bt_CleanupThread(NULL); 1.256 + 1.257 + return 0; 1.258 +} 1.259 + 1.260 +PR_IMPLEMENT(PRThread*) 1.261 + PR_CreateThread (PRThreadType type, void (*start)(void* arg), void* arg, 1.262 + PRThreadPriority priority, PRThreadScope scope, 1.263 + PRThreadState state, PRUint32 stackSize) 1.264 +{ 1.265 + PRUint32 bePriority; 1.266 + 1.267 + PRThread* thred; 1.268 + 1.269 + if (!_pr_initialized) _PR_ImplicitInitialization(); 1.270 + 1.271 + thred = PR_NEWZAP(PRThread); 1.272 + if (thred == NULL) 1.273 + { 1.274 + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); 1.275 + return NULL; 1.276 + } 1.277 + 1.278 + thred->md.joinSem = B_ERROR; 1.279 + 1.280 + thred->arg = arg; 1.281 + thred->startFunc = start; 1.282 + thred->priority = priority; 1.283 + 1.284 + if( state == PR_JOINABLE_THREAD ) 1.285 + { 1.286 + thred->state |= BT_THREAD_JOINABLE; 1.287 + } 1.288 + 1.289 + /* keep some books */ 1.290 + 1.291 + PR_Lock( bt_book.ml ); 1.292 + 1.293 + if (type == PR_USER_THREAD) 1.294 + { 1.295 + bt_book.threadCount++; 1.296 + } 1.297 + 1.298 + PR_Unlock( bt_book.ml ); 1.299 + 1.300 + bePriority = _bt_MapNSPRToNativePriority( priority ); 1.301 + 1.302 + thred->md.tid = spawn_thread((thread_func)_bt_root, "moz-thread", 1.303 + bePriority, thred); 1.304 + if (thred->md.tid < B_OK) { 1.305 + PR_SetError(PR_UNKNOWN_ERROR, thred->md.tid); 1.306 + PR_DELETE(thred); 1.307 + return NULL; 1.308 + } 1.309 + 1.310 + if (resume_thread(thred->md.tid) < B_OK) { 1.311 + PR_SetError(PR_UNKNOWN_ERROR, 0); 1.312 + PR_DELETE(thred); 1.313 + return NULL; 1.314 + } 1.315 + 1.316 + return thred; 1.317 + } 1.318 + 1.319 +PR_IMPLEMENT(PRThread*) 1.320 + PR_AttachThread(PRThreadType type, PRThreadPriority priority, 1.321 + PRThreadStack *stack) 1.322 +{ 1.323 + /* PR_GetCurrentThread() will attach a thread if necessary */ 1.324 + return PR_GetCurrentThread(); 1.325 +} 1.326 + 1.327 +PR_IMPLEMENT(void) 1.328 + PR_DetachThread() 1.329 +{ 1.330 + /* we don't support detaching */ 1.331 +} 1.332 + 1.333 +PR_IMPLEMENT(PRStatus) 1.334 + PR_JoinThread (PRThread* thred) 1.335 +{ 1.336 + status_t eval, status; 1.337 + 1.338 + PR_ASSERT(thred != NULL); 1.339 + 1.340 + if ((thred->state & BT_THREAD_JOINABLE) == 0) 1.341 + { 1.342 + PR_SetError( PR_INVALID_ARGUMENT_ERROR, 0 ); 1.343 + return( PR_FAILURE ); 1.344 + } 1.345 + 1.346 + /* synchronize access to the thread's joinSem */ 1.347 + PR_Lock(joinSemLock); 1.348 + 1.349 + if (thred->md.is_joining) 1.350 + { 1.351 + /* another thread is already waiting to join the specified 1.352 + thread - we must fail */ 1.353 + PR_Unlock(joinSemLock); 1.354 + return PR_FAILURE; 1.355 + } 1.356 + 1.357 + /* let others know we are waiting to join */ 1.358 + thred->md.is_joining = PR_TRUE; 1.359 + 1.360 + if (thred->md.joinSem == B_ERROR) 1.361 + { 1.362 + /* the thread hasn't finished yet - it is our responsibility to 1.363 + allocate a joinSem and wait on it */ 1.364 + thred->md.joinSem = create_sem(0, "join sem"); 1.365 + 1.366 + /* we're done changing the joinSem now */ 1.367 + PR_Unlock(joinSemLock); 1.368 + 1.369 + /* wait for the thread to finish */ 1.370 + while (acquire_sem(thred->md.joinSem) == B_INTERRUPTED); 1.371 + 1.372 + } 1.373 + else 1.374 + { 1.375 + /* the thread has already finished, and has allocated the 1.376 + joinSem itself - let it know it can finally die */ 1.377 + delete_sem(thred->md.joinSem); 1.378 + 1.379 + PR_Unlock(joinSemLock); 1.380 + } 1.381 + 1.382 + /* make sure the thread is dead */ 1.383 + wait_for_thread(thred->md.tid, &eval); 1.384 + 1.385 + return PR_SUCCESS; 1.386 +} 1.387 + 1.388 +PR_IMPLEMENT(PRThread*) 1.389 + PR_GetCurrentThread () 1.390 +{ 1.391 + PRThread* thred; 1.392 + 1.393 + if (!_pr_initialized) _PR_ImplicitInitialization(); 1.394 + 1.395 + thred = (PRThread *)tls_get( tls_prThreadSlot); 1.396 + if (thred == NULL) 1.397 + { 1.398 + /* this thread doesn't have a PRThread structure (it must be 1.399 + a native thread not created by the NSPR) - assimilate it */ 1.400 + thred = _bt_AttachThread(); 1.401 + } 1.402 + PR_ASSERT(NULL != thred); 1.403 + 1.404 + return thred; 1.405 +} 1.406 + 1.407 +PR_IMPLEMENT(PRThreadScope) 1.408 + PR_GetThreadScope (const PRThread* thred) 1.409 +{ 1.410 + PR_ASSERT(thred != NULL); 1.411 + return PR_GLOBAL_THREAD; 1.412 +} 1.413 + 1.414 +PR_IMPLEMENT(PRThreadType) 1.415 + PR_GetThreadType (const PRThread* thred) 1.416 +{ 1.417 + PR_ASSERT(thred != NULL); 1.418 + return (thred->state & BT_THREAD_SYSTEM) ? 1.419 + PR_SYSTEM_THREAD : PR_USER_THREAD; 1.420 +} 1.421 + 1.422 +PR_IMPLEMENT(PRThreadState) 1.423 + PR_GetThreadState (const PRThread* thred) 1.424 +{ 1.425 + PR_ASSERT(thred != NULL); 1.426 + return (thred->state & BT_THREAD_JOINABLE)? 1.427 + PR_JOINABLE_THREAD: PR_UNJOINABLE_THREAD; 1.428 +} 1.429 + 1.430 +PR_IMPLEMENT(PRThreadPriority) 1.431 + PR_GetThreadPriority (const PRThread* thred) 1.432 +{ 1.433 + PR_ASSERT(thred != NULL); 1.434 + return thred->priority; 1.435 +} /* PR_GetThreadPriority */ 1.436 + 1.437 +PR_IMPLEMENT(void) PR_SetThreadPriority(PRThread *thred, 1.438 + PRThreadPriority newPri) 1.439 +{ 1.440 + PRUint32 bePriority; 1.441 + 1.442 + PR_ASSERT( thred != NULL ); 1.443 + 1.444 + thred->priority = newPri; 1.445 + bePriority = _bt_MapNSPRToNativePriority( newPri ); 1.446 + set_thread_priority( thred->md.tid, bePriority ); 1.447 +} 1.448 + 1.449 +PR_IMPLEMENT(PRStatus) 1.450 + PR_NewThreadPrivateIndex (PRUintn* newIndex, 1.451 + PRThreadPrivateDTOR destructor) 1.452 +{ 1.453 + int32 index; 1.454 + 1.455 + if (!_pr_initialized) _PR_ImplicitInitialization(); 1.456 + 1.457 + /* reserve the next available tpd slot */ 1.458 + index = atomic_add( &tpd_slotsUsed, 1 ); 1.459 + if (index >= BT_TPD_LIMIT) 1.460 + { 1.461 + /* no slots left - decrement value, then fail */ 1.462 + atomic_add( &tpd_slotsUsed, -1 ); 1.463 + PR_SetError( PR_TPD_RANGE_ERROR, 0 ); 1.464 + return( PR_FAILURE ); 1.465 + } 1.466 + 1.467 + /* allocate a beos-native TLS slot for this index (the new slot 1.468 + automatically contains NULL) */ 1.469 + tpd_beosTLSSlots[index] = tls_allocate(); 1.470 + 1.471 + /* remember the destructor */ 1.472 + tpd_dtors[index] = destructor; 1.473 + 1.474 + *newIndex = (PRUintn)index; 1.475 + 1.476 + return( PR_SUCCESS ); 1.477 +} 1.478 + 1.479 +PR_IMPLEMENT(PRStatus) 1.480 + PR_SetThreadPrivate (PRUintn index, void* priv) 1.481 +{ 1.482 + void *oldValue; 1.483 + 1.484 + /* 1.485 + ** Sanity checking 1.486 + */ 1.487 + 1.488 + if(index < 0 || index >= tpd_slotsUsed || index >= BT_TPD_LIMIT) 1.489 + { 1.490 + PR_SetError( PR_TPD_RANGE_ERROR, 0 ); 1.491 + return( PR_FAILURE ); 1.492 + } 1.493 + 1.494 + /* if the old value isn't NULL, and the dtor for this slot isn't 1.495 + NULL, we must destroy the data */ 1.496 + oldValue = tls_get(tpd_beosTLSSlots[index]); 1.497 + if (oldValue != NULL && tpd_dtors[index] != NULL) 1.498 + (*tpd_dtors[index])(oldValue); 1.499 + 1.500 + /* save new value */ 1.501 + tls_set(tpd_beosTLSSlots[index], priv); 1.502 + 1.503 + return( PR_SUCCESS ); 1.504 + } 1.505 + 1.506 +PR_IMPLEMENT(void*) 1.507 + PR_GetThreadPrivate (PRUintn index) 1.508 +{ 1.509 + /* make sure the index is valid */ 1.510 + if (index < 0 || index >= tpd_slotsUsed || index >= BT_TPD_LIMIT) 1.511 + { 1.512 + PR_SetError( PR_TPD_RANGE_ERROR, 0 ); 1.513 + return NULL; 1.514 + } 1.515 + 1.516 + /* return the value */ 1.517 + return tls_get( tpd_beosTLSSlots[index] ); 1.518 + } 1.519 + 1.520 + 1.521 +PR_IMPLEMENT(PRStatus) 1.522 + PR_Interrupt (PRThread* thred) 1.523 +{ 1.524 + PRIntn rv; 1.525 + 1.526 + PR_ASSERT(thred != NULL); 1.527 + 1.528 + /* 1.529 + ** there seems to be a bug in beos R5 in which calling 1.530 + ** resume_thread() on a blocked thread returns B_OK instead 1.531 + ** of B_BAD_THREAD_STATE (beos bug #20000422-19095). as such, 1.532 + ** to interrupt a thread, we will simply suspend then resume it 1.533 + ** (no longer call resume_thread(), check for B_BAD_THREAD_STATE, 1.534 + ** the suspend/resume to wake up a blocked thread). this wakes 1.535 + ** up blocked threads properly, and doesn't hurt unblocked threads 1.536 + ** (they simply get stopped then re-started immediately) 1.537 + */ 1.538 + 1.539 + rv = suspend_thread( thred->md.tid ); 1.540 + if( rv != B_NO_ERROR ) 1.541 + { 1.542 + /* this doesn't appear to be a valid thread_id */ 1.543 + PR_SetError( PR_UNKNOWN_ERROR, rv ); 1.544 + return PR_FAILURE; 1.545 + } 1.546 + 1.547 + rv = resume_thread( thred->md.tid ); 1.548 + if( rv != B_NO_ERROR ) 1.549 + { 1.550 + PR_SetError( PR_UNKNOWN_ERROR, rv ); 1.551 + return PR_FAILURE; 1.552 + } 1.553 + 1.554 + return PR_SUCCESS; 1.555 +} 1.556 + 1.557 +PR_IMPLEMENT(void) 1.558 + PR_ClearInterrupt () 1.559 +{ 1.560 +} 1.561 + 1.562 +PR_IMPLEMENT(PRStatus) 1.563 + PR_Yield () 1.564 +{ 1.565 + /* we just sleep for long enough to cause a reschedule (100 1.566 + microseconds) */ 1.567 + snooze(100); 1.568 +} 1.569 + 1.570 +#define BT_MILLION 1000000UL 1.571 + 1.572 +PR_IMPLEMENT(PRStatus) 1.573 + PR_Sleep (PRIntervalTime ticks) 1.574 +{ 1.575 + bigtime_t tps; 1.576 + status_t status; 1.577 + 1.578 + if (!_pr_initialized) _PR_ImplicitInitialization(); 1.579 + 1.580 + tps = PR_IntervalToMicroseconds( ticks ); 1.581 + 1.582 + status = snooze(tps); 1.583 + if (status == B_NO_ERROR) return PR_SUCCESS; 1.584 + 1.585 + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, status); 1.586 + return PR_FAILURE; 1.587 +} 1.588 + 1.589 +PR_IMPLEMENT(PRStatus) 1.590 + PR_Cleanup () 1.591 +{ 1.592 + PRThread *me = PR_GetCurrentThread(); 1.593 + 1.594 + PR_ASSERT(me->state & BT_THREAD_PRIMORD); 1.595 + if ((me->state & BT_THREAD_PRIMORD) == 0) { 1.596 + return PR_FAILURE; 1.597 + } 1.598 + 1.599 + PR_Lock( bt_book.ml ); 1.600 + 1.601 + if (bt_book.threadCount != 0) 1.602 + { 1.603 + /* we'll have to wait for some threads to finish - create a 1.604 + sem to block on */ 1.605 + bt_book.cleanUpSem = create_sem(0, "cleanup sem"); 1.606 + } 1.607 + 1.608 + PR_Unlock( bt_book.ml ); 1.609 + 1.610 + /* note that, if all the user threads were already dead, we 1.611 + wouldn't have created a sem above, so this acquire_sem() 1.612 + will fail immediately */ 1.613 + while (acquire_sem(bt_book.cleanUpSem) == B_INTERRUPTED); 1.614 + 1.615 + return PR_SUCCESS; 1.616 +} 1.617 + 1.618 +PR_IMPLEMENT(void) 1.619 + PR_ProcessExit (PRIntn status) 1.620 +{ 1.621 + exit(status); 1.622 +} 1.623 + 1.624 +PRThread *_bt_AttachThread() 1.625 +{ 1.626 + PRThread *thread; 1.627 + thread_info tInfo; 1.628 + 1.629 + /* make sure this thread doesn't already have a PRThread structure */ 1.630 + PR_ASSERT(tls_get(tls_prThreadSlot) == NULL); 1.631 + 1.632 + /* allocate a PRThread structure for this thread */ 1.633 + thread = PR_NEWZAP(PRThread); 1.634 + if (thread == NULL) 1.635 + { 1.636 + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); 1.637 + return NULL; 1.638 + } 1.639 + 1.640 + /* get the native thread's current state */ 1.641 + get_thread_info(find_thread(NULL), &tInfo); 1.642 + 1.643 + /* initialize new PRThread */ 1.644 + thread->md.tid = tInfo.thread; 1.645 + thread->md.joinSem = B_ERROR; 1.646 + thread->priority = _bt_MapNativeToNSPRPriority(tInfo.priority); 1.647 + 1.648 + /* attached threads are always non-joinable user threads */ 1.649 + thread->state = 0; 1.650 + 1.651 + /* increment user thread count */ 1.652 + PR_Lock(bt_book.ml); 1.653 + bt_book.threadCount++; 1.654 + PR_Unlock(bt_book.ml); 1.655 + 1.656 + /* store this thread's PRThread */ 1.657 + tls_set(tls_prThreadSlot, thread); 1.658 + 1.659 + /* the thread must call _bt_CleanupThread() before it dies, in order 1.660 + to clean up its PRThread, synchronize with the primordial thread, 1.661 + etc. */ 1.662 + on_exit_thread(_bt_CleanupThread, NULL); 1.663 + 1.664 + return thread; 1.665 +}