Changeset 101899 in vbox for trunk/src/libs/xpcom18a4/nsprpub
- Timestamp:
- Nov 6, 2023 8:10:50 PM (15 months ago)
- Location:
- trunk/src/libs/xpcom18a4/nsprpub/pr
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/libs/xpcom18a4/nsprpub/pr/include/private/pprthred.h
r101877 r101899 53 53 54 54 #ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP 55 #define PR_AttachThread VBoxNsprPR_AttachThread56 55 #define PR_DetachThread VBoxNsprPR_DetachThread 57 56 #define PR_GetThreadID VBoxNsprPR_GetThreadID … … 61 60 #define PR_SetCPUAffinityMask VBoxNsprPR_SetCPUAffinityMask 62 61 #define PR_ShowStatus VBoxNsprPR_ShowStatus 63 #define PR_SetThreadRecycleMode VBoxNsprPR_SetThreadRecycleMode64 #define PR_CreateThreadGCAble VBoxNsprPR_CreateThreadGCAble65 #define PR_AttachThreadGCAble VBoxNsprPR_AttachThreadGCAble66 #define PR_SetThreadGCAble VBoxNsprPR_SetThreadGCAble67 #define PR_ClearThreadGCAble VBoxNsprPR_ClearThreadGCAble68 #define PR_SuspendAll VBoxNsprPR_SuspendAll69 #define PR_ResumeAll VBoxNsprPR_ResumeAll70 #define PR_GetSP VBoxNsprPR_GetSP71 #define GetExecutionEnvironment VBoxNsprGetExecutionEnvironment72 #define SetExecutionEnvironment VBoxNsprSetExecutionEnvironment73 #define PR_EnumerateThreads VBoxNsprPR_EnumerateThreads74 62 #define PR_ThreadScanStackPointers VBoxNsprPR_ThreadScanStackPointers 75 63 #define PR_ScanStackPointers VBoxNsprPR_ScanStackPointers … … 79 67 #define PR_TestAndEnterMonitor VBoxNsprPR_TestAndEnterMonitor 80 68 #define PR_GetMonitorEntryCount VBoxNsprPR_GetMonitorEntryCount 81 #define PR_CTestAndEnterMonitor VBoxNsprPR_CTestAndEnterMonitor82 #define PR_Mac_WaitForAsyncNotify VBoxNsprPR_Mac_WaitForAsyncNotify83 #define PR_Mac_PostAsyncNotify VBoxNsprPR_Mac_PostAsyncNotify84 #define PR_OS2_SetFloatExcpHandler VBoxNsprPR_OS2_SetFloatExcpHandler85 #define PR_OS2_UnsetFloatExcpHandler VBoxNsprPR_OS2_UnsetFloatExcpHandler86 69 #endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ 87 70 … … 91 74 ** THREAD PRIVATE FUNCTIONS 92 75 ---------------------------------------------------------------------------*/ 93 94 /*95 ** Associate a thread object with an existing native thread.96 ** "type" is the type of thread object to attach97 ** "priority" is the priority to assign to the thread98 ** "stack" defines the shape of the threads stack99 **100 ** This can return NULL if some kind of error occurs, or if memory is101 ** tight. This call invokes "start(obj,arg)" and returns when the102 ** function returns. The thread object is automatically destroyed.103 **104 ** This call is not normally needed unless you create your own native105 ** thread. PR_Init does this automatically for the primordial thread.106 */107 NSPR_API(PRThread*) PR_AttachThread(PRThreadType type,108 PRThreadPriority priority,109 PRThreadStack *stack);110 111 /*112 ** Detach the nspr thread from the currently executing native thread.113 ** The thread object will be destroyed and all related data attached114 ** to it. The exit procs will be invoked.115 **116 ** This call is not normally needed unless you create your own native117 ** thread. PR_Exit will automatially detach the nspr thread object118 ** created by PR_Init for the primordial thread.119 **120 ** This call returns after the nspr thread object is destroyed.121 */122 NSPR_API(void) PR_DetachThread(void);123 76 124 77 /* … … 160 113 NSPR_API(PRInt32) PR_SetCPUAffinityMask(PRUint32 mask); 161 114 162 /*163 ** Show status of all threads to standard error output.164 */165 NSPR_API(void) PR_ShowStatus(void);166 167 /*168 ** Set thread recycle mode to on (1) or off (0)169 */170 NSPR_API(void) PR_SetThreadRecycleMode(PRUint32 flag);171 172 173 /*---------------------------------------------------------------------------174 ** THREAD PRIVATE FUNCTIONS FOR GARBAGE COLLECTIBLE THREADS175 ---------------------------------------------------------------------------*/176 177 /*178 ** Only Garbage collectible threads participate in resume all, suspend all and179 ** enumeration operations. They are also different during creation when180 ** platform specific action may be needed (For example, all Solaris GC able181 ** threads are bound threads).182 */183 184 /*185 ** Same as PR_CreateThread except that the thread is marked as garbage186 ** collectible.187 */188 NSPR_API(PRThread*) PR_CreateThreadGCAble(PRThreadType type,189 void (*start)(void *arg),190 void *arg,191 PRThreadPriority priority,192 PRThreadScope scope,193 PRThreadState state,194 PRUint32 stackSize);195 196 /*197 ** Same as PR_AttachThread except that the thread being attached is marked as198 ** garbage collectible.199 */200 NSPR_API(PRThread*) PR_AttachThreadGCAble(PRThreadType type,201 PRThreadPriority priority,202 PRThreadStack *stack);203 204 /*205 ** Mark the thread as garbage collectible.206 */207 NSPR_API(void) PR_SetThreadGCAble(void);208 209 /*210 ** Unmark the thread as garbage collectible.211 */212 NSPR_API(void) PR_ClearThreadGCAble(void);213 214 /*215 ** This routine prevents all other GC able threads from running. This call is needed by216 ** the garbage collector.217 */218 NSPR_API(void) PR_SuspendAll(void);219 220 /*221 ** This routine unblocks all other GC able threads that were suspended from running by222 ** PR_SuspendAll(). This call is needed by the garbage collector.223 */224 NSPR_API(void) PR_ResumeAll(void);225 226 /*227 ** Return the thread stack pointer of the given thread.228 ** Needed by the garbage collector.229 */230 NSPR_API(void *) PR_GetSP(PRThread *thread);231 232 /*233 ** (Get|Set)ExecutionEnvironent234 **235 ** Used by Java to associate it's execution environment so garbage collector236 ** can find it. If return is NULL, then it's probably not a collectable thread.237 **238 ** There's no locking required around these calls.239 */240 NSPR_API(void*) GetExecutionEnvironment(PRThread *thread);241 NSPR_API(void) SetExecutionEnvironment(PRThread* thread, void *environment);242 243 /*244 ** Enumeration function that applies "func(thread,i,arg)" to each active245 ** thread in the process. The enumerator returns PR_SUCCESS if the enumeration246 ** should continue, any other value is considered failure, and enumeration247 ** stops, returning the failure value from PR_EnumerateThreads.248 ** Needed by the garbage collector.249 */250 typedef PRStatus (PR_CALLBACK *PREnumerator)(PRThread *t, int i, void *arg);251 NSPR_API(PRStatus) PR_EnumerateThreads(PREnumerator func, void *arg);252 253 /*---------------------------------------------------------------------------254 ** THREAD CPU PRIVATE FUNCTIONS255 ---------------------------------------------------------------------------*/256 257 /*258 ** Get a pointer to the primordial CPU.259 */260 NSPR_API(struct _PRCPU *) _PR_GetPrimordialCPU(void);261 115 262 116 /*--------------------------------------------------------------------------- … … 293 147 NSPR_API(PRIntn) PR_GetMonitorEntryCount(PRMonitor *mon); 294 148 295 /*296 ** Just like PR_CEnterMonitor except that if the monitor is owned by297 ** another thread NULL is returned.298 */299 NSPR_API(PRMonitor*) PR_CTestAndEnterMonitor(void *address);300 301 149 /*--------------------------------------------------------------------------- 302 150 ** PLATFORM-SPECIFIC INITIALIZATION FUNCTIONS -
trunk/src/libs/xpcom18a4/nsprpub/pr/include/prlog.h
r11551 r101899 205 205 #if (defined(DEBUG) || defined(FORCE_PR_LOG)) && !defined(WIN16) 206 206 #define PR_LOGGING 1 207 208 207 #define PR_LOG_TEST(_module,_level) \ 209 208 ((_module)->level >= (_level)) -
trunk/src/libs/xpcom18a4/nsprpub/pr/src/pthreads/ptthread.c
r101891 r101899 51 51 #include <signal.h> 52 52 53 #ifdef VBOX_USE_IPRT_IN_NSPR 54 # include <iprt/thread.h> 55 # include <iprt/mem.h> 56 # include <iprt/asm.h> 57 # include <iprt/err.h> 58 #endif /* VBOX_USE_IPRT_IN_NSPR */ 53 #include <iprt/thread.h> 54 #include <iprt/mem.h> 55 #include <iprt/asm.h> 56 #include <iprt/err.h> 59 57 60 58 /* … … 75 73 pthread_key_t key; /* private private data key */ 76 74 PRThread *first, *last; /* list of threads we know about */ 77 #if defined(_P R_DCETHREADS) || defined(_POSIX_THREAD_PRIORITY_SCHEDULING)75 #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) 78 76 PRInt32 minPrio, maxPrio; /* range of scheduling priorities */ 79 77 #endif … … 81 79 82 80 static void _pt_thread_death(void *arg); 83 static void init_pthread_gc_support(void); 84 85 #if defined(_PR_DCETHREADS) || defined(_POSIX_THREAD_PRIORITY_SCHEDULING) 81 82 #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) 86 83 static PRIntn pt_PriorityMap(PRThreadPriority pri) 87 84 { 88 #ifdef NTO89 /* This priority algorithm causes lots of problems on Neutrino90 * for now I have just hard coded everything to run at priority 1091 * until I can come up with a new algorithm.92 * [email protected]93 */94 return 10;95 #else96 85 return pt_book.minPrio + 97 86 pri * (pt_book.maxPrio - pt_book.minPrio) / PR_PRIORITY_LAST; 98 #endif99 87 } 100 88 #endif … … 139 127 thred->id = pthread_self(); 140 128 141 /*142 ** DCE Threads can't detach during creation, so do it late.143 ** I would like to do it only here, but that doesn't seem144 ** to work.145 */146 #if defined(_PR_DCETHREADS)147 if (detached)148 {149 /* pthread_detach() modifies its argument, so we must pass a copy */150 pthread_t self = thred->id;151 rv = pthread_detach(&self);152 PR_ASSERT(0 == rv);153 }154 #endif /* defined(_PR_DCETHREADS) */155 156 129 /* Set up the thread stack information */ 157 130 _PR_InitializeStack(thred->stack); … … 222 195 } /* _pt_root */ 223 196 224 #ifdef VBOX_USE_IPRT_IN_NSPR225 197 static DECLCALLBACK(int) _pt_iprt_root( 226 198 RTTHREAD Thread, void *pvUser) … … 230 202 return VINF_SUCCESS; 231 203 } 232 #endif /* VBOX_USE_IPRT_IN_NSPR */233 204 234 205 static PRThread* pt_AttachThread(void) … … 279 250 int rv; 280 251 PRThread *thred; 281 #ifndef VBOX_USE_IPRT_IN_NSPR282 pthread_attr_t tattr;283 #else284 252 static uint32_t volatile s_iThread = 0; 285 253 RTTHREADTYPE enmType; 286 254 RTTHREAD hThread; 287 255 uint32_t fFlags = 0; 288 #endif289 256 290 257 if (!_pr_initialized) _PR_ImplicitInitialization(); … … 295 262 priority = PR_PRIORITY_LAST; 296 263 297 #ifndef VBOX_USE_IPRT_IN_NSPR298 rv = _PT_PTHREAD_ATTR_INIT(&tattr);299 PR_ASSERT(0 == rv);300 301 if (EPERM != pt_schedpriv)302 {303 #if !defined(_PR_DCETHREADS) && defined(_POSIX_THREAD_PRIORITY_SCHEDULING)304 struct sched_param schedule;305 #endif306 307 #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING)308 rv = pthread_attr_setinheritsched(&tattr, PTHREAD_EXPLICIT_SCHED);309 PR_ASSERT(0 == rv);310 #endif311 312 /* Use the default scheduling policy */313 314 #if defined(_PR_DCETHREADS)315 rv = pthread_attr_setprio(&tattr, pt_PriorityMap(priority));316 PR_ASSERT(0 == rv);317 #elif defined(_POSIX_THREAD_PRIORITY_SCHEDULING)318 rv = pthread_attr_getschedparam(&tattr, &schedule);319 PR_ASSERT(0 == rv);320 schedule.sched_priority = pt_PriorityMap(priority);321 rv = pthread_attr_setschedparam(&tattr, &schedule);322 PR_ASSERT(0 == rv);323 #ifdef NTO324 rv = pthread_attr_setschedpolicy(&tattr, SCHED_RR); /* Round Robin */325 PR_ASSERT(0 == rv);326 #endif327 #endif /* !defined(_PR_DCETHREADS) */328 }329 #else /* VBOX_USE_IPRT_IN_NSPR */330 264 /* calc priority */ 331 265 switch (priority) … … 337 271 case PR_PRIORITY_URGENT: enmType = RTTHREADTYPE_IO; break; 338 272 } 339 #endif /* VBOX_USE_IPRT_IN_NSPR */ 340 341 #ifndef VBOX_USE_IPRT_IN_NSPR 342 /* 343 * DCE threads can't set detach state before creating the thread. 344 * AIX can't set detach late. Why can't we all just get along? 345 */ 346 #if !defined(_PR_DCETHREADS) 347 rv = pthread_attr_setdetachstate(&tattr, 348 ((PR_JOINABLE_THREAD == state) ? 349 PTHREAD_CREATE_JOINABLE : PTHREAD_CREATE_DETACHED)); 350 PR_ASSERT(0 == rv); 351 #endif /* !defined(_PR_DCETHREADS) */ 352 #else 273 353 274 if (state == PR_JOINABLE_THREAD) 354 275 fFlags |= RTTHREADFLAGS_WAITABLE; 355 #endif /* !VBOX_USE_IPRT_IN_NSPR */356 357 #ifndef VBOX_USE_IPRT_IN_NSPR /* We let stackSize stay zero and let IPRT choose a default size. */358 if (0 == stackSize) stackSize = (64 * 1024); /* default == 64K */359 #ifdef _MD_MINIMUM_STACK_SIZE360 if (stackSize < _MD_MINIMUM_STACK_SIZE) stackSize = _MD_MINIMUM_STACK_SIZE;361 #endif362 /*363 * Linux doesn't have pthread_attr_setstacksize.364 */365 #ifndef LINUX366 rv = pthread_attr_setstacksize(&tattr, stackSize);367 PR_ASSERT(0 == rv);368 #endif369 #endif /* !VBOX_USE_IPRT_IN_NSPR */370 276 371 277 thred = PR_NEWZAP(PRThread); … … 387 293 if (PR_LOCAL_THREAD == scope) 388 294 scope = PR_GLOBAL_THREAD; 389 390 #ifndef VBOX_USE_IPRT_IN_NSPR391 if (PR_GLOBAL_BOUND_THREAD == scope) {392 #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING)393 rv = pthread_attr_setscope(&tattr, PTHREAD_SCOPE_SYSTEM);394 if (rv) {395 /*396 * system scope not supported397 */398 scope = PR_GLOBAL_THREAD;399 /*400 * reset scope401 */402 rv = pthread_attr_setscope(&tattr, PTHREAD_SCOPE_PROCESS);403 PR_ASSERT(0 == rv);404 }405 #endif406 }407 #endif /* !VBOX_USE_IPRT_IN_NSPR */408 295 if (PR_GLOBAL_THREAD == scope) 409 296 thred->state |= PT_THREAD_GLOBAL; … … 445 332 * pthread_create() may be doing to its argument. 446 333 */ 447 #ifndef VBOX_USE_IPRT_IN_NSPR448 rv = _PT_PTHREAD_CREATE(&id, tattr, _pt_root, thred);449 450 #if !defined(_PR_DCETHREADS)451 if (EPERM == rv)452 {453 #if defined(IRIX)454 if (PR_GLOBAL_BOUND_THREAD == scope) {455 /*456 * SCOPE_SYSTEM requires appropriate privilege457 * reset to process scope and try again458 */459 rv = pthread_attr_setscope(&tattr, PTHREAD_SCOPE_PROCESS);460 PR_ASSERT(0 == rv);461 thred->state &= ~PT_THREAD_BOUND;462 }463 #else464 /* Remember that we don't have thread scheduling privilege. */465 pt_schedpriv = EPERM;466 PR_LOG(_pr_thread_lm, PR_LOG_MIN,467 ("_PR_CreateThread: no thread scheduling privilege"));468 /* Try creating the thread again without setting priority. */469 #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING)470 rv = pthread_attr_setinheritsched(&tattr, PTHREAD_INHERIT_SCHED);471 PR_ASSERT(0 == rv);472 #endif473 #endif /* IRIX */474 rv = _PT_PTHREAD_CREATE(&id, tattr, _pt_root, thred);475 }476 #endif477 #else /* VBOX_USE_IPRT_IN_NSPR */478 334 rv = RTThreadCreateF(&hThread, _pt_iprt_root, thred, stackSize, enmType, fFlags, "nspr-%u", ASMAtomicIncU32(&s_iThread)); 479 335 if (RT_SUCCESS(rv)) { 480 #ifdef VBOX_USE_IPRT_IN_NSPR481 336 RTMEM_WILL_LEAK(hThread); 482 #endif483 337 id = (pthread_t)RTThreadGetNative(hThread); 484 338 rv = 0; 485 339 } 486 #endif /* VBOX_USE_IPRT_IN_NSPR */487 340 488 341 if (0 != rv) 489 342 { 490 #if defined(_PR_DCETHREADS)491 PRIntn oserr = errno;492 #else493 343 PRIntn oserr = rv; 494 #endif495 344 PR_Lock(pt_book.ml); 496 345 if (thred->state & PT_THREAD_SYSTEM) … … 528 377 529 378 done: 530 #ifndef VBOX_USE_IPRT_IN_NSPR531 rv = _PT_PTHREAD_ATTR_DESTROY(&tattr);532 PR_ASSERT(0 == rv);533 #endif534 535 379 return thred; 536 380 } /* _PR_CreateThread */ … … 544 388 type, start, arg, priority, scope, state, stackSize, PR_FALSE); 545 389 } /* PR_CreateThread */ 546 547 PR_IMPLEMENT(PRThread*) PR_CreateThreadGCAble(548 PRThreadType type, void (*start)(void *arg), void *arg,549 PRThreadPriority priority, PRThreadScope scope,550 PRThreadState state, PRUint32 stackSize)551 {552 return _PR_CreateThread(553 type, start, arg, priority, scope, state, stackSize, PR_TRUE);554 } /* PR_CreateThreadGCAble */555 556 PR_IMPLEMENT(void*) GetExecutionEnvironment(PRThread *thred)557 {558 return thred->environment;559 } /* GetExecutionEnvironment */560 561 PR_IMPLEMENT(void) SetExecutionEnvironment(PRThread *thred, void *env)562 {563 thred->environment = env;564 } /* SetExecutionEnvironment */565 566 PR_IMPLEMENT(PRThread*) PR_AttachThread(567 PRThreadType type, PRThreadPriority priority, PRThreadStack *stack)568 {569 return PR_GetCurrentThread();570 } /* PR_AttachThread */571 572 390 573 391 PR_IMPLEMENT(PRStatus) PR_JoinThread(PRThread *thred) … … 593 411 else 594 412 { 595 #ifndef VBOX_USE_IPRT_IN_NSPR596 pthread_t id = thred->id;597 rv = pthread_join(id, &result);598 PR_ASSERT(rv == 0 && result == NULL);599 if (0 == rv)600 {601 #ifdef _PR_DCETHREADS602 rv = pthread_detach(&id);603 PR_ASSERT(0 == rv);604 #endif605 _pt_thread_death(thred);606 }607 else608 {609 PRErrorCode prerror;610 switch (rv)611 {612 case EINVAL: /* not a joinable thread */613 case ESRCH: /* no thread with given ID */614 prerror = PR_INVALID_ARGUMENT_ERROR;615 break;616 case EDEADLK: /* a thread joining with itself */617 prerror = PR_DEADLOCK_ERROR;618 break;619 default:620 prerror = PR_UNKNOWN_ERROR;621 break;622 }623 PR_SetError(prerror, rv);624 }625 #else /* VBOX_USE_IPRT_IN_NSPR */626 413 rv = VERR_INVALID_HANDLE; 627 414 RTTHREAD hThread = RTThreadFromNative((RTNATIVETHREAD)thred->id); … … 642 429 rv); 643 430 } 644 #endif /* VBOX_USE_IPRT_IN_NSPR */645 431 } 646 432 return (0 == rv) ? PR_SUCCESS : PR_FAILURE; 647 433 } /* PR_JoinThread */ 648 649 PR_IMPLEMENT(void) PR_DetachThread(void) { } /* PR_DetachThread */650 434 651 435 PR_IMPLEMENT(PRThread*) PR_GetCurrentThread(void) … … 696 480 newPri = PR_PRIORITY_LAST; 697 481 698 #if defined(_PR_DCETHREADS) 699 rv = pthread_setprio(thred->id, pt_PriorityMap(newPri)); 700 /* pthread_setprio returns the old priority */ 701 #elif defined(_POSIX_THREAD_PRIORITY_SCHEDULING) 482 #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) 702 483 if (EPERM != pt_schedpriv) 703 484 { … … 855 636 PRThread *thred; 856 637 857 #ifdef _PR_NEED_PTHREAD_INIT 858 /* 859 * On BSD/OS (3.1 and 4.0), the pthread subsystem is lazily 860 * initialized, but pthread_self() fails to initialize 861 * pthreads and hence returns a null thread ID if invoked 862 * by the primordial thread before any other pthread call. 863 * So we explicitly initialize pthreads here. 864 */ 865 pthread_init(); 866 #endif 867 868 #if defined(_PR_DCETHREADS) || defined(_POSIX_THREAD_PRIORITY_SCHEDULING) 638 #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) 869 639 #if defined(FREEBSD) 870 640 { … … 984 754 } /* PR_Cleanup */ 985 755 986 PR_IMPLEMENT(void) PR_ProcessExit(PRIntn status)987 {988 _exit(status);989 }990 991 PR_IMPLEMENT(PRUint32) PR_GetThreadID(PRThread *thred)992 {993 #if defined(_PR_DCETHREADS)994 return (PRUint32)&thred->id; /* this is really a sham! */995 #else996 return (PRUint32)thred->id; /* and I don't know what they will do with it */997 #endif998 }999 1000 /*1001 * $$$1002 * The following two thread-to-processor affinity functions are not1003 * yet implemented for pthreads. By the way, these functions should return1004 * PRStatus rather than PRInt32 to indicate the success/failure status.1005 * $$$1006 */1007 1008 PR_IMPLEMENT(PRInt32) PR_GetThreadAffinityMask(PRThread *thread, PRUint32 *mask)1009 {1010 return 0; /* not implemented */1011 }1012 1013 PR_IMPLEMENT(PRInt32) PR_SetThreadAffinityMask(PRThread *thread, PRUint32 mask )1014 {1015 return 0; /* not implemented */1016 }1017 1018 PR_IMPLEMENT(void)1019 PR_SetThreadDumpProc(PRThread* thread, PRThreadDumpProc dump, void *arg)1020 {1021 thread->dump = dump;1022 thread->dumpArg = arg;1023 }1024 1025 /*1026 * Garbage collection support follows.1027 */1028 1029 #if defined(_PR_DCETHREADS)1030 1031 /*1032 * statics for Garbage Collection support. We don't need to protect these1033 * signal masks since the garbage collector itself is protected by a lock1034 * and multiple threads will not be garbage collecting at the same time.1035 */1036 static sigset_t javagc_vtalarm_sigmask;1037 static sigset_t javagc_intsoff_sigmask;1038 1039 #else /* defined(_PR_DCETHREADS) */1040 1041 /* a bogus signal mask for forcing a timed wait */1042 /* Not so bogus in AIX as we really do a sigwait */1043 static sigset_t sigwait_set;1044 1045 static struct timespec onemillisec = {0, 1000000L};1046 #ifndef PT_NO_SIGTIMEDWAIT1047 static struct timespec hundredmillisec = {0, 100000000L};1048 #endif1049 1050 static void suspend_signal_handler(PRIntn sig);1051 1052 #ifdef PT_NO_SIGTIMEDWAIT1053 static void null_signal_handler(PRIntn sig);1054 #endif1055 1056 #endif /* defined(_PR_DCETHREADS) */1057 1058 /*1059 * Linux pthreads use SIGUSR1 and SIGUSR2 internally, which1060 * conflict with the use of these two signals in our GC support.1061 * So we don't know how to support GC on Linux pthreads.1062 */1063 static void init_pthread_gc_support(void)1064 {1065 PRIntn rv;1066 1067 #if defined(_PR_DCETHREADS)1068 rv = sigemptyset(&javagc_vtalarm_sigmask);1069 PR_ASSERT(0 == rv);1070 rv = sigaddset(&javagc_vtalarm_sigmask, SIGVTALRM);1071 PR_ASSERT(0 == rv);1072 #else /* defined(_PR_DCETHREADS) */1073 {1074 struct sigaction sigact_usr2;1075 1076 sigact_usr2.sa_handler = suspend_signal_handler;1077 sigact_usr2.sa_flags = SA_RESTART;1078 sigemptyset (&sigact_usr2.sa_mask);1079 1080 rv = sigaction (SIGUSR2, &sigact_usr2, NULL);1081 PR_ASSERT(0 == rv);1082 1083 sigemptyset (&sigwait_set);1084 #if defined(PT_NO_SIGTIMEDWAIT)1085 sigaddset (&sigwait_set, SIGUSR1);1086 #else1087 sigaddset (&sigwait_set, SIGUSR2);1088 #endif /* defined(PT_NO_SIGTIMEDWAIT) */1089 }1090 #if defined(PT_NO_SIGTIMEDWAIT)1091 {1092 struct sigaction sigact_null;1093 sigact_null.sa_handler = null_signal_handler;1094 sigact_null.sa_flags = SA_RESTART;1095 sigemptyset (&sigact_null.sa_mask);1096 rv = sigaction (SIGUSR1, &sigact_null, NULL);1097 PR_ASSERT(0 ==rv);1098 }1099 #endif /* defined(PT_NO_SIGTIMEDWAIT) */1100 #endif /* defined(_PR_DCETHREADS) */1101 }1102 1103 PR_IMPLEMENT(void) PR_SetThreadGCAble(void)1104 {1105 PR_Lock(pt_book.ml);1106 PR_CurrentThread()->state |= PT_THREAD_GCABLE;1107 PR_Unlock(pt_book.ml);1108 }1109 1110 PR_IMPLEMENT(void) PR_ClearThreadGCAble(void)1111 {1112 PR_Lock(pt_book.ml);1113 PR_CurrentThread()->state &= (~PT_THREAD_GCABLE);1114 PR_Unlock(pt_book.ml);1115 }1116 1117 #if defined(DEBUG)1118 static PRBool suspendAllOn = PR_FALSE;1119 #endif1120 1121 static PRBool suspendAllSuspended = PR_FALSE;1122 1123 PR_IMPLEMENT(PRStatus) PR_EnumerateThreads(PREnumerator func, void *arg)1124 {1125 PRIntn count = 0;1126 PRStatus rv = PR_SUCCESS;1127 PRThread* thred = pt_book.first;1128 PRThread *me = PR_CurrentThread();1129 1130 PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_EnumerateThreads\n"));1131 /*1132 * $$$1133 * Need to suspend all threads other than me before doing this.1134 * This is really a gross and disgusting thing to do. The only1135 * good thing is that since all other threads are suspended, holding1136 * the lock during a callback seems like child's play.1137 * $$$1138 */1139 PR_ASSERT(suspendAllOn);1140 1141 while (thred != NULL)1142 {1143 /* Steve Morse, 4-23-97: Note that we can't walk a queue by taking1144 * qp->next after applying the function "func". In particular, "func"1145 * might remove the thread from the queue and put it into another one in1146 * which case qp->next no longer points to the next entry in the original1147 * queue.1148 *1149 * To get around this problem, we save qp->next in qp_next before applying1150 * "func" and use that saved value as the next value after applying "func".1151 */1152 PRThread* next = thred->next;1153 1154 if (_PT_IS_GCABLE_THREAD(thred))1155 {1156 #if !defined(_PR_DCETHREADS)1157 PR_ASSERT((thred == me) || (thred->suspend & PT_THREAD_SUSPENDED));1158 #endif1159 PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,1160 ("In PR_EnumerateThreads callback thread %X thid = %X\n",1161 thred, thred->id));1162 1163 rv = func(thred, count++, arg);1164 if (rv != PR_SUCCESS)1165 return rv;1166 }1167 thred = next;1168 }1169 PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,1170 ("End PR_EnumerateThreads count = %d \n", count));1171 return rv;1172 } /* PR_EnumerateThreads */1173 1174 /*1175 * PR_SuspendAll and PR_ResumeAll are called during garbage collection. The strategy1176 * we use is to send a SIGUSR2 signal to every gc able thread that we intend to suspend.1177 * The signal handler will record the stack pointer and will block until resumed by1178 * the resume call. Since the signal handler is the last routine called for the1179 * suspended thread, the stack pointer will also serve as a place where all the1180 * registers have been saved on the stack for the previously executing routines.1181 *1182 * Through global variables, we also make sure that PR_Suspend and PR_Resume does not1183 * proceed until the thread is suspended or resumed.1184 */1185 1186 #if !defined(_PR_DCETHREADS)1187 1188 /*1189 * In the signal handler, we can not use condition variable notify or wait.1190 * This does not work consistently across all pthread platforms. We also can not1191 * use locking since that does not seem to work reliably across platforms.1192 * Only thing we can do is yielding while testing for a global condition1193 * to change. This does work on pthread supported platforms. We may have1194 * to play with priortities if there are any problems detected.1195 */1196 1197 /*1198 * In AIX, you cannot use ANY pthread calls in the signal handler except perhaps1199 * pthread_yield. But that is horribly inefficient. Hence we use only sigwait, no1200 * sigtimedwait is available. We need to use another user signal, SIGUSR1. Actually1201 * SIGUSR1 is also used by exec in Java. So our usage here breaks the exec in Java,1202 * for AIX. You cannot use pthread_cond_wait or pthread_delay_np in the signal1203 * handler as all synchronization mechanisms just break down.1204 */1205 1206 #if defined(PT_NO_SIGTIMEDWAIT)1207 static void null_signal_handler(PRIntn sig)1208 {1209 return;1210 }1211 #endif1212 1213 static void suspend_signal_handler(PRIntn sig)1214 {1215 PRThread *me = PR_CurrentThread();1216 1217 PR_ASSERT(me != NULL);1218 PR_ASSERT(_PT_IS_GCABLE_THREAD(me));1219 PR_ASSERT((me->suspend & PT_THREAD_SUSPENDED) == 0);1220 1221 PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,1222 ("Begin suspend_signal_handler thred %X thread id = %X\n",1223 me, me->id));1224 1225 /*1226 * save stack pointer1227 */1228 me->sp = &me;1229 1230 /*1231 At this point, the thread's stack pointer has been saved,1232 And it is going to enter a wait loop until it is resumed.1233 So it is _really_ suspended1234 */1235 1236 me->suspend |= PT_THREAD_SUSPENDED;1237 1238 /*1239 * now, block current thread1240 */1241 #if defined(PT_NO_SIGTIMEDWAIT)1242 pthread_cond_signal(&me->suspendResumeCV);1243 while (me->suspend & PT_THREAD_SUSPENDED)1244 {1245 #if !defined(FREEBSD) && !defined(NETBSD) && !defined(OPENBSD) \1246 && !defined(BSDI) && !defined(VMS) && !defined(UNIXWARE) && !defined(DARWIN) /*XXX*/1247 PRIntn rv;1248 sigwait(&sigwait_set, &rv);1249 #endif1250 }1251 me->suspend |= PT_THREAD_RESUMED;1252 pthread_cond_signal(&me->suspendResumeCV);1253 #else /* defined(PT_NO_SIGTIMEDWAIT) */1254 while (me->suspend & PT_THREAD_SUSPENDED)1255 {1256 PRIntn rv = sigtimedwait(&sigwait_set, NULL, &hundredmillisec);1257 PR_ASSERT(-1 == rv);1258 }1259 me->suspend |= PT_THREAD_RESUMED;1260 #endif1261 1262 /*1263 * At this point, thread has been resumed, so set a global condition.1264 * The ResumeAll needs to know that this has really been resumed.1265 * So the signal handler sets a flag which PR_ResumeAll will reset.1266 * The PR_ResumeAll must reset this flag ...1267 */1268 1269 PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,1270 ("End suspend_signal_handler thred = %X tid = %X\n", me, me->id));1271 } /* suspend_signal_handler */1272 1273 static void pt_SuspendSet(PRThread *thred)1274 {1275 PRIntn rv;1276 1277 PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,1278 ("pt_SuspendSet thred %X thread id = %X\n", thred, thred->id));1279 1280 1281 /*1282 * Check the thread state and signal the thread to suspend1283 */1284 1285 PR_ASSERT((thred->suspend & PT_THREAD_SUSPENDED) == 0);1286 1287 PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,1288 ("doing pthread_kill in pt_SuspendSet thred %X tid = %X\n",1289 thred, thred->id));1290 #if defined(VMS)1291 rv = thread_suspend(thred);1292 #else1293 rv = pthread_kill (thred->id, SIGUSR2);1294 #endif1295 PR_ASSERT(0 == rv);1296 }1297 1298 static void pt_SuspendTest(PRThread *thred)1299 {1300 PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,1301 ("Begin pt_SuspendTest thred %X thread id = %X\n", thred, thred->id));1302 1303 1304 /*1305 * Wait for the thread to be really suspended. This happens when the1306 * suspend signal handler stores the stack pointer and sets the state1307 * to suspended.1308 */1309 1310 #if defined(PT_NO_SIGTIMEDWAIT)1311 pthread_mutex_lock(&thred->suspendResumeMutex);1312 while ((thred->suspend & PT_THREAD_SUSPENDED) == 0)1313 {1314 pthread_cond_timedwait(1315 &thred->suspendResumeCV, &thred->suspendResumeMutex, &onemillisec);1316 }1317 pthread_mutex_unlock(&thred->suspendResumeMutex);1318 #else1319 while ((thred->suspend & PT_THREAD_SUSPENDED) == 0)1320 {1321 PRIntn rv = sigtimedwait(&sigwait_set, NULL, &onemillisec);1322 PR_ASSERT(-1 == rv);1323 }1324 #endif1325 1326 PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,1327 ("End pt_SuspendTest thred %X tid %X\n", thred, thred->id));1328 } /* pt_SuspendTest */1329 1330 static void pt_ResumeSet(PRThread *thred)1331 {1332 PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,1333 ("pt_ResumeSet thred %X thread id = %X\n", thred, thred->id));1334 1335 /*1336 * Clear the global state and set the thread state so that it will1337 * continue past yield loop in the suspend signal handler1338 */1339 1340 PR_ASSERT(thred->suspend & PT_THREAD_SUSPENDED);1341 1342 1343 thred->suspend &= ~PT_THREAD_SUSPENDED;1344 1345 #if defined(PT_NO_SIGTIMEDWAIT)1346 #if defined(VMS)1347 thread_resume(thred);1348 #else1349 pthread_kill(thred->id, SIGUSR1);1350 #endif1351 #endif1352 1353 } /* pt_ResumeSet */1354 1355 static void pt_ResumeTest(PRThread *thred)1356 {1357 PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,1358 ("Begin pt_ResumeTest thred %X thread id = %X\n", thred, thred->id));1359 1360 /*1361 * Wait for the threads resume state to change1362 * to indicate it is really resumed1363 */1364 #if defined(PT_NO_SIGTIMEDWAIT)1365 pthread_mutex_lock(&thred->suspendResumeMutex);1366 while ((thred->suspend & PT_THREAD_RESUMED) == 0)1367 {1368 pthread_cond_timedwait(1369 &thred->suspendResumeCV, &thred->suspendResumeMutex, &onemillisec);1370 }1371 pthread_mutex_unlock(&thred->suspendResumeMutex);1372 #else1373 while ((thred->suspend & PT_THREAD_RESUMED) == 0) {1374 PRIntn rv = sigtimedwait(&sigwait_set, NULL, &onemillisec);1375 PR_ASSERT(-1 == rv);1376 }1377 #endif1378 1379 thred->suspend &= ~PT_THREAD_RESUMED;1380 1381 PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, (1382 "End pt_ResumeTest thred %X tid %X\n", thred, thred->id));1383 } /* pt_ResumeTest */1384 1385 static pthread_once_t pt_gc_support_control = PTHREAD_ONCE_INIT;1386 1387 PR_IMPLEMENT(void) PR_SuspendAll(void)1388 {1389 #ifdef DEBUG1390 PRIntervalTime stime, etime;1391 #endif1392 PRThread* thred = pt_book.first;1393 PRThread *me = PR_CurrentThread();1394 int rv;1395 1396 rv = pthread_once(&pt_gc_support_control, init_pthread_gc_support);1397 PR_ASSERT(0 == rv);1398 PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_SuspendAll\n"));1399 /*1400 * Stop all threads which are marked GC able.1401 */1402 PR_Lock(pt_book.ml);1403 #ifdef DEBUG1404 suspendAllOn = PR_TRUE;1405 stime = PR_IntervalNow();1406 #endif1407 while (thred != NULL)1408 {1409 if ((thred != me) && _PT_IS_GCABLE_THREAD(thred))1410 pt_SuspendSet(thred);1411 thred = thred->next;1412 }1413 1414 /* Wait till they are really suspended */1415 thred = pt_book.first;1416 while (thred != NULL)1417 {1418 if ((thred != me) && _PT_IS_GCABLE_THREAD(thred))1419 pt_SuspendTest(thred);1420 thred = thred->next;1421 }1422 1423 suspendAllSuspended = PR_TRUE;1424 1425 #ifdef DEBUG1426 etime = PR_IntervalNow();1427 PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,\1428 ("End PR_SuspendAll (time %dms)\n",1429 PR_IntervalToMilliseconds(etime - stime)));1430 #endif1431 } /* PR_SuspendAll */1432 1433 PR_IMPLEMENT(void) PR_ResumeAll(void)1434 {1435 #ifdef DEBUG1436 PRIntervalTime stime, etime;1437 #endif1438 PRThread* thred = pt_book.first;1439 PRThread *me = PR_CurrentThread();1440 PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_ResumeAll\n"));1441 /*1442 * Resume all previously suspended GC able threads.1443 */1444 suspendAllSuspended = PR_FALSE;1445 #ifdef DEBUG1446 stime = PR_IntervalNow();1447 #endif1448 1449 while (thred != NULL)1450 {1451 if ((thred != me) && _PT_IS_GCABLE_THREAD(thred))1452 pt_ResumeSet(thred);1453 thred = thred->next;1454 }1455 1456 thred = pt_book.first;1457 while (thred != NULL)1458 {1459 if ((thred != me) && _PT_IS_GCABLE_THREAD(thred))1460 pt_ResumeTest(thred);1461 thred = thred->next;1462 }1463 1464 PR_Unlock(pt_book.ml);1465 #ifdef DEBUG1466 suspendAllOn = PR_FALSE;1467 etime = PR_IntervalNow();1468 PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,1469 ("End PR_ResumeAll (time %dms)\n",1470 PR_IntervalToMilliseconds(etime - stime)));1471 #endif1472 } /* PR_ResumeAll */1473 1474 /* Return the stack pointer for the given thread- used by the GC */1475 PR_IMPLEMENT(void *)PR_GetSP(PRThread *thred)1476 {1477 PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,1478 ("in PR_GetSP thred %X thid = %X, sp = %X \n",1479 thred, thred->id, thred->sp));1480 return thred->sp;1481 } /* PR_GetSP */1482 1483 #else /* !defined(_PR_DCETHREADS) */1484 1485 static pthread_once_t pt_gc_support_control = pthread_once_init;1486 1487 /*1488 * For DCE threads, there is no pthread_kill or a way of suspending or resuming a1489 * particular thread. We will just disable the preemption (virtual timer alarm) and1490 * let the executing thread finish the garbage collection. This stops all other threads1491 * (GC able or not) and is very inefficient but there is no other choice.1492 */1493 PR_IMPLEMENT(void) PR_SuspendAll()1494 {1495 PRIntn rv;1496 1497 rv = pthread_once(&pt_gc_support_control, init_pthread_gc_support);1498 PR_ASSERT(0 == rv); /* returns -1 on failure */1499 #ifdef DEBUG1500 suspendAllOn = PR_TRUE;1501 #endif1502 PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_SuspendAll\n"));1503 /*1504 * turn off preemption - i.e add virtual alarm signal to the set of1505 * blocking signals1506 */1507 rv = sigprocmask(1508 SIG_BLOCK, &javagc_vtalarm_sigmask, &javagc_intsoff_sigmask);1509 PR_ASSERT(0 == rv);1510 suspendAllSuspended = PR_TRUE;1511 PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("End PR_SuspendAll\n"));1512 } /* PR_SuspendAll */1513 1514 PR_IMPLEMENT(void) PR_ResumeAll()1515 {1516 PRIntn rv;1517 1518 suspendAllSuspended = PR_FALSE;1519 PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_ResumeAll\n"));1520 /* turn on preemption - i.e re-enable virtual alarm signal */1521 1522 rv = sigprocmask(SIG_SETMASK, &javagc_intsoff_sigmask, (sigset_t *)NULL);1523 PR_ASSERT(0 == rv);1524 #ifdef DEBUG1525 suspendAllOn = PR_FALSE;1526 #endif1527 1528 PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("End PR_ResumeAll\n"));1529 } /* PR_ResumeAll */1530 1531 /* Return the stack pointer for the given thread- used by the GC */1532 PR_IMPLEMENT(void*)PR_GetSP(PRThread *thred)1533 {1534 pthread_t tid = thred->id;1535 char *thread_tcb, *top_sp;1536 1537 /*1538 * For HPUX DCE threads, pthread_t is a struct with the1539 * following three fields (see pthread.h, dce/cma.h):1540 * cma_t_address field1;1541 * short int field2;1542 * short int field3;1543 * where cma_t_address is typedef'd to be either void*1544 * or char*.1545 */1546 PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_GetSP\n"));1547 thread_tcb = (char*)tid.field1;1548 top_sp = *(char**)(thread_tcb + 128);1549 PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("End PR_GetSP %X \n", top_sp));1550 return top_sp;1551 } /* PR_GetSP */1552 1553 #endif /* !defined(_PR_DCETHREADS) */1554 1555 756 /* ptthread.c */
Note:
See TracChangeset
for help on using the changeset viewer.