nsprpub/pr/src/threads/prtpd.c

Wed, 31 Dec 2014 06:55:46 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:46 +0100
changeset 1
ca08bd8f51b2
permissions
-rw-r--r--

Added tag TORBROWSER_REPLICA for changeset 6474c204b198

     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 /*
     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 */
    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 */
    35 #ifndef XP_BEOS
    37 #include "primpl.h"
    39 #include <string.h>
    41 #if defined(WIN95)
    42 /*
    43 ** Some local variables report warnings on Win95 because the code paths 
    44 ** using them are conditioned on HAVE_CUSTOME_USER_THREADS.
    45 ** The pragma suppresses the warning.
    46 ** 
    47 */
    48 #pragma warning(disable : 4101)
    49 #endif
    51 #define _PR_TPD_LIMIT 128               /* arbitary limit on the TPD slots */
    52 static PRInt32 _pr_tpd_length = 0;      /* current length of destructor vector */
    53 static PRInt32 _pr_tpd_highwater = 0;   /* next TPD key to be assigned */
    54 static PRThreadPrivateDTOR *_pr_tpd_destructors = NULL;
    55                                         /* the destructors are associated with
    56                                             the keys, therefore asserting that
    57                                             the TPD key depicts the data's 'type' */
    59 /*
    60 ** Initialize the thread private data manipulation
    61 */
    62 void _PR_InitTPD(void)
    63 {
    64     _pr_tpd_destructors = (PRThreadPrivateDTOR*)
    65         PR_CALLOC(_PR_TPD_LIMIT * sizeof(PRThreadPrivateDTOR*));
    66     PR_ASSERT(NULL != _pr_tpd_destructors);
    67     _pr_tpd_length = _PR_TPD_LIMIT;
    68 }
    70 /*
    71 ** Clean up the thread private data manipulation
    72 */
    73 void _PR_CleanupTPD(void)
    74 {
    75 }  /* _PR_CleanupTPD */
    77 /*
    78 ** This routine returns a new index for per-thread-private data table. 
    79 ** The index is visible to all threads within a process. This index can 
    80 ** be used with the PR_SetThreadPrivate() and PR_GetThreadPrivate() routines 
    81 ** to save and retrieve data associated with the index for a thread.
    82 **
    83 ** The index independently maintains specific values for each binding thread. 
    84 ** A thread can only get access to its own thread-specific-data.
    85 **
    86 ** Upon a new index return the value associated with the index for all threads
    87 ** is NULL, and upon thread creation the value associated with all indices for 
    88 ** that thread is NULL. 
    89 **
    90 **     "dtor" is the destructor function to invoke when the private
    91 **       data is set or destroyed
    92 **
    93 ** Returns PR_FAILURE if the total number of indices will exceed the maximun 
    94 ** allowed.
    95 */
    97 PR_IMPLEMENT(PRStatus) PR_NewThreadPrivateIndex(
    98     PRUintn *newIndex, PRThreadPrivateDTOR dtor)
    99 {
   100     PRStatus rv;
   101     PRInt32 index;
   103     if (!_pr_initialized) _PR_ImplicitInitialization();
   105     PR_ASSERT(NULL != newIndex);
   106     PR_ASSERT(NULL != _pr_tpd_destructors);
   108     index = PR_ATOMIC_INCREMENT(&_pr_tpd_highwater) - 1;  /* allocate index */
   109     if (_PR_TPD_LIMIT <= index)
   110     {
   111         PR_SetError(PR_TPD_RANGE_ERROR, 0);
   112         rv = PR_FAILURE;  /* that's just wrong */
   113     }
   114     else
   115     {
   116         _pr_tpd_destructors[index] = dtor;  /* record destructor @index */
   117         *newIndex = (PRUintn)index;  /* copy into client's location */
   118         rv = PR_SUCCESS;  /* that's okay */
   119     }
   121     return rv;
   122 }
   124 /*
   125 ** Define some per-thread-private data.
   126 **     "index" is an index into the per-thread private data table
   127 **     "priv" is the per-thread-private data 
   128 **
   129 ** If the per-thread private data table has a previously registered
   130 ** destructor function and a non-NULL per-thread-private data value,
   131 ** the destructor function is invoked.
   132 **
   133 ** This can return PR_FAILURE if index is invalid (ie., beyond the current
   134 ** high water mark) or memory is insufficient to allocate an exanded vector.
   135 */
   137 PR_IMPLEMENT(PRStatus) PR_SetThreadPrivate(PRUintn index, void *priv)
   138 {
   139     PRThread *self = PR_GetCurrentThread();
   141     /*
   142     ** The index being set might not have a sufficient vector in this
   143     ** thread. But if the index has been allocated, it's okay to go
   144     ** ahead and extend this one now.
   145     */
   146     if ((index >= _PR_TPD_LIMIT) || (index >= _pr_tpd_highwater))
   147     {
   148         PR_SetError(PR_TPD_RANGE_ERROR, 0);
   149         return PR_FAILURE;
   150     }
   152     PR_ASSERT(((NULL == self->privateData) && (0 == self->tpdLength))
   153         || ((NULL != self->privateData) && (0 != self->tpdLength)));
   155     if ((NULL == self->privateData) || (self->tpdLength <= index))
   156     {
   157         void *extension = PR_CALLOC(_pr_tpd_length * sizeof(void*));
   158         if (NULL == extension)
   159         {
   160             PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
   161             return PR_FAILURE;
   162         }
   163         if (self->privateData) {
   164             (void)memcpy(
   165                 extension, self->privateData,
   166                 self->tpdLength * sizeof(void*));
   167             PR_DELETE(self->privateData);
   168         }
   169         self->tpdLength = _pr_tpd_length;
   170         self->privateData = (void**)extension;
   171     }
   172     /*
   173     ** There wasn't much chance of having to call the destructor
   174     ** unless the slot already existed.
   175     */
   176     else if (self->privateData[index] && _pr_tpd_destructors[index])
   177     {
   178         void *data = self->privateData[index];
   179         self->privateData[index] = NULL;
   180         (*_pr_tpd_destructors[index])(data);
   181     }
   183     PR_ASSERT(index < self->tpdLength);
   184     self->privateData[index] = priv;
   186     return PR_SUCCESS;
   187 }
   189 /*
   190 ** Recover the per-thread-private data for the current thread. "index" is
   191 ** the index into the per-thread private data table. 
   192 **
   193 ** The returned value may be NULL which is indistinguishable from an error 
   194 ** condition.
   195 **
   196 */
   198 PR_IMPLEMENT(void*) PR_GetThreadPrivate(PRUintn index)
   199 {
   200     PRThread *self = PR_GetCurrentThread();
   201     void *tpd = ((NULL == self->privateData) || (index >= self->tpdLength)) ?
   202         NULL : self->privateData[index];
   204     return tpd;
   205 }
   207 /*
   208 ** Destroy the thread's private data, if any exists. This is called at
   209 ** thread termination time only. There should be no threading issues
   210 ** since this is being called by the thread itself.
   211 */
   212 void _PR_DestroyThreadPrivate(PRThread* self)
   213 {
   214 #define _PR_TPD_DESTRUCTOR_ITERATIONS 4
   216     if (NULL != self->privateData)  /* we have some */
   217     {
   218         PRBool clean;
   219         PRUint32 index;
   220         PRInt32 passes = _PR_TPD_DESTRUCTOR_ITERATIONS;
   221         PR_ASSERT(0 != self->tpdLength);
   222         do
   223         {
   224             clean = PR_TRUE;
   225             for (index = 0; index < self->tpdLength; ++index)
   226             {
   227                 void *priv = self->privateData[index];  /* extract */
   228                 if (NULL != priv)  /* we have data at this index */
   229                 {
   230                     if (NULL != _pr_tpd_destructors[index])
   231                     {
   232                         self->privateData[index] = NULL;  /* precondition */
   233                         (*_pr_tpd_destructors[index])(priv);  /* destroy */
   234                         clean = PR_FALSE;  /* unknown side effects */
   235                     }
   236                 }
   237             }
   238         } while ((--passes > 0) && !clean);  /* limit # of passes */
   239         /*
   240         ** We give up after a fixed number of passes. Any non-NULL
   241         ** thread-private data value with a registered destructor
   242         ** function is not destroyed.
   243         */
   244         memset(self->privateData, 0, self->tpdLength * sizeof(void*));
   245     }
   246 }  /* _PR_DestroyThreadPrivate */
   248 #endif /* !XP_BEOS */

mercurial