1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
3
* The contents of this file are subject to the Mozilla Public
4
* License Version 1.1 (the "License"); you may not use this file
5
* except in compliance with the License. You may obtain a copy of
6
* the License at http://www.mozilla.org/MPL/
8
* Software distributed under the License is distributed on an "AS
9
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
10
* implied. See the License for the specific language governing
11
* rights and limitations under the License.
13
* The Original Code is the Netscape Portable Runtime (NSPR).
15
* The Initial Developer of the Original Code is Netscape
16
* Communications Corporation. Portions created by Netscape are
17
* Copyright (C) 1998-2000 Netscape Communications Corporation. All
22
* Alternatively, the contents of this file may be used under the
23
* terms of the GNU General Public License Version 2 or later (the
24
* "GPL"), in which case the provisions of the GPL are applicable
25
* instead of those above. If you wish to allow use of your
26
* version of this file only under the terms of the GPL and not to
27
* allow others to use your version of this file under the MPL,
28
* indicate your decision by deleting the provisions above and
29
* replace them with the notice and other provisions required by
30
* the GPL. If you do not delete the provisions above, a recipient
31
* may use your version of this file under either the MPL or the
36
** Thread Private Data
38
** There is an aribitrary limit on the number of keys that will be allocated
39
** by the runtime. It's largish, so it is intended to be a sanity check, not
42
** There is a counter, initialized to zero and incremented every time a
43
** client asks for a new key, that holds the high water mark for keys. All
44
** threads logically have the same high water mark and are permitted to
45
** ask for TPD up to that key value.
47
** The vector to hold the TPD are allocated when PR_SetThreadPrivate() is
48
** called. The size of the vector will be some value greater than or equal
49
** to the current high water mark. Each thread has its own TPD length and
52
** Threads that get private data for keys they have not set (or perhaps
53
** don't even exist for that thread) get a NULL return. If the key is
54
** beyond the high water mark, an error will be returned.
58
** As of this time, BeOS has its own TPD implementation. Integrating
59
** this standard one is a TODO for anyone with a bit of spare time on
60
** their hand. For now, we just #ifdef out this whole file and use
61
** the routines in pr/src/btthreads/
72
** Some local variables report warnings on Win95 because the code paths
73
** using them are conditioned on HAVE_CUSTOME_USER_THREADS.
74
** The pragma suppresses the warning.
77
#pragma warning(disable : 4101)
80
#define _PR_TPD_LIMIT 128 /* arbitary limit on the TPD slots */
81
static PRInt32 _pr_tpd_length = 0; /* current length of destructor vector */
82
static PRInt32 _pr_tpd_highwater = 0; /* next TPD key to be assigned */
83
static PRThreadPrivateDTOR *_pr_tpd_destructors = NULL;
84
/* the destructors are associated with
85
the keys, therefore asserting that
86
the TPD key depicts the data's 'type' */
89
** Initialize the thread private data manipulation
91
void _PR_InitTPD(void)
93
_pr_tpd_destructors = (PRThreadPrivateDTOR*)
94
PR_CALLOC(_PR_TPD_LIMIT * sizeof(PRThreadPrivateDTOR*));
95
PR_ASSERT(NULL != _pr_tpd_destructors);
96
_pr_tpd_length = _PR_TPD_LIMIT;
100
** Clean up the thread private data manipulation
102
void _PR_CleanupTPD(void)
104
} /* _PR_CleanupTPD */
107
** This routine returns a new index for per-thread-private data table.
108
** The index is visible to all threads within a process. This index can
109
** be used with the PR_SetThreadPrivate() and PR_GetThreadPrivate() routines
110
** to save and retrieve data associated with the index for a thread.
112
** The index independently maintains specific values for each binding thread.
113
** A thread can only get access to its own thread-specific-data.
115
** Upon a new index return the value associated with the index for all threads
116
** is NULL, and upon thread creation the value associated with all indices for
117
** that thread is NULL.
119
** "dtor" is the destructor function to invoke when the private
120
** data is set or destroyed
122
** Returns PR_FAILURE if the total number of indices will exceed the maximun
126
PR_IMPLEMENT(PRStatus) PR_NewThreadPrivateIndex(
127
PRUintn *newIndex, PRThreadPrivateDTOR dtor)
132
if (!_pr_initialized) _PR_ImplicitInitialization();
134
PR_ASSERT(NULL != newIndex);
135
PR_ASSERT(NULL != _pr_tpd_destructors);
137
index = PR_AtomicIncrement(&_pr_tpd_highwater) - 1; /* allocate index */
138
if (_PR_TPD_LIMIT <= index)
140
PR_SetError(PR_TPD_RANGE_ERROR, 0);
141
rv = PR_FAILURE; /* that's just wrong */
145
_pr_tpd_destructors[index] = dtor; /* record destructor @index */
146
*newIndex = (PRUintn)index; /* copy into client's location */
147
rv = PR_SUCCESS; /* that's okay */
154
** Define some per-thread-private data.
155
** "index" is an index into the per-thread private data table
156
** "priv" is the per-thread-private data
158
** If the per-thread private data table has a previously registered
159
** destructor function and a non-NULL per-thread-private data value,
160
** the destructor function is invoked.
162
** This can return PR_FAILURE if index is invalid (ie., beyond the current
163
** high water mark) or memory is insufficient to allocate an exanded vector.
166
PR_IMPLEMENT(PRStatus) PR_SetThreadPrivate(PRUintn index, void *priv)
168
PRThread *self = PR_GetCurrentThread();
171
** The index being set might not have a sufficient vector in this
172
** thread. But if the index has been allocated, it's okay to go
173
** ahead and extend this one now.
175
if ((index >= _PR_TPD_LIMIT) || (index >= _pr_tpd_highwater))
177
PR_SetError(PR_TPD_RANGE_ERROR, 0);
181
PR_ASSERT(((NULL == self->privateData) && (0 == self->tpdLength))
182
|| ((NULL != self->privateData) && (0 != self->tpdLength)));
184
if ((NULL == self->privateData) || (self->tpdLength <= index))
186
void *extension = PR_CALLOC(_pr_tpd_length * sizeof(void*));
187
if (NULL == extension)
189
PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
193
extension, self->privateData,
194
self->tpdLength * sizeof(void*));
195
PR_DELETE(self->privateData);
196
self->tpdLength = _pr_tpd_length;
197
self->privateData = (void**)extension;
200
** There wasn't much chance of having to call the destructor
201
** unless the slot already existed.
203
else if (self->privateData[index] && _pr_tpd_destructors[index])
205
void *data = self->privateData[index];
206
self->privateData[index] = NULL;
207
(*_pr_tpd_destructors[index])(data);
210
PR_ASSERT(index < self->tpdLength);
211
self->privateData[index] = priv;
217
** Recover the per-thread-private data for the current thread. "index" is
218
** the index into the per-thread private data table.
220
** The returned value may be NULL which is indistinguishable from an error
225
PR_IMPLEMENT(void*) PR_GetThreadPrivate(PRUintn index)
227
PRThread *self = PR_GetCurrentThread();
228
void *tpd = ((NULL == self->privateData) || (index >= self->tpdLength)) ?
229
NULL : self->privateData[index];
235
** Destroy the thread's private data, if any exists. This is called at
236
** thread termination time only. There should be no threading issues
237
** since this is being called by the thread itself.
239
void _PR_DestroyThreadPrivate(PRThread* self)
241
#define _PR_TPD_DESTRUCTOR_ITERATIONS 4
243
if (NULL != self->privateData) /* we have some */
247
PRInt32 passes = _PR_TPD_DESTRUCTOR_ITERATIONS;
248
PR_ASSERT(0 != self->tpdLength);
252
for (index = 0; index < self->tpdLength; ++index)
254
void *priv = self->privateData[index]; /* extract */
255
if (NULL != priv) /* we have data at this index */
257
if (NULL != _pr_tpd_destructors[index])
259
self->privateData[index] = NULL; /* precondition */
260
(*_pr_tpd_destructors[index])(priv); /* destroy */
261
clean = PR_FALSE; /* unknown side effects */
265
} while ((--passes > 0) && !clean); /* limit # of passes */
267
** We give up after a fixed number of passes. Any non-NULL
268
** thread-private data value with a registered destructor
269
** function is not destroyed.
271
memset(self->privateData, 0, self->tpdLength * sizeof(void*));
273
} /* _PR_DestroyThreadPrivate */
275
#endif /* !XP_BEOS */