nsprpub/pr/src/threads/prcthr.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial