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.

     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/. */
     6 #include "primpl.h"
     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
    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);
    32     /* Free any thread dump procs */
    33     if (thread->dumpArg) {
    34         PR_DELETE(thread->dumpArg);
    35     }
    36     thread->dump = 0;
    38     PR_DELETE(thread->name);
    39     PR_DELETE(thread->errorString);
    40     thread->errorStringSize = 0;
    41     thread->errorStringLength = 0;
    42     thread->environment = NULL;
    43 }
    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 }
    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;
    67     if (!_pr_initialized) _PR_ImplicitInitialization();
    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();
    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);
    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"));
    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;
   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 }
   130 PR_IMPLEMENT(PRUint32) PR_GetThreadID(PRThread *thread)
   131 {
   132     return thread->id;
   133 }
   135 PR_IMPLEMENT(PRThreadPriority) PR_GetThreadPriority(const PRThread *thread)
   136 {
   137     return (PRThreadPriority) thread->priority;
   138 }
   140 PR_IMPLEMENT(PRThread *) PR_GetCurrentThread()
   141 {
   142     if (!_pr_initialized) _PR_ImplicitInitialization();
   143     return _PR_MD_CURRENT_THREAD();
   144 }
   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;
   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());
   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();
   173             if (!_PR_IS_NATIVE_THREAD(me))
   174             	_PR_INTSOFF(is);
   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_INTERRUPT_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_INTERRUPT_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 }
   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();
   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 }
   228 PR_IMPLEMENT(void) PR_BlockInterrupt()
   229 {
   230     PRIntn is;
   231     PRThread *me = _PR_MD_CURRENT_THREAD();
   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 */
   240 PR_IMPLEMENT(void) PR_UnblockInterrupt()
   241 {
   242     PRIntn is;
   243     PRThread *me = _PR_MD_CURRENT_THREAD();
   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 */
   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 }
   260 PR_IMPLEMENT(void*) GetExecutionEnvironment(PRThread *thread)
   261 {
   262         return thread->environment;
   263 }
   265 PR_IMPLEMENT(void) SetExecutionEnvironment(PRThread *thread, void *env)
   266 {
   267         thread->environment = env;
   268 }
   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 }
   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 }
   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;
   301     if (!_pr_initialized) _PR_ImplicitInitialization();
   303     _pr_cpu_affinity_mask = mask;
   305     qp = _PR_CPUQ().next;
   306     while(qp != &_PR_CPUQ()) {
   307         _PRCPU *cpu;
   309         cpu = _PR_CPU_PTR(qp);
   310         PR_SetThreadAffinityMask(cpu->thread, mask);
   312         qp = qp->next;
   313     }
   314 #endif
   316     return 0;
   317 }
   319 PRUint32 _pr_recycleThreads = 0;
   320 PR_IMPLEMENT(void) PR_SetThreadRecycleMode(PRUint32 count)
   321 {
   322     _pr_recycleThreads = count;
   323 }
   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 }
   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
   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 }
   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 }
   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 }
   376 PR_IMPLEMENT(PRThreadScope) PR_GetThreadScope(const PRThread *thread)
   377 {
   378     if (!_pr_initialized) _PR_ImplicitInitialization();
   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 }
   387 PR_IMPLEMENT(PRThreadType) PR_GetThreadType(const PRThread *thread)
   388 {
   389     return (thread->flags & _PR_SYSTEM) ? PR_SYSTEM_THREAD : PR_USER_THREAD;
   390 }
   392 PR_IMPLEMENT(PRThreadState) PR_GetThreadState(const PRThread *thread)
   393 {
   394     return (NULL == thread->term) ? PR_UNJOINABLE_THREAD : PR_JOINABLE_THREAD;
   395 }  /* PR_GetThreadState */

mercurial