Changeset 102202 in vbox for trunk/src/libs/xpcom18a4/nsprpub
- Timestamp:
- Nov 21, 2023 1:16:56 PM (14 months ago)
- Location:
- trunk/src/libs/xpcom18a4/nsprpub/pr
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/libs/xpcom18a4/nsprpub/pr/include/prthread.h
r101900 r102202 80 80 81 81 #ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP 82 #define PR_CreateThread VBoxNsprPR_CreateThread83 #define PR_JoinThread VBoxNsprPR_JoinThread84 #define PR_Sleep VBoxNsprPR_Sleep85 82 #define PR_GetCurrentThread VBoxNsprPR_GetCurrentThread 86 #define PR_GetThreadState VBoxNsprPR_GetThreadState87 #define PR_SetThreadPrivate VBoxNsprPR_SetThreadPrivate88 #define PR_GetThreadPrivate VBoxNsprPR_GetThreadPrivate89 #define PR_NewThreadPrivateIndex VBoxNsprPR_NewThreadPrivateIndex90 #define PR_GetThreadPriority VBoxNsprPR_GetThreadPriority91 #define PR_SetThreadPriority VBoxNsprPR_SetThreadPriority92 #define PR_Interrupt VBoxNsprPR_Interrupt93 #define PR_ClearInterrupt VBoxNsprPR_ClearInterrupt94 #define PR_BlockInterrupt VBoxNsprPR_BlockInterrupt95 #define PR_UnblockInterrupt VBoxNsprPR_UnblockInterrupt96 #define PR_GetThreadScope VBoxNsprPR_GetThreadScope97 #define PR_GetThreadType VBoxNsprPR_GetThreadType98 83 #endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ 99 84 … … 130 115 131 116 /* 132 ** Create a new thread:133 ** "type" is the type of thread to create134 ** "start(arg)" will be invoked as the threads "main"135 ** "priority" will be created thread's priority136 ** "scope" will specify whether the thread is local or global137 ** "state" will specify whether the thread is joinable or not138 ** "stackSize" the size of the stack, in bytes. The value can be zero139 ** and then a machine specific stack size will be chosen.140 **141 ** This can return NULL if some kind of error occurs, such as if memory is142 ** tight.143 **144 ** If you want the thread to start up waiting for the creator to do145 ** something, enter a lock before creating the thread and then have the146 ** threads start routine enter and exit the same lock. When you are ready147 ** for the thread to run, exit the lock.148 **149 ** If you want to detect the completion of the created thread, the thread150 ** should be created joinable. Then, use PR_JoinThread to synchrnoize the151 ** termination of another thread.152 **153 ** When the start function returns the thread exits. If it is the last154 ** PR_USER_THREAD to exit then the process exits.155 */156 NSPR_API(PRThread*) PR_CreateThread(PRThreadType type,157 void (PR_CALLBACK *start)(void *arg),158 void *arg,159 PRThreadPriority priority,160 PRThreadScope scope,161 PRThreadState state,162 PRUint32 stackSize);163 164 /*165 ** Wait for thread termination:166 ** "thread" is the target thread167 **168 ** This can return PR_FAILURE if no joinable thread could be found169 ** corresponding to the specified target thread.170 **171 ** The calling thread is blocked until the target thread completes.172 ** Several threads cannot wait for the same thread to complete; one thread173 ** will operate successfully and others will terminate with an error PR_FAILURE.174 ** The calling thread will not be blocked if the target thread has already175 ** terminated.176 */177 NSPR_API(PRStatus) PR_JoinThread(PRThread *thread);178 179 /*180 117 ** Return the current thread object for the currently running code. 181 118 ** Never returns NULL. 182 119 */ 183 120 NSPR_API(PRThread*) PR_GetCurrentThread(void); 184 #ifndef NO_NSPR_10_SUPPORT185 #define PR_CurrentThread() PR_GetCurrentThread() /* for nspr1.0 compat. */186 #endif /* NO_NSPR_10_SUPPORT */187 188 /*189 ** Get the priority of "thread".190 */191 NSPR_API(PRThreadPriority) PR_GetThreadPriority(const PRThread *thread);192 193 /*194 ** Change the priority of the "thread" to "priority".195 */196 NSPR_API(void) PR_SetThreadPriority(PRThread *thread, PRThreadPriority priority);197 198 /*199 ** This routine returns a new index for per-thread-private data table.200 ** The index is visible to all threads within a process. This index can201 ** be used with the PR_SetThreadPrivate() and PR_GetThreadPrivate() routines202 ** to save and retrieve data associated with the index for a thread.203 **204 ** Each index is associationed with a destructor function ('dtor'). The function205 ** may be specified as NULL when the index is created. If it is not NULL, the206 ** function will be called when:207 ** - the thread exits and the private data for the associated index208 ** is not NULL,209 ** - new thread private data is set and the current private data is210 ** not NULL.211 **212 ** The index independently maintains specific values for each binding thread.213 ** A thread can only get access to its own thread-specific-data.214 **215 ** Upon a new index return the value associated with the index for all threads216 ** is NULL, and upon thread creation the value associated with all indices for217 ** that thread is NULL.218 **219 ** Returns PR_FAILURE if the total number of indices will exceed the maximun220 ** allowed.221 */222 typedef void (PR_CALLBACK *PRThreadPrivateDTOR)(void *priv);223 224 NSPR_API(PRStatus) PR_NewThreadPrivateIndex(225 PRUintn *newIndex, PRThreadPrivateDTOR destructor);226 227 /*228 ** Define some per-thread-private data.229 ** "tpdIndex" is an index into the per-thread private data table230 ** "priv" is the per-thread-private data231 **232 ** If the per-thread private data table has a previously registered233 ** destructor function and a non-NULL per-thread-private data value,234 ** the destructor function is invoked.235 **236 ** This can return PR_FAILURE if the index is invalid.237 */238 NSPR_API(PRStatus) PR_SetThreadPrivate(PRUintn tpdIndex, void *priv);239 240 /*241 ** Recover the per-thread-private data for the current thread. "tpdIndex" is242 ** the index into the per-thread private data table.243 **244 ** The returned value may be NULL which is indistinguishable from an error245 ** condition.246 **247 ** A thread can only get access to its own thread-specific-data.248 */249 NSPR_API(void*) PR_GetThreadPrivate(PRUintn tpdIndex);250 251 /*252 ** This routine sets the interrupt request for a target thread. The interrupt253 ** request remains in the thread's state until it is delivered exactly once254 ** or explicitly canceled.255 **256 ** A thread that has been interrupted will fail all NSPR blocking operations257 ** that return a PRStatus (I/O, waiting on a condition, etc).258 **259 ** PR_Interrupt may itself fail if the target thread is invalid.260 */261 NSPR_API(PRStatus) PR_Interrupt(PRThread *thread);262 263 /*264 ** Make the current thread sleep until "ticks" time amount of time265 ** has expired. If "ticks" is PR_INTERVAL_NO_WAIT then the call is266 ** equivalent to calling PR_Yield. Calling PR_Sleep with an argument267 ** equivalent to PR_INTERVAL_NO_TIMEOUT is an error and will result268 ** in a PR_FAILURE error return.269 */270 NSPR_API(PRStatus) PR_Sleep(PRIntervalTime ticks);271 272 /*273 ** Get the scoping of this thread.274 */275 NSPR_API(PRThreadScope) PR_GetThreadScope(const PRThread *thread);276 277 /*278 ** Get the type of this thread.279 */280 NSPR_API(PRThreadType) PR_GetThreadType(const PRThread *thread);281 282 /*283 ** Get the join state of this thread.284 */285 NSPR_API(PRThreadState) PR_GetThreadState(const PRThread *thread);286 121 287 122 PR_END_EXTERN_C -
trunk/src/libs/xpcom18a4/nsprpub/pr/src/pthreads/ptsynch.c
r102178 r102202 322 322 { 323 323 PRIntn rv; 324 PRThread *thred = PR_ CurrentThread();324 PRThread *thred = PR_GetCurrentThread(); 325 325 326 326 Assert(cvar != NULL); -
trunk/src/libs/xpcom18a4/nsprpub/pr/src/pthreads/ptthread.c
r102198 r102202 80 80 static void _pt_thread_death(void *arg); 81 81 82 #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING)83 static PRIntn pt_PriorityMap(PRThreadPriority pri)84 {85 return pt_book.minPrio +86 pri * (pt_book.maxPrio - pt_book.minPrio) / PR_PRIORITY_LAST;87 }88 #endif89 90 static void *_pt_root(void *arg)91 {92 PRIntn rv;93 PRThread *thred = (PRThread*)arg;94 PRBool detached = (thred->state & PT_THREAD_DETACHED) ? PR_TRUE : PR_FALSE;95 96 /*97 * Both the parent thread and this new thread set thred->id.98 * The new thread must ensure that thred->id is set before99 * it executes its startFunc. The parent thread must ensure100 * that thred->id is set before PR_CreateThread() returns.101 * Both threads set thred->id without holding a lock. Since102 * they are writing the same value, this unprotected double103 * write should be safe.104 */105 thred->id = pthread_self();106 107 /*108 * Set within the current thread the pointer to our object.109 * This object will be deleted when the thread termintates,110 * whether in a join or detached (see _PR_InitThreads()).111 */112 rv = pthread_setspecific(pt_book.key, thred);113 Assert(0 == rv);114 115 /* make the thread visible to the rest of the runtime */116 PR_Lock(pt_book.ml);117 118 /* If this is a GCABLE thread, set its state appropriately */119 if (thred->suspend & PT_THREAD_SETGCABLE)120 thred->state |= PT_THREAD_GCABLE;121 thred->suspend = 0;122 123 thred->prev = pt_book.last;124 pt_book.last->next = thred;125 thred->next = NULL;126 pt_book.last = thred;127 PR_Unlock(pt_book.ml);128 129 thred->startFunc(thred->arg); /* make visible to the client */130 131 /* unhook the thread from the runtime */132 PR_Lock(pt_book.ml);133 /*134 * At this moment, PR_CreateThread() may not have set thred->id yet.135 * It is safe for a detached thread to free thred only after136 * PR_CreateThread() has set thred->id.137 */138 if (detached)139 {140 while (!thred->okToDelete)141 PR_WaitCondVar(pt_book.cv, PR_INTERVAL_NO_TIMEOUT);142 }143 144 if (thred->state & PT_THREAD_SYSTEM)145 pt_book.system -= 1;146 else if (--pt_book.user == pt_book.this_many)147 PR_NotifyAllCondVar(pt_book.cv);148 thred->prev->next = thred->next;149 if (NULL == thred->next)150 pt_book.last = thred->prev;151 else152 thred->next->prev = thred->prev;153 PR_Unlock(pt_book.ml);154 155 /*156 * Here we set the pthread's backpointer to the PRThread to NULL.157 * Otherwise the desctructor would get called eagerly as the thread158 * returns to the pthread runtime. The joining thread would them be159 * the proud possessor of a dangling reference. However, this is the160 * last chance to delete the object if the thread is detached, so161 * just let the destuctor do the work.162 */163 if (PR_FALSE == detached)164 {165 rv = pthread_setspecific(pt_book.key, NULL);166 Assert(0 == rv);167 }168 169 return NULL;170 } /* _pt_root */171 172 static DECLCALLBACK(int) _pt_iprt_root(173 RTTHREAD Thread, void *pvUser)174 {175 PRThread *thred = (PRThread *)pvUser;176 _pt_root(thred);177 return VINF_SUCCESS;178 }179 180 82 static PRThread* pt_AttachThread(void) 181 83 { … … 218 120 } /* pt_AttachThread */ 219 121 220 static PRThread* _PR_CreateThread(221 PRThreadType type, void (*start)(void *arg),222 void *arg, PRThreadPriority priority, PRThreadScope scope,223 PRThreadState state, PRUint32 stackSize, PRBool isGCAble)224 {225 int rv;226 PRThread *thred;227 static uint32_t volatile s_iThread = 0;228 RTTHREADTYPE enmType;229 RTTHREAD hThread;230 uint32_t fFlags = 0;231 232 if (!_pr_initialized) _PR_ImplicitInitialization();233 234 if ((PRIntn)PR_PRIORITY_FIRST > (PRIntn)priority)235 priority = PR_PRIORITY_FIRST;236 else if ((PRIntn)PR_PRIORITY_LAST < (PRIntn)priority)237 priority = PR_PRIORITY_LAST;238 239 /* calc priority */240 switch (priority)241 {242 default:243 case PR_PRIORITY_NORMAL: enmType = RTTHREADTYPE_DEFAULT; break;244 case PR_PRIORITY_LOW: enmType = RTTHREADTYPE_MAIN_HEAVY_WORKER; break;245 case PR_PRIORITY_HIGH: enmType = RTTHREADTYPE_MAIN_WORKER; break;246 case PR_PRIORITY_URGENT: enmType = RTTHREADTYPE_IO; break;247 }248 249 if (state == PR_JOINABLE_THREAD)250 fFlags |= RTTHREADFLAGS_WAITABLE;251 252 thred = PR_NEWZAP(PRThread);253 if (NULL == thred)254 {255 PR_SetError(PR_OUT_OF_MEMORY_ERROR, errno);256 goto done;257 }258 else259 {260 pthread_t id;261 262 thred->arg = arg;263 thred->startFunc = start;264 thred->priority = priority;265 if (PR_UNJOINABLE_THREAD == state)266 thred->state |= PT_THREAD_DETACHED;267 268 if (PR_LOCAL_THREAD == scope)269 scope = PR_GLOBAL_THREAD;270 if (PR_GLOBAL_THREAD == scope)271 thred->state |= PT_THREAD_GLOBAL;272 else if (PR_GLOBAL_BOUND_THREAD == scope)273 thred->state |= (PT_THREAD_GLOBAL | PT_THREAD_BOUND);274 else /* force it global */275 thred->state |= PT_THREAD_GLOBAL;276 if (PR_SYSTEM_THREAD == type)277 thred->state |= PT_THREAD_SYSTEM;278 279 thred->suspend =(isGCAble) ? PT_THREAD_SETGCABLE : 0;280 281 #ifdef PT_NO_SIGTIMEDWAIT282 pthread_mutex_init(&thred->suspendResumeMutex,NULL);283 pthread_cond_init(&thred->suspendResumeCV,NULL);284 #endif285 286 /* make the thread counted to the rest of the runtime */287 PR_Lock(pt_book.ml);288 if (PR_SYSTEM_THREAD == type)289 pt_book.system += 1;290 else pt_book.user += 1;291 PR_Unlock(pt_book.ml);292 293 /*294 * We pass a pointer to a local copy (instead of thred->id)295 * to pthread_create() because who knows what wacky things296 * pthread_create() may be doing to its argument.297 */298 rv = RTThreadCreateF(&hThread, _pt_iprt_root, thred, stackSize, enmType, fFlags, "nspr-%u", ASMAtomicIncU32(&s_iThread));299 if (RT_SUCCESS(rv)) {300 RTMEM_WILL_LEAK(hThread);301 id = (pthread_t)RTThreadGetNative(hThread);302 rv = 0;303 }304 305 if (0 != rv)306 {307 PRIntn oserr = rv;308 PR_Lock(pt_book.ml);309 if (thred->state & PT_THREAD_SYSTEM)310 pt_book.system -= 1;311 else if (--pt_book.user == pt_book.this_many)312 PR_NotifyAllCondVar(pt_book.cv);313 PR_Unlock(pt_book.ml);314 315 PR_Free(thred); /* all that work ... poof! */316 PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, oserr);317 thred = NULL; /* and for what? */318 goto done;319 }320 321 /*322 * Both the parent thread and this new thread set thred->id.323 * The parent thread must ensure that thred->id is set before324 * PR_CreateThread() returns. (See comments in _pt_root().)325 */326 thred->id = id;327 328 /*329 * If the new thread is detached, tell it that PR_CreateThread()330 * has set thred->id so it's ok to delete thred.331 */332 if (PR_UNJOINABLE_THREAD == state)333 {334 PR_Lock(pt_book.ml);335 thred->okToDelete = PR_TRUE;336 PR_NotifyAllCondVar(pt_book.cv);337 PR_Unlock(pt_book.ml);338 }339 }340 341 done:342 return thred;343 } /* _PR_CreateThread */344 345 PR_IMPLEMENT(PRThread*) PR_CreateThread(346 PRThreadType type, void (*start)(void *arg), void *arg,347 PRThreadPriority priority, PRThreadScope scope,348 PRThreadState state, PRUint32 stackSize)349 {350 return _PR_CreateThread(351 type, start, arg, priority, scope, state, stackSize, PR_FALSE);352 } /* PR_CreateThread */353 354 PR_IMPLEMENT(PRStatus) PR_JoinThread(PRThread *thred)355 {356 int rv = -1;357 void *result = NULL;358 Assert(thred != NULL);359 360 if ((0xafafafaf == thred->state)361 || (PT_THREAD_DETACHED == (PT_THREAD_DETACHED & thred->state))362 || (PT_THREAD_FOREIGN == (PT_THREAD_FOREIGN & thred->state)))363 {364 /*365 * This might be a bad address, but if it isn't, the state should366 * either be an unjoinable thread or it's already had the object367 * deleted. However, the client that called join on a detached368 * thread deserves all the rath I can muster....369 */370 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);371 Log(("PR_JoinThread: 0x%X not joinable | already smashed\n", thred));372 }373 else374 {375 rv = VERR_INVALID_HANDLE;376 RTTHREAD hThread = RTThreadFromNative((RTNATIVETHREAD)thred->id);377 if (hThread != NIL_RTTHREAD)378 {379 int rcThread = 0;380 rv = RTThreadWait(hThread, RT_INDEFINITE_WAIT, &rcThread);381 Assert(RT_SUCCESS(rv) && rcThread == VINF_SUCCESS);382 if (RT_SUCCESS(rv))383 {384 rv = 0;385 _pt_thread_death(thred);386 }387 else388 PR_SetError(rv == VERR_THREAD_NOT_WAITABLE389 ? PR_INVALID_ARGUMENT_ERROR390 : PR_UNKNOWN_ERROR,391 rv);392 }393 }394 return (0 == rv) ? PR_SUCCESS : PR_FAILURE;395 } /* PR_JoinThread */396 397 122 PR_IMPLEMENT(PRThread*) PR_GetCurrentThread(void) 398 123 { … … 406 131 return (PRThread*)thred; 407 132 } /* PR_GetCurrentThread */ 408 409 PR_IMPLEMENT(PRThreadScope) PR_GetThreadScope(const PRThread *thred)410 {411 return (thred->state & PT_THREAD_BOUND) ?412 PR_GLOBAL_BOUND_THREAD : PR_GLOBAL_THREAD;413 } /* PR_GetThreadScope() */414 415 PR_IMPLEMENT(PRThreadType) PR_GetThreadType(const PRThread *thred)416 {417 return (thred->state & PT_THREAD_SYSTEM) ?418 PR_SYSTEM_THREAD : PR_USER_THREAD;419 }420 421 PR_IMPLEMENT(PRThreadState) PR_GetThreadState(const PRThread *thred)422 {423 return (thred->state & PT_THREAD_DETACHED) ?424 PR_UNJOINABLE_THREAD : PR_JOINABLE_THREAD;425 } /* PR_GetThreadState */426 427 PR_IMPLEMENT(PRThreadPriority) PR_GetThreadPriority(const PRThread *thred)428 {429 Assert(thred != NULL);430 return thred->priority;431 } /* PR_GetThreadPriority */432 433 PR_IMPLEMENT(void) PR_SetThreadPriority(PRThread *thred, PRThreadPriority newPri)434 {435 PRIntn rv = -1;436 437 Assert(NULL != thred);438 439 if ((PRIntn)PR_PRIORITY_FIRST > (PRIntn)newPri)440 newPri = PR_PRIORITY_FIRST;441 else if ((PRIntn)PR_PRIORITY_LAST < (PRIntn)newPri)442 newPri = PR_PRIORITY_LAST;443 444 #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING)445 if (EPERM != pt_schedpriv)446 {447 int policy;448 struct sched_param schedule;449 450 rv = pthread_getschedparam(thred->id, &policy, &schedule);451 if(0 == rv) {452 schedule.sched_priority = pt_PriorityMap(newPri);453 rv = pthread_setschedparam(thred->id, policy, &schedule);454 if (EPERM == rv)455 {456 pt_schedpriv = EPERM;457 Log(("PR_SetThreadPriority: no thread scheduling privilege\n"));458 }459 }460 if (rv != 0)461 rv = -1;462 }463 #endif464 465 thred->priority = newPri;466 } /* PR_SetThreadPriority */467 468 PR_IMPLEMENT(PRStatus) PR_Interrupt(PRThread *thred)469 {470 /*471 ** If the target thread indicates that it's waiting,472 ** find the condition and broadcast to it. Broadcast473 ** since we don't know which thread (if there are more474 ** than one). This sounds risky, but clients must475 ** test their invariants when resumed from a wait and476 ** I don't expect very many threads to be waiting on477 ** a single condition and I don't expect interrupt to478 ** be used very often.479 **480 ** I don't know why I thought this would work. Must have481 ** been one of those weaker momements after I'd been482 ** smelling the vapors.483 **484 ** Even with the followng changes it is possible that485 ** the pointer to the condition variable is pointing486 ** at a bogus value. Will the unerlying code detect487 ** that?488 */489 PRCondVar *cv;490 Assert(NULL != thred);491 if (NULL == thred) return PR_FAILURE;492 493 thred->state |= PT_THREAD_ABORTED;494 495 cv = thred->waiting;496 if ((NULL != cv) && !thred->interrupt_blocked)497 {498 PRIntn rv;499 ASMAtomicIncU32(&cv->notify_pending);500 rv = pthread_cond_broadcast(&cv->cv);501 Assert(0 == rv);502 if (0 > ASMAtomicDecU32(&cv->notify_pending))503 PR_DestroyCondVar(cv);504 }505 return PR_SUCCESS;506 } /* PR_Interrupt */507 133 508 134 static void _pt_thread_death(void *arg) … … 607 233 rv = pthread_setspecific(pt_book.key, thred); 608 234 Assert(0 == rv); 609 PR_SetThreadPriority(thred, priority);610 235 } /* _PR_InitThreads */ 611 236 612 237 PR_IMPLEMENT(PRStatus) PR_Cleanup(void) 613 238 { 614 PRThread *me = PR_ CurrentThread();239 PRThread *me = PR_GetCurrentThread(); 615 240 Log(("PR_Cleanup: shutting down NSPR\n")); 616 241 Assert(me->state & PT_THREAD_PRIMORD);
Note:
See TracChangeset
for help on using the changeset viewer.