1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/nsprpub/pr/src/threads/prcthr.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,395 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 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 "primpl.h" 1.10 + 1.11 +#if defined(WIN95) 1.12 +/* 1.13 +** Some local variables report warnings on Win95 because the code paths 1.14 +** using them are conditioned on HAVE_CUSTOME_USER_THREADS. 1.15 +** The pragma suppresses the warning. 1.16 +** 1.17 +*/ 1.18 +#pragma warning(disable : 4101) 1.19 +#endif 1.20 + 1.21 + 1.22 +extern PRLock *_pr_sleeplock; /* allocated and initialized in prinit */ 1.23 +/* 1.24 +** Routines common to both native and user threads. 1.25 +** 1.26 +** 1.27 +** Clean up a thread object, releasing all of the attached data. Do not 1.28 +** free the object itself (it may not have been malloc'd) 1.29 +*/ 1.30 +void _PR_CleanupThread(PRThread *thread) 1.31 +{ 1.32 + /* Free up per-thread-data */ 1.33 + _PR_DestroyThreadPrivate(thread); 1.34 + 1.35 + /* Free any thread dump procs */ 1.36 + if (thread->dumpArg) { 1.37 + PR_DELETE(thread->dumpArg); 1.38 + } 1.39 + thread->dump = 0; 1.40 + 1.41 + PR_DELETE(thread->name); 1.42 + PR_DELETE(thread->errorString); 1.43 + thread->errorStringSize = 0; 1.44 + thread->errorStringLength = 0; 1.45 + thread->environment = NULL; 1.46 +} 1.47 + 1.48 +PR_IMPLEMENT(PRStatus) PR_Yield() 1.49 +{ 1.50 + static PRBool warning = PR_TRUE; 1.51 + if (warning) warning = _PR_Obsolete( 1.52 + "PR_Yield()", "PR_Sleep(PR_INTERVAL_NO_WAIT)"); 1.53 + return (PR_Sleep(PR_INTERVAL_NO_WAIT)); 1.54 +} 1.55 + 1.56 +/* 1.57 +** Make the current thread sleep until "timeout" ticks amount of time 1.58 +** has expired. If "timeout" is PR_INTERVAL_NO_WAIT then the call is 1.59 +** equivalent to a yield. Waiting for an infinite amount of time is 1.60 +** allowed in the expectation that another thread will interrupt(). 1.61 +** 1.62 +** A single lock is used for all threads calling sleep. Each caller 1.63 +** does get its own condition variable since each is expected to have 1.64 +** a unique 'timeout'. 1.65 +*/ 1.66 +PR_IMPLEMENT(PRStatus) PR_Sleep(PRIntervalTime timeout) 1.67 +{ 1.68 + PRStatus rv = PR_SUCCESS; 1.69 + 1.70 + if (!_pr_initialized) _PR_ImplicitInitialization(); 1.71 + 1.72 + if (PR_INTERVAL_NO_WAIT == timeout) 1.73 + { 1.74 + /* 1.75 + ** This is a simple yield, nothing more, nothing less. 1.76 + */ 1.77 + PRIntn is; 1.78 + PRThread *me = PR_GetCurrentThread(); 1.79 + PRUintn pri = me->priority; 1.80 + _PRCPU *cpu = _PR_MD_CURRENT_CPU(); 1.81 + 1.82 + if ( _PR_IS_NATIVE_THREAD(me) ) _PR_MD_YIELD(); 1.83 + else 1.84 + { 1.85 + _PR_INTSOFF(is); 1.86 + _PR_RUNQ_LOCK(cpu); 1.87 + if (_PR_RUNQREADYMASK(cpu) >> pri) { 1.88 + me->cpu = cpu; 1.89 + me->state = _PR_RUNNABLE; 1.90 + _PR_ADD_RUNQ(me, cpu, pri); 1.91 + _PR_RUNQ_UNLOCK(cpu); 1.92 + 1.93 + PR_LOG(_pr_sched_lm, PR_LOG_MIN, ("PR_Yield: yielding")); 1.94 + _PR_MD_SWITCH_CONTEXT(me); 1.95 + PR_LOG(_pr_sched_lm, PR_LOG_MIN, ("PR_Yield: done")); 1.96 + 1.97 + _PR_FAST_INTSON(is); 1.98 + } 1.99 + else 1.100 + { 1.101 + _PR_RUNQ_UNLOCK(cpu); 1.102 + _PR_INTSON(is); 1.103 + } 1.104 + } 1.105 + } 1.106 + else 1.107 + { 1.108 + /* 1.109 + ** This is waiting for some finite period of time. 1.110 + ** A thread in this state is interruptible (PR_Interrupt()), 1.111 + ** but the lock and cvar used are local to the implementation 1.112 + ** and not visible to the caller, therefore not notifiable. 1.113 + */ 1.114 + PRCondVar *cv; 1.115 + PRIntervalTime timein; 1.116 + 1.117 + timein = PR_IntervalNow(); 1.118 + cv = PR_NewCondVar(_pr_sleeplock); 1.119 + PR_ASSERT(cv != NULL); 1.120 + PR_Lock(_pr_sleeplock); 1.121 + do 1.122 + { 1.123 + PRIntervalTime delta = PR_IntervalNow() - timein; 1.124 + if (delta > timeout) break; 1.125 + rv = PR_WaitCondVar(cv, timeout - delta); 1.126 + } while (rv == PR_SUCCESS); 1.127 + PR_Unlock(_pr_sleeplock); 1.128 + PR_DestroyCondVar(cv); 1.129 + } 1.130 + return rv; 1.131 +} 1.132 + 1.133 +PR_IMPLEMENT(PRUint32) PR_GetThreadID(PRThread *thread) 1.134 +{ 1.135 + return thread->id; 1.136 +} 1.137 + 1.138 +PR_IMPLEMENT(PRThreadPriority) PR_GetThreadPriority(const PRThread *thread) 1.139 +{ 1.140 + return (PRThreadPriority) thread->priority; 1.141 +} 1.142 + 1.143 +PR_IMPLEMENT(PRThread *) PR_GetCurrentThread() 1.144 +{ 1.145 + if (!_pr_initialized) _PR_ImplicitInitialization(); 1.146 + return _PR_MD_CURRENT_THREAD(); 1.147 +} 1.148 + 1.149 +/* 1.150 +** Set the interrupt flag for a thread. The thread will be unable to 1.151 +** block in i/o functions when this happens. Also, any PR_Wait's in 1.152 +** progress will be undone. The interrupt remains in force until 1.153 +** PR_ClearInterrupt is called. 1.154 +*/ 1.155 +PR_IMPLEMENT(PRStatus) PR_Interrupt(PRThread *thread) 1.156 +{ 1.157 +#ifdef _PR_GLOBAL_THREADS_ONLY 1.158 + PRCondVar *victim; 1.159 + 1.160 + _PR_THREAD_LOCK(thread); 1.161 + thread->flags |= _PR_INTERRUPT; 1.162 + victim = thread->wait.cvar; 1.163 + _PR_THREAD_UNLOCK(thread); 1.164 + if ((NULL != victim) && (!(thread->flags & _PR_INTERRUPT_BLOCKED))) { 1.165 + int haveLock = (victim->lock->owner == _PR_MD_CURRENT_THREAD()); 1.166 + 1.167 + if (!haveLock) PR_Lock(victim->lock); 1.168 + PR_NotifyAllCondVar(victim); 1.169 + if (!haveLock) PR_Unlock(victim->lock); 1.170 + } 1.171 + return PR_SUCCESS; 1.172 +#else /* ! _PR_GLOBAL_THREADS_ONLY */ 1.173 + PRIntn is; 1.174 + PRThread *me = _PR_MD_CURRENT_THREAD(); 1.175 + 1.176 + if (!_PR_IS_NATIVE_THREAD(me)) 1.177 + _PR_INTSOFF(is); 1.178 + 1.179 + _PR_THREAD_LOCK(thread); 1.180 + thread->flags |= _PR_INTERRUPT; 1.181 + switch (thread->state) { 1.182 + case _PR_COND_WAIT: 1.183 + /* 1.184 + * call is made with thread locked; 1.185 + * on return lock is released 1.186 + */ 1.187 + if (!(thread->flags & _PR_INTERRUPT_BLOCKED)) 1.188 + _PR_NotifyLockedThread(thread); 1.189 + break; 1.190 + case _PR_IO_WAIT: 1.191 + /* 1.192 + * Need to hold the thread lock when calling 1.193 + * _PR_Unblock_IO_Wait(). On return lock is 1.194 + * released. 1.195 + */ 1.196 +#if defined(XP_UNIX) || defined(WINNT) || defined(WIN16) 1.197 + if (!(thread->flags & _PR_INTERRUPT_BLOCKED)) 1.198 + _PR_Unblock_IO_Wait(thread); 1.199 +#else 1.200 + _PR_THREAD_UNLOCK(thread); 1.201 +#endif 1.202 + break; 1.203 + case _PR_RUNNING: 1.204 + case _PR_RUNNABLE: 1.205 + case _PR_LOCK_WAIT: 1.206 + default: 1.207 + _PR_THREAD_UNLOCK(thread); 1.208 + break; 1.209 + } 1.210 + if (!_PR_IS_NATIVE_THREAD(me)) 1.211 + _PR_INTSON(is); 1.212 + return PR_SUCCESS; 1.213 +#endif /* _PR_GLOBAL_THREADS_ONLY */ 1.214 +} 1.215 + 1.216 +/* 1.217 +** Clear the interrupt flag for self. 1.218 +*/ 1.219 +PR_IMPLEMENT(void) PR_ClearInterrupt() 1.220 +{ 1.221 + PRIntn is; 1.222 + PRThread *me = _PR_MD_CURRENT_THREAD(); 1.223 + 1.224 + if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(is); 1.225 + _PR_THREAD_LOCK(me); 1.226 + me->flags &= ~_PR_INTERRUPT; 1.227 + _PR_THREAD_UNLOCK(me); 1.228 + if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSON(is); 1.229 +} 1.230 + 1.231 +PR_IMPLEMENT(void) PR_BlockInterrupt() 1.232 +{ 1.233 + PRIntn is; 1.234 + PRThread *me = _PR_MD_CURRENT_THREAD(); 1.235 + 1.236 + if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(is); 1.237 + _PR_THREAD_LOCK(me); 1.238 + _PR_THREAD_BLOCK_INTERRUPT(me); 1.239 + _PR_THREAD_UNLOCK(me); 1.240 + if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSON(is); 1.241 +} /* PR_BlockInterrupt */ 1.242 + 1.243 +PR_IMPLEMENT(void) PR_UnblockInterrupt() 1.244 +{ 1.245 + PRIntn is; 1.246 + PRThread *me = _PR_MD_CURRENT_THREAD(); 1.247 + 1.248 + if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(is); 1.249 + _PR_THREAD_LOCK(me); 1.250 + _PR_THREAD_UNBLOCK_INTERRUPT(me); 1.251 + _PR_THREAD_UNLOCK(me); 1.252 + if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSON(is); 1.253 +} /* PR_UnblockInterrupt */ 1.254 + 1.255 +/* 1.256 +** Return the thread stack pointer of the given thread. 1.257 +*/ 1.258 +PR_IMPLEMENT(void *) PR_GetSP(PRThread *thread) 1.259 +{ 1.260 + return (void *)_PR_MD_GET_SP(thread); 1.261 +} 1.262 + 1.263 +PR_IMPLEMENT(void*) GetExecutionEnvironment(PRThread *thread) 1.264 +{ 1.265 + return thread->environment; 1.266 +} 1.267 + 1.268 +PR_IMPLEMENT(void) SetExecutionEnvironment(PRThread *thread, void *env) 1.269 +{ 1.270 + thread->environment = env; 1.271 +} 1.272 + 1.273 + 1.274 +PR_IMPLEMENT(PRInt32) PR_GetThreadAffinityMask(PRThread *thread, PRUint32 *mask) 1.275 +{ 1.276 +#ifdef HAVE_THREAD_AFFINITY 1.277 + return _PR_MD_GETTHREADAFFINITYMASK(thread, mask); 1.278 +#else 1.279 + return 0; 1.280 +#endif 1.281 +} 1.282 + 1.283 +PR_IMPLEMENT(PRInt32) PR_SetThreadAffinityMask(PRThread *thread, PRUint32 mask ) 1.284 +{ 1.285 +#ifdef HAVE_THREAD_AFFINITY 1.286 +#ifndef IRIX 1.287 + return _PR_MD_SETTHREADAFFINITYMASK(thread, mask); 1.288 +#else 1.289 + return 0; 1.290 +#endif 1.291 +#else 1.292 + return 0; 1.293 +#endif 1.294 +} 1.295 + 1.296 +/* This call is thread unsafe if another thread is calling SetConcurrency() 1.297 + */ 1.298 +PR_IMPLEMENT(PRInt32) PR_SetCPUAffinityMask(PRUint32 mask) 1.299 +{ 1.300 +#ifdef HAVE_THREAD_AFFINITY 1.301 + PRCList *qp; 1.302 + extern PRUint32 _pr_cpu_affinity_mask; 1.303 + 1.304 + if (!_pr_initialized) _PR_ImplicitInitialization(); 1.305 + 1.306 + _pr_cpu_affinity_mask = mask; 1.307 + 1.308 + qp = _PR_CPUQ().next; 1.309 + while(qp != &_PR_CPUQ()) { 1.310 + _PRCPU *cpu; 1.311 + 1.312 + cpu = _PR_CPU_PTR(qp); 1.313 + PR_SetThreadAffinityMask(cpu->thread, mask); 1.314 + 1.315 + qp = qp->next; 1.316 + } 1.317 +#endif 1.318 + 1.319 + return 0; 1.320 +} 1.321 + 1.322 +PRUint32 _pr_recycleThreads = 0; 1.323 +PR_IMPLEMENT(void) PR_SetThreadRecycleMode(PRUint32 count) 1.324 +{ 1.325 + _pr_recycleThreads = count; 1.326 +} 1.327 + 1.328 +PR_IMPLEMENT(PRThread*) PR_CreateThreadGCAble(PRThreadType type, 1.329 + void (*start)(void *arg), 1.330 + void *arg, 1.331 + PRThreadPriority priority, 1.332 + PRThreadScope scope, 1.333 + PRThreadState state, 1.334 + PRUint32 stackSize) 1.335 +{ 1.336 + return _PR_CreateThread(type, start, arg, priority, scope, state, 1.337 + stackSize, _PR_GCABLE_THREAD); 1.338 +} 1.339 + 1.340 +#ifdef SOLARIS 1.341 +PR_IMPLEMENT(PRThread*) PR_CreateThreadBound(PRThreadType type, 1.342 + void (*start)(void *arg), 1.343 + void *arg, 1.344 + PRUintn priority, 1.345 + PRThreadScope scope, 1.346 + PRThreadState state, 1.347 + PRUint32 stackSize) 1.348 +{ 1.349 + return _PR_CreateThread(type, start, arg, priority, scope, state, 1.350 + stackSize, _PR_BOUND_THREAD); 1.351 +} 1.352 +#endif 1.353 + 1.354 + 1.355 +PR_IMPLEMENT(PRThread*) PR_AttachThreadGCAble( 1.356 + PRThreadType type, PRThreadPriority priority, PRThreadStack *stack) 1.357 +{ 1.358 + /* $$$$ not sure how to finese this one */ 1.359 + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); 1.360 + return NULL; 1.361 +} 1.362 + 1.363 +PR_IMPLEMENT(void) PR_SetThreadGCAble() 1.364 +{ 1.365 + if (!_pr_initialized) _PR_ImplicitInitialization(); 1.366 + PR_Lock(_pr_activeLock); 1.367 + _PR_MD_CURRENT_THREAD()->flags |= _PR_GCABLE_THREAD; 1.368 + PR_Unlock(_pr_activeLock); 1.369 +} 1.370 + 1.371 +PR_IMPLEMENT(void) PR_ClearThreadGCAble() 1.372 +{ 1.373 + if (!_pr_initialized) _PR_ImplicitInitialization(); 1.374 + PR_Lock(_pr_activeLock); 1.375 + _PR_MD_CURRENT_THREAD()->flags &= (~_PR_GCABLE_THREAD); 1.376 + PR_Unlock(_pr_activeLock); 1.377 +} 1.378 + 1.379 +PR_IMPLEMENT(PRThreadScope) PR_GetThreadScope(const PRThread *thread) 1.380 +{ 1.381 + if (!_pr_initialized) _PR_ImplicitInitialization(); 1.382 + 1.383 + if (_PR_IS_NATIVE_THREAD(thread)) { 1.384 + return (thread->flags & _PR_BOUND_THREAD) ? PR_GLOBAL_BOUND_THREAD : 1.385 + PR_GLOBAL_THREAD; 1.386 + } else 1.387 + return PR_LOCAL_THREAD; 1.388 +} 1.389 + 1.390 +PR_IMPLEMENT(PRThreadType) PR_GetThreadType(const PRThread *thread) 1.391 +{ 1.392 + return (thread->flags & _PR_SYSTEM) ? PR_SYSTEM_THREAD : PR_USER_THREAD; 1.393 +} 1.394 + 1.395 +PR_IMPLEMENT(PRThreadState) PR_GetThreadState(const PRThread *thread) 1.396 +{ 1.397 + return (NULL == thread->term) ? PR_UNJOINABLE_THREAD : PR_JOINABLE_THREAD; 1.398 +} /* PR_GetThreadState */