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

mercurial