prcthr.c (10257B)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #include "primpl.h" 7 8 #if defined(WIN95) 9 /* 10 ** Some local variables report warnings on Win95 because the code paths 11 ** using them are conditioned on HAVE_CUSTOME_USER_THREADS. 12 ** The pragma suppresses the warning. 13 ** 14 */ 15 # pragma warning(disable : 4101) 16 #endif 17 18 extern PRLock* _pr_sleeplock; /* allocated and initialized in prinit */ 19 /* 20 ** Routines common to both native and user threads. 21 ** 22 ** 23 ** Clean up a thread object, releasing all of the attached data. Do not 24 ** free the object itself (it may not have been malloc'd) 25 */ 26 void _PR_CleanupThread(PRThread* thread) { 27 /* Free up per-thread-data */ 28 _PR_DestroyThreadPrivate(thread); 29 30 /* Free any thread dump procs */ 31 if (thread->dumpArg) { 32 PR_DELETE(thread->dumpArg); 33 } 34 thread->dump = 0; 35 36 PR_DELETE(thread->name); 37 PR_DELETE(thread->errorString); 38 thread->errorStringSize = 0; 39 thread->errorStringLength = 0; 40 thread->environment = NULL; 41 } 42 43 PR_IMPLEMENT(PRStatus) PR_Yield() { 44 static PRBool warning = PR_TRUE; 45 if (warning) 46 warning = _PR_Obsolete("PR_Yield()", "PR_Sleep(PR_INTERVAL_NO_WAIT)"); 47 return (PR_Sleep(PR_INTERVAL_NO_WAIT)); 48 } 49 50 /* 51 ** Make the current thread sleep until "timeout" ticks amount of time 52 ** has expired. If "timeout" is PR_INTERVAL_NO_WAIT then the call is 53 ** equivalent to a yield. Waiting for an infinite amount of time is 54 ** allowed in the expectation that another thread will interrupt(). 55 ** 56 ** A single lock is used for all threads calling sleep. Each caller 57 ** does get its own condition variable since each is expected to have 58 ** a unique 'timeout'. 59 */ 60 PR_IMPLEMENT(PRStatus) PR_Sleep(PRIntervalTime timeout) { 61 PRStatus rv = PR_SUCCESS; 62 63 if (!_pr_initialized) { 64 _PR_ImplicitInitialization(); 65 } 66 67 if (PR_INTERVAL_NO_WAIT == timeout) { 68 /* 69 ** This is a simple yield, nothing more, nothing less. 70 */ 71 PRIntn is; 72 PRThread* me = PR_GetCurrentThread(); 73 PRUintn pri = me->priority; 74 _PRCPU* cpu = _PR_MD_CURRENT_CPU(); 75 76 if (_PR_IS_NATIVE_THREAD(me)) { 77 _PR_MD_YIELD(); 78 } else { 79 _PR_INTSOFF(is); 80 _PR_RUNQ_LOCK(cpu); 81 if (_PR_RUNQREADYMASK(cpu) >> pri) { 82 me->cpu = cpu; 83 me->state = _PR_RUNNABLE; 84 _PR_ADD_RUNQ(me, cpu, pri); 85 _PR_RUNQ_UNLOCK(cpu); 86 87 PR_LOG(_pr_sched_lm, PR_LOG_MIN, ("PR_Yield: yielding")); 88 _PR_MD_SWITCH_CONTEXT(me); 89 PR_LOG(_pr_sched_lm, PR_LOG_MIN, ("PR_Yield: done")); 90 91 _PR_FAST_INTSON(is); 92 } else { 93 _PR_RUNQ_UNLOCK(cpu); 94 _PR_INTSON(is); 95 } 96 } 97 } else { 98 /* 99 ** This is waiting for some finite period of time. 100 ** A thread in this state is interruptible (PR_Interrupt()), 101 ** but the lock and cvar used are local to the implementation 102 ** and not visible to the caller, therefore not notifiable. 103 */ 104 PRCondVar* cv; 105 PRIntervalTime timein; 106 107 timein = PR_IntervalNow(); 108 cv = PR_NewCondVar(_pr_sleeplock); 109 PR_ASSERT(cv != NULL); 110 PR_Lock(_pr_sleeplock); 111 do { 112 PRIntervalTime delta = PR_IntervalNow() - timein; 113 if (delta > timeout) { 114 break; 115 } 116 rv = PR_WaitCondVar(cv, timeout - delta); 117 } while (rv == PR_SUCCESS); 118 PR_Unlock(_pr_sleeplock); 119 PR_DestroyCondVar(cv); 120 } 121 return rv; 122 } 123 124 PR_IMPLEMENT(PRUint32) PR_GetThreadID(PRThread* thread) { return thread->id; } 125 126 PR_IMPLEMENT(PRThreadPriority) PR_GetThreadPriority(const PRThread* thread) { 127 return (PRThreadPriority)thread->priority; 128 } 129 130 PR_IMPLEMENT(PRThread*) PR_GetCurrentThread() { 131 if (!_pr_initialized) { 132 _PR_ImplicitInitialization(); 133 } 134 return _PR_MD_CURRENT_THREAD(); 135 } 136 137 /* 138 ** Set the interrupt flag for a thread. The thread will be unable to 139 ** block in i/o functions when this happens. Also, any PR_Wait's in 140 ** progress will be undone. The interrupt remains in force until 141 ** PR_ClearInterrupt is called. 142 */ 143 PR_IMPLEMENT(PRStatus) PR_Interrupt(PRThread* thread) { 144 #ifdef _PR_GLOBAL_THREADS_ONLY 145 PRCondVar* victim; 146 147 _PR_THREAD_LOCK(thread); 148 thread->flags |= _PR_INTERRUPT; 149 victim = thread->wait.cvar; 150 _PR_THREAD_UNLOCK(thread); 151 if ((NULL != victim) && (!(thread->flags & _PR_INTERRUPT_BLOCKED))) { 152 int haveLock = (victim->lock->owner == _PR_MD_CURRENT_THREAD()); 153 154 if (!haveLock) { 155 PR_Lock(victim->lock); 156 } 157 PR_NotifyAllCondVar(victim); 158 if (!haveLock) { 159 PR_Unlock(victim->lock); 160 } 161 } 162 return PR_SUCCESS; 163 #else /* ! _PR_GLOBAL_THREADS_ONLY */ 164 PRIntn is; 165 PRThread* me = _PR_MD_CURRENT_THREAD(); 166 167 if (!_PR_IS_NATIVE_THREAD(me)) { 168 _PR_INTSOFF(is); 169 } 170 171 _PR_THREAD_LOCK(thread); 172 thread->flags |= _PR_INTERRUPT; 173 switch (thread->state) { 174 case _PR_COND_WAIT: 175 /* 176 * call is made with thread locked; 177 * on return lock is released 178 */ 179 if (!(thread->flags & _PR_INTERRUPT_BLOCKED)) { 180 _PR_NotifyLockedThread(thread); 181 } 182 break; 183 case _PR_IO_WAIT: 184 /* 185 * Need to hold the thread lock when calling 186 * _PR_Unblock_IO_Wait(). On return lock is 187 * released. 188 */ 189 # if defined(XP_UNIX) || defined(WINNT) 190 if (!(thread->flags & _PR_INTERRUPT_BLOCKED)) { 191 _PR_Unblock_IO_Wait(thread); 192 } 193 # else 194 _PR_THREAD_UNLOCK(thread); 195 # endif 196 break; 197 case _PR_RUNNING: 198 case _PR_RUNNABLE: 199 case _PR_LOCK_WAIT: 200 default: 201 _PR_THREAD_UNLOCK(thread); 202 break; 203 } 204 if (!_PR_IS_NATIVE_THREAD(me)) { 205 _PR_INTSON(is); 206 } 207 return PR_SUCCESS; 208 #endif /* _PR_GLOBAL_THREADS_ONLY */ 209 } 210 211 /* 212 ** Clear the interrupt flag for self. 213 */ 214 PR_IMPLEMENT(void) PR_ClearInterrupt() { 215 PRIntn is; 216 PRThread* me = _PR_MD_CURRENT_THREAD(); 217 218 if (!_PR_IS_NATIVE_THREAD(me)) { 219 _PR_INTSOFF(is); 220 } 221 _PR_THREAD_LOCK(me); 222 me->flags &= ~_PR_INTERRUPT; 223 _PR_THREAD_UNLOCK(me); 224 if (!_PR_IS_NATIVE_THREAD(me)) { 225 _PR_INTSON(is); 226 } 227 } 228 229 PR_IMPLEMENT(void) PR_BlockInterrupt() { 230 PRIntn is; 231 PRThread* me = _PR_MD_CURRENT_THREAD(); 232 233 if (!_PR_IS_NATIVE_THREAD(me)) { 234 _PR_INTSOFF(is); 235 } 236 _PR_THREAD_LOCK(me); 237 _PR_THREAD_BLOCK_INTERRUPT(me); 238 _PR_THREAD_UNLOCK(me); 239 if (!_PR_IS_NATIVE_THREAD(me)) { 240 _PR_INTSON(is); 241 } 242 } /* PR_BlockInterrupt */ 243 244 PR_IMPLEMENT(void) PR_UnblockInterrupt() { 245 PRIntn is; 246 PRThread* me = _PR_MD_CURRENT_THREAD(); 247 248 if (!_PR_IS_NATIVE_THREAD(me)) { 249 _PR_INTSOFF(is); 250 } 251 _PR_THREAD_LOCK(me); 252 _PR_THREAD_UNBLOCK_INTERRUPT(me); 253 _PR_THREAD_UNLOCK(me); 254 if (!_PR_IS_NATIVE_THREAD(me)) { 255 _PR_INTSON(is); 256 } 257 } /* PR_UnblockInterrupt */ 258 259 /* 260 ** Return the thread stack pointer of the given thread. 261 */ 262 PR_IMPLEMENT(void*) PR_GetSP(PRThread* thread) { 263 return (void*)_PR_MD_GET_SP(thread); 264 } 265 266 PR_IMPLEMENT(void*) GetExecutionEnvironment(PRThread* thread) { 267 return thread->environment; 268 } 269 270 PR_IMPLEMENT(void) SetExecutionEnvironment(PRThread* thread, void* env) { 271 thread->environment = env; 272 } 273 274 PR_IMPLEMENT(PRInt32) 275 PR_GetThreadAffinityMask(PRThread* thread, PRUint32* mask) { 276 #ifdef HAVE_THREAD_AFFINITY 277 return _PR_MD_GETTHREADAFFINITYMASK(thread, mask); 278 #else 279 return 0; 280 #endif 281 } 282 283 PR_IMPLEMENT(PRInt32) 284 PR_SetThreadAffinityMask(PRThread* thread, PRUint32 mask) { 285 #ifdef HAVE_THREAD_AFFINITY 286 return _PR_MD_SETTHREADAFFINITYMASK(thread, mask); 287 #else 288 return 0; 289 #endif 290 } 291 292 /* This call is thread unsafe if another thread is calling SetConcurrency() 293 */ 294 PR_IMPLEMENT(PRInt32) PR_SetCPUAffinityMask(PRUint32 mask) { 295 #ifdef HAVE_THREAD_AFFINITY 296 PRCList* qp; 297 extern PRUint32 _pr_cpu_affinity_mask; 298 299 if (!_pr_initialized) { 300 _PR_ImplicitInitialization(); 301 } 302 303 _pr_cpu_affinity_mask = mask; 304 305 qp = _PR_CPUQ().next; 306 while (qp != &_PR_CPUQ()) { 307 _PRCPU* cpu; 308 309 cpu = _PR_CPU_PTR(qp); 310 PR_SetThreadAffinityMask(cpu->thread, mask); 311 312 qp = qp->next; 313 } 314 #endif 315 316 return 0; 317 } 318 319 PRUint32 _pr_recycleThreads = 0; 320 PR_IMPLEMENT(void) PR_SetThreadRecycleMode(PRUint32 count) { 321 _pr_recycleThreads = count; 322 } 323 324 PR_IMPLEMENT(PRThread*) 325 PR_CreateThreadGCAble(PRThreadType type, void (*start)(void* arg), void* arg, 326 PRThreadPriority priority, PRThreadScope scope, 327 PRThreadState state, PRUint32 stackSize) { 328 return _PR_CreateThread(type, start, arg, priority, scope, state, stackSize, 329 _PR_GCABLE_THREAD); 330 } 331 332 #ifdef SOLARIS 333 PR_IMPLEMENT(PRThread*) 334 PR_CreateThreadBound(PRThreadType type, void (*start)(void* arg), void* arg, 335 PRUintn priority, PRThreadScope scope, PRThreadState state, 336 PRUint32 stackSize) { 337 return _PR_CreateThread(type, start, arg, priority, scope, state, stackSize, 338 _PR_BOUND_THREAD); 339 } 340 #endif 341 342 PR_IMPLEMENT(PRThread*) 343 PR_AttachThreadGCAble(PRThreadType type, PRThreadPriority priority, 344 PRThreadStack* stack) { 345 /* $$$$ not sure how to finese this one */ 346 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); 347 return NULL; 348 } 349 350 PR_IMPLEMENT(void) PR_SetThreadGCAble() { 351 if (!_pr_initialized) { 352 _PR_ImplicitInitialization(); 353 } 354 PR_Lock(_pr_activeLock); 355 _PR_MD_CURRENT_THREAD()->flags |= _PR_GCABLE_THREAD; 356 PR_Unlock(_pr_activeLock); 357 } 358 359 PR_IMPLEMENT(void) PR_ClearThreadGCAble() { 360 if (!_pr_initialized) { 361 _PR_ImplicitInitialization(); 362 } 363 PR_Lock(_pr_activeLock); 364 _PR_MD_CURRENT_THREAD()->flags &= (~_PR_GCABLE_THREAD); 365 PR_Unlock(_pr_activeLock); 366 } 367 368 PR_IMPLEMENT(PRThreadScope) PR_GetThreadScope(const PRThread* thread) { 369 if (!_pr_initialized) { 370 _PR_ImplicitInitialization(); 371 } 372 373 if (_PR_IS_NATIVE_THREAD(thread)) { 374 return (thread->flags & _PR_BOUND_THREAD) ? PR_GLOBAL_BOUND_THREAD 375 : PR_GLOBAL_THREAD; 376 } else { 377 return PR_LOCAL_THREAD; 378 } 379 } 380 381 PR_IMPLEMENT(PRThreadType) PR_GetThreadType(const PRThread* thread) { 382 return (thread->flags & _PR_SYSTEM) ? PR_SYSTEM_THREAD : PR_USER_THREAD; 383 } 384 385 PR_IMPLEMENT(PRThreadState) PR_GetThreadState(const PRThread* thread) { 386 return (NULL == thread->term) ? PR_UNJOINABLE_THREAD : PR_JOINABLE_THREAD; 387 } /* PR_GetThreadState */