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