Wed, 31 Dec 2014 06:09:35 +0100
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 */ |