1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/nsprpub/pr/src/threads/prtpd.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,248 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/* 1.10 +** Thread Private Data 1.11 +** 1.12 +** There is an aribitrary limit on the number of keys that will be allocated 1.13 +** by the runtime. It's largish, so it is intended to be a sanity check, not 1.14 +** an impediment. 1.15 +** 1.16 +** There is a counter, initialized to zero and incremented every time a 1.17 +** client asks for a new key, that holds the high water mark for keys. All 1.18 +** threads logically have the same high water mark and are permitted to 1.19 +** ask for TPD up to that key value. 1.20 +** 1.21 +** The vector to hold the TPD are allocated when PR_SetThreadPrivate() is 1.22 +** called. The size of the vector will be some value greater than or equal 1.23 +** to the current high water mark. Each thread has its own TPD length and 1.24 +** vector. 1.25 +** 1.26 +** Threads that get private data for keys they have not set (or perhaps 1.27 +** don't even exist for that thread) get a NULL return. If the key is 1.28 +** beyond the high water mark, an error will be returned. 1.29 +*/ 1.30 + 1.31 +/* 1.32 +** As of this time, BeOS has its own TPD implementation. Integrating 1.33 +** this standard one is a TODO for anyone with a bit of spare time on 1.34 +** their hand. For now, we just #ifdef out this whole file and use 1.35 +** the routines in pr/src/btthreads/ 1.36 +*/ 1.37 + 1.38 +#ifndef XP_BEOS 1.39 + 1.40 +#include "primpl.h" 1.41 + 1.42 +#include <string.h> 1.43 + 1.44 +#if defined(WIN95) 1.45 +/* 1.46 +** Some local variables report warnings on Win95 because the code paths 1.47 +** using them are conditioned on HAVE_CUSTOME_USER_THREADS. 1.48 +** The pragma suppresses the warning. 1.49 +** 1.50 +*/ 1.51 +#pragma warning(disable : 4101) 1.52 +#endif 1.53 + 1.54 +#define _PR_TPD_LIMIT 128 /* arbitary limit on the TPD slots */ 1.55 +static PRInt32 _pr_tpd_length = 0; /* current length of destructor vector */ 1.56 +static PRInt32 _pr_tpd_highwater = 0; /* next TPD key to be assigned */ 1.57 +static PRThreadPrivateDTOR *_pr_tpd_destructors = NULL; 1.58 + /* the destructors are associated with 1.59 + the keys, therefore asserting that 1.60 + the TPD key depicts the data's 'type' */ 1.61 + 1.62 +/* 1.63 +** Initialize the thread private data manipulation 1.64 +*/ 1.65 +void _PR_InitTPD(void) 1.66 +{ 1.67 + _pr_tpd_destructors = (PRThreadPrivateDTOR*) 1.68 + PR_CALLOC(_PR_TPD_LIMIT * sizeof(PRThreadPrivateDTOR*)); 1.69 + PR_ASSERT(NULL != _pr_tpd_destructors); 1.70 + _pr_tpd_length = _PR_TPD_LIMIT; 1.71 +} 1.72 + 1.73 +/* 1.74 +** Clean up the thread private data manipulation 1.75 +*/ 1.76 +void _PR_CleanupTPD(void) 1.77 +{ 1.78 +} /* _PR_CleanupTPD */ 1.79 + 1.80 +/* 1.81 +** This routine returns a new index for per-thread-private data table. 1.82 +** The index is visible to all threads within a process. This index can 1.83 +** be used with the PR_SetThreadPrivate() and PR_GetThreadPrivate() routines 1.84 +** to save and retrieve data associated with the index for a thread. 1.85 +** 1.86 +** The index independently maintains specific values for each binding thread. 1.87 +** A thread can only get access to its own thread-specific-data. 1.88 +** 1.89 +** Upon a new index return the value associated with the index for all threads 1.90 +** is NULL, and upon thread creation the value associated with all indices for 1.91 +** that thread is NULL. 1.92 +** 1.93 +** "dtor" is the destructor function to invoke when the private 1.94 +** data is set or destroyed 1.95 +** 1.96 +** Returns PR_FAILURE if the total number of indices will exceed the maximun 1.97 +** allowed. 1.98 +*/ 1.99 + 1.100 +PR_IMPLEMENT(PRStatus) PR_NewThreadPrivateIndex( 1.101 + PRUintn *newIndex, PRThreadPrivateDTOR dtor) 1.102 +{ 1.103 + PRStatus rv; 1.104 + PRInt32 index; 1.105 + 1.106 + if (!_pr_initialized) _PR_ImplicitInitialization(); 1.107 + 1.108 + PR_ASSERT(NULL != newIndex); 1.109 + PR_ASSERT(NULL != _pr_tpd_destructors); 1.110 + 1.111 + index = PR_ATOMIC_INCREMENT(&_pr_tpd_highwater) - 1; /* allocate index */ 1.112 + if (_PR_TPD_LIMIT <= index) 1.113 + { 1.114 + PR_SetError(PR_TPD_RANGE_ERROR, 0); 1.115 + rv = PR_FAILURE; /* that's just wrong */ 1.116 + } 1.117 + else 1.118 + { 1.119 + _pr_tpd_destructors[index] = dtor; /* record destructor @index */ 1.120 + *newIndex = (PRUintn)index; /* copy into client's location */ 1.121 + rv = PR_SUCCESS; /* that's okay */ 1.122 + } 1.123 + 1.124 + return rv; 1.125 +} 1.126 + 1.127 +/* 1.128 +** Define some per-thread-private data. 1.129 +** "index" is an index into the per-thread private data table 1.130 +** "priv" is the per-thread-private data 1.131 +** 1.132 +** If the per-thread private data table has a previously registered 1.133 +** destructor function and a non-NULL per-thread-private data value, 1.134 +** the destructor function is invoked. 1.135 +** 1.136 +** This can return PR_FAILURE if index is invalid (ie., beyond the current 1.137 +** high water mark) or memory is insufficient to allocate an exanded vector. 1.138 +*/ 1.139 + 1.140 +PR_IMPLEMENT(PRStatus) PR_SetThreadPrivate(PRUintn index, void *priv) 1.141 +{ 1.142 + PRThread *self = PR_GetCurrentThread(); 1.143 + 1.144 + /* 1.145 + ** The index being set might not have a sufficient vector in this 1.146 + ** thread. But if the index has been allocated, it's okay to go 1.147 + ** ahead and extend this one now. 1.148 + */ 1.149 + if ((index >= _PR_TPD_LIMIT) || (index >= _pr_tpd_highwater)) 1.150 + { 1.151 + PR_SetError(PR_TPD_RANGE_ERROR, 0); 1.152 + return PR_FAILURE; 1.153 + } 1.154 + 1.155 + PR_ASSERT(((NULL == self->privateData) && (0 == self->tpdLength)) 1.156 + || ((NULL != self->privateData) && (0 != self->tpdLength))); 1.157 + 1.158 + if ((NULL == self->privateData) || (self->tpdLength <= index)) 1.159 + { 1.160 + void *extension = PR_CALLOC(_pr_tpd_length * sizeof(void*)); 1.161 + if (NULL == extension) 1.162 + { 1.163 + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); 1.164 + return PR_FAILURE; 1.165 + } 1.166 + if (self->privateData) { 1.167 + (void)memcpy( 1.168 + extension, self->privateData, 1.169 + self->tpdLength * sizeof(void*)); 1.170 + PR_DELETE(self->privateData); 1.171 + } 1.172 + self->tpdLength = _pr_tpd_length; 1.173 + self->privateData = (void**)extension; 1.174 + } 1.175 + /* 1.176 + ** There wasn't much chance of having to call the destructor 1.177 + ** unless the slot already existed. 1.178 + */ 1.179 + else if (self->privateData[index] && _pr_tpd_destructors[index]) 1.180 + { 1.181 + void *data = self->privateData[index]; 1.182 + self->privateData[index] = NULL; 1.183 + (*_pr_tpd_destructors[index])(data); 1.184 + } 1.185 + 1.186 + PR_ASSERT(index < self->tpdLength); 1.187 + self->privateData[index] = priv; 1.188 + 1.189 + return PR_SUCCESS; 1.190 +} 1.191 + 1.192 +/* 1.193 +** Recover the per-thread-private data for the current thread. "index" is 1.194 +** the index into the per-thread private data table. 1.195 +** 1.196 +** The returned value may be NULL which is indistinguishable from an error 1.197 +** condition. 1.198 +** 1.199 +*/ 1.200 + 1.201 +PR_IMPLEMENT(void*) PR_GetThreadPrivate(PRUintn index) 1.202 +{ 1.203 + PRThread *self = PR_GetCurrentThread(); 1.204 + void *tpd = ((NULL == self->privateData) || (index >= self->tpdLength)) ? 1.205 + NULL : self->privateData[index]; 1.206 + 1.207 + return tpd; 1.208 +} 1.209 + 1.210 +/* 1.211 +** Destroy the thread's private data, if any exists. This is called at 1.212 +** thread termination time only. There should be no threading issues 1.213 +** since this is being called by the thread itself. 1.214 +*/ 1.215 +void _PR_DestroyThreadPrivate(PRThread* self) 1.216 +{ 1.217 +#define _PR_TPD_DESTRUCTOR_ITERATIONS 4 1.218 + 1.219 + if (NULL != self->privateData) /* we have some */ 1.220 + { 1.221 + PRBool clean; 1.222 + PRUint32 index; 1.223 + PRInt32 passes = _PR_TPD_DESTRUCTOR_ITERATIONS; 1.224 + PR_ASSERT(0 != self->tpdLength); 1.225 + do 1.226 + { 1.227 + clean = PR_TRUE; 1.228 + for (index = 0; index < self->tpdLength; ++index) 1.229 + { 1.230 + void *priv = self->privateData[index]; /* extract */ 1.231 + if (NULL != priv) /* we have data at this index */ 1.232 + { 1.233 + if (NULL != _pr_tpd_destructors[index]) 1.234 + { 1.235 + self->privateData[index] = NULL; /* precondition */ 1.236 + (*_pr_tpd_destructors[index])(priv); /* destroy */ 1.237 + clean = PR_FALSE; /* unknown side effects */ 1.238 + } 1.239 + } 1.240 + } 1.241 + } while ((--passes > 0) && !clean); /* limit # of passes */ 1.242 + /* 1.243 + ** We give up after a fixed number of passes. Any non-NULL 1.244 + ** thread-private data value with a registered destructor 1.245 + ** function is not destroyed. 1.246 + */ 1.247 + memset(self->privateData, 0, self->tpdLength * sizeof(void*)); 1.248 + } 1.249 +} /* _PR_DestroyThreadPrivate */ 1.250 + 1.251 +#endif /* !XP_BEOS */