tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 */