tor-browser

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

prtpd.c (7832B)


      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 /*
      7 ** Thread Private Data
      8 **
      9 ** There is an aribitrary limit on the number of keys that will be allocated
     10 ** by the runtime. It's largish, so it is intended to be a sanity check, not
     11 ** an impediment.
     12 **
     13 ** There is a counter, initialized to zero and incremented every time a
     14 ** client asks for a new key, that holds the high water mark for keys. All
     15 ** threads logically have the same high water mark and are permitted to
     16 ** ask for TPD up to that key value.
     17 **
     18 ** The vector to hold the TPD are allocated when PR_SetThreadPrivate() is
     19 ** called. The size of the vector will be some value greater than or equal
     20 ** to the current high water mark. Each thread has its own TPD length and
     21 ** vector.
     22 **
     23 ** Threads that get private data for keys they have not set (or perhaps
     24 ** don't even exist for that thread) get a NULL return. If the key is
     25 ** beyond the high water mark, an error will be returned.
     26 */
     27 
     28 /*
     29 ** As of this time, BeOS has its own TPD implementation.  Integrating
     30 ** this standard one is a TODO for anyone with a bit of spare time on
     31 ** their hand.  For now, we just #ifdef out this whole file and use
     32 ** the routines in pr/src/btthreads/
     33 */
     34 
     35 #include "primpl.h"
     36 
     37 #include <string.h>
     38 
     39 #if defined(WIN95)
     40 /*
     41 ** Some local variables report warnings on Win95 because the code paths
     42 ** using them are conditioned on HAVE_CUSTOME_USER_THREADS.
     43 ** The pragma suppresses the warning.
     44 **
     45 */
     46 #  pragma warning(disable : 4101)
     47 #endif
     48 
     49 #define _PR_TPD_LIMIT 128             /* arbitary limit on the TPD slots */
     50 static PRInt32 _pr_tpd_length = 0;    /* current length of destructor vector */
     51 static PRInt32 _pr_tpd_highwater = 0; /* next TPD key to be assigned */
     52 static PRThreadPrivateDTOR* _pr_tpd_destructors = NULL;
     53 /* the destructors are associated with
     54    the keys, therefore asserting that
     55    the TPD key depicts the data's 'type' */
     56 
     57 /*
     58 ** Initialize the thread private data manipulation
     59 */
     60 void _PR_InitTPD(void) {
     61  _pr_tpd_destructors = (PRThreadPrivateDTOR*)PR_CALLOC(
     62      _PR_TPD_LIMIT * sizeof(PRThreadPrivateDTOR*));
     63  PR_ASSERT(NULL != _pr_tpd_destructors);
     64  _pr_tpd_length = _PR_TPD_LIMIT;
     65 }
     66 
     67 /*
     68 ** Clean up the thread private data manipulation
     69 */
     70 void _PR_CleanupTPD(void) {} /* _PR_CleanupTPD */
     71 
     72 /*
     73 ** This routine returns a new index for per-thread-private data table.
     74 ** The index is visible to all threads within a process. This index can
     75 ** be used with the PR_SetThreadPrivate() and PR_GetThreadPrivate() routines
     76 ** to save and retrieve data associated with the index for a thread.
     77 **
     78 ** The index independently maintains specific values for each binding thread.
     79 ** A thread can only get access to its own thread-specific-data.
     80 **
     81 ** Upon a new index return the value associated with the index for all threads
     82 ** is NULL, and upon thread creation the value associated with all indices for
     83 ** that thread is NULL.
     84 **
     85 **     "dtor" is the destructor function to invoke when the private
     86 **       data is set or destroyed
     87 **
     88 ** Returns PR_FAILURE if the total number of indices will exceed the maximun
     89 ** allowed.
     90 */
     91 
     92 PR_IMPLEMENT(PRStatus)
     93 PR_NewThreadPrivateIndex(PRUintn* newIndex, PRThreadPrivateDTOR dtor) {
     94  PRStatus rv;
     95  PRInt32 index;
     96 
     97  if (!_pr_initialized) {
     98    _PR_ImplicitInitialization();
     99  }
    100 
    101  PR_ASSERT(NULL != newIndex);
    102  PR_ASSERT(NULL != _pr_tpd_destructors);
    103 
    104  index = PR_ATOMIC_INCREMENT(&_pr_tpd_highwater) - 1; /* allocate index */
    105  if (_PR_TPD_LIMIT <= index) {
    106    PR_SetError(PR_TPD_RANGE_ERROR, 0);
    107    rv = PR_FAILURE; /* that's just wrong */
    108  } else {
    109    _pr_tpd_destructors[index] = dtor; /* record destructor @index */
    110    *newIndex = (PRUintn)index;        /* copy into client's location */
    111    rv = PR_SUCCESS;                   /* that's okay */
    112  }
    113 
    114  return rv;
    115 }
    116 
    117 /*
    118 ** Define some per-thread-private data.
    119 **     "index" is an index into the per-thread private data table
    120 **     "priv" is the per-thread-private data
    121 **
    122 ** If the per-thread private data table has a previously registered
    123 ** destructor function and a non-NULL per-thread-private data value,
    124 ** the destructor function is invoked.
    125 **
    126 ** This can return PR_FAILURE if index is invalid (ie., beyond the limit
    127 ** on the TPD slots) or memory is insufficient to allocate an expanded
    128 ** vector.
    129 */
    130 
    131 PR_IMPLEMENT(PRStatus) PR_SetThreadPrivate(PRUintn index, void* priv) {
    132  PRThread* self = PR_GetCurrentThread();
    133 
    134  /*
    135  ** To improve performance, we don't check if the index has been
    136  ** allocated.
    137  */
    138  if (index >= _PR_TPD_LIMIT) {
    139    PR_SetError(PR_TPD_RANGE_ERROR, 0);
    140    return PR_FAILURE;
    141  }
    142 
    143  PR_ASSERT(((NULL == self->privateData) && (0 == self->tpdLength)) ||
    144            ((NULL != self->privateData) && (0 != self->tpdLength)));
    145 
    146  /*
    147  ** If this thread does not have a sufficient vector for the index
    148  ** being set, go ahead and extend this vector now.
    149  */
    150  if ((NULL == self->privateData) || (self->tpdLength <= index)) {
    151    void* extension = PR_CALLOC(_pr_tpd_length * sizeof(void*));
    152    if (NULL == extension) {
    153      PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
    154      return PR_FAILURE;
    155    }
    156    if (self->privateData) {
    157      (void)memcpy(extension, self->privateData,
    158                   self->tpdLength * sizeof(void*));
    159      PR_DELETE(self->privateData);
    160    }
    161    self->tpdLength = _pr_tpd_length;
    162    self->privateData = (void**)extension;
    163  }
    164  /*
    165  ** There wasn't much chance of having to call the destructor
    166  ** unless the slot already existed.
    167  */
    168  else if (self->privateData[index] && _pr_tpd_destructors[index]) {
    169    void* data = self->privateData[index];
    170    self->privateData[index] = NULL;
    171    (*_pr_tpd_destructors[index])(data);
    172  }
    173 
    174  PR_ASSERT(index < self->tpdLength);
    175  self->privateData[index] = priv;
    176 
    177  return PR_SUCCESS;
    178 }
    179 
    180 /*
    181 ** Recover the per-thread-private data for the current thread. "index" is
    182 ** the index into the per-thread private data table.
    183 **
    184 ** The returned value may be NULL which is indistinguishable from an error
    185 ** condition.
    186 **
    187 */
    188 
    189 PR_IMPLEMENT(void*) PR_GetThreadPrivate(PRUintn index) {
    190  PRThread* self = PR_GetCurrentThread();
    191  void* tpd = ((NULL == self->privateData) || (index >= self->tpdLength))
    192                  ? NULL
    193                  : self->privateData[index];
    194 
    195  return tpd;
    196 }
    197 
    198 /*
    199 ** Destroy the thread's private data, if any exists. This is called at
    200 ** thread termination time only. There should be no threading issues
    201 ** since this is being called by the thread itself.
    202 */
    203 void _PR_DestroyThreadPrivate(PRThread* self) {
    204 #define _PR_TPD_DESTRUCTOR_ITERATIONS 4
    205 
    206  if (NULL != self->privateData) /* we have some */
    207  {
    208    PRBool clean;
    209    PRUint32 index;
    210    PRInt32 passes = _PR_TPD_DESTRUCTOR_ITERATIONS;
    211    PR_ASSERT(0 != self->tpdLength);
    212    do {
    213      clean = PR_TRUE;
    214      for (index = 0; index < self->tpdLength; ++index) {
    215        void* priv = self->privateData[index]; /* extract */
    216        if (NULL != priv)                      /* we have data at this index */
    217        {
    218          if (NULL != _pr_tpd_destructors[index]) {
    219            self->privateData[index] = NULL;     /* precondition */
    220            (*_pr_tpd_destructors[index])(priv); /* destroy */
    221            clean = PR_FALSE;                    /* unknown side effects */
    222          }
    223        }
    224      }
    225    } while ((--passes > 0) && !clean); /* limit # of passes */
    226    /*
    227    ** We give up after a fixed number of passes. Any non-NULL
    228    ** thread-private data value with a registered destructor
    229    ** function is not destroyed.
    230    */
    231    memset(self->privateData, 0, self->tpdLength * sizeof(void*));
    232  }
    233 } /* _PR_DestroyThreadPrivate */