Back to index

lightning-sunbird  0.9+nobinonly
prtpd.c
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is the Netscape Portable Runtime (NSPR).
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-2000
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 /*
00039 ** Thread Private Data
00040 **
00041 ** There is an aribitrary limit on the number of keys that will be allocated
00042 ** by the runtime. It's largish, so it is intended to be a sanity check, not
00043 ** an impediment.
00044 **
00045 ** There is a counter, initialized to zero and incremented every time a
00046 ** client asks for a new key, that holds the high water mark for keys. All
00047 ** threads logically have the same high water mark and are permitted to
00048 ** ask for TPD up to that key value.
00049 **
00050 ** The vector to hold the TPD are allocated when PR_SetThreadPrivate() is
00051 ** called. The size of the vector will be some value greater than or equal
00052 ** to the current high water mark. Each thread has its own TPD length and
00053 ** vector.
00054 **
00055 ** Threads that get private data for keys they have not set (or perhaps
00056 ** don't even exist for that thread) get a NULL return. If the key is
00057 ** beyond the high water mark, an error will be returned.
00058 */
00059 
00060 /*
00061 ** As of this time, BeOS has its own TPD implementation.  Integrating
00062 ** this standard one is a TODO for anyone with a bit of spare time on
00063 ** their hand.  For now, we just #ifdef out this whole file and use
00064 ** the routines in pr/src/btthreads/
00065 */
00066 
00067 #ifndef XP_BEOS
00068 
00069 #include "primpl.h"
00070 
00071 #include <string.h>
00072 
00073 #if defined(WIN95)
00074 /*
00075 ** Some local variables report warnings on Win95 because the code paths 
00076 ** using them are conditioned on HAVE_CUSTOME_USER_THREADS.
00077 ** The pragma suppresses the warning.
00078 ** 
00079 */
00080 #pragma warning(disable : 4101)
00081 #endif
00082 
00083 #define _PR_TPD_LIMIT 128               /* arbitary limit on the TPD slots */
00084 static PRInt32 _pr_tpd_length = 0;      /* current length of destructor vector */
00085 static PRInt32 _pr_tpd_highwater = 0;   /* next TPD key to be assigned */
00086 static PRThreadPrivateDTOR *_pr_tpd_destructors = NULL;
00087                                         /* the destructors are associated with
00088                                             the keys, therefore asserting that
00089                                             the TPD key depicts the data's 'type' */
00090 
00091 /*
00092 ** Initialize the thread private data manipulation
00093 */
00094 void _PR_InitTPD(void)
00095 {
00096     _pr_tpd_destructors = (PRThreadPrivateDTOR*)
00097         PR_CALLOC(_PR_TPD_LIMIT * sizeof(PRThreadPrivateDTOR*));
00098     PR_ASSERT(NULL != _pr_tpd_destructors);
00099     _pr_tpd_length = _PR_TPD_LIMIT;
00100 }
00101 
00102 /*
00103 ** Clean up the thread private data manipulation
00104 */
00105 void _PR_CleanupTPD(void)
00106 {
00107 }  /* _PR_CleanupTPD */
00108 
00109 /*
00110 ** This routine returns a new index for per-thread-private data table. 
00111 ** The index is visible to all threads within a process. This index can 
00112 ** be used with the PR_SetThreadPrivate() and PR_GetThreadPrivate() routines 
00113 ** to save and retrieve data associated with the index for a thread.
00114 **
00115 ** The index independently maintains specific values for each binding thread. 
00116 ** A thread can only get access to its own thread-specific-data.
00117 **
00118 ** Upon a new index return the value associated with the index for all threads
00119 ** is NULL, and upon thread creation the value associated with all indices for 
00120 ** that thread is NULL. 
00121 **
00122 **     "dtor" is the destructor function to invoke when the private
00123 **       data is set or destroyed
00124 **
00125 ** Returns PR_FAILURE if the total number of indices will exceed the maximun 
00126 ** allowed.
00127 */
00128 
00129 PR_IMPLEMENT(PRStatus) PR_NewThreadPrivateIndex(
00130     PRUintn *newIndex, PRThreadPrivateDTOR dtor)
00131 {
00132     PRStatus rv;
00133     PRInt32 index;
00134 
00135     if (!_pr_initialized) _PR_ImplicitInitialization();
00136 
00137     PR_ASSERT(NULL != newIndex);
00138     PR_ASSERT(NULL != _pr_tpd_destructors);
00139 
00140     index = PR_AtomicIncrement(&_pr_tpd_highwater) - 1;  /* allocate index */
00141     if (_PR_TPD_LIMIT <= index)
00142     {
00143         PR_SetError(PR_TPD_RANGE_ERROR, 0);
00144         rv = PR_FAILURE;  /* that's just wrong */
00145     }
00146     else
00147     {
00148         _pr_tpd_destructors[index] = dtor;  /* record destructor @index */
00149         *newIndex = (PRUintn)index;  /* copy into client's location */
00150         rv = PR_SUCCESS;  /* that's okay */
00151     }
00152 
00153     return rv;
00154 }
00155 
00156 /*
00157 ** Define some per-thread-private data.
00158 **     "index" is an index into the per-thread private data table
00159 **     "priv" is the per-thread-private data 
00160 **
00161 ** If the per-thread private data table has a previously registered
00162 ** destructor function and a non-NULL per-thread-private data value,
00163 ** the destructor function is invoked.
00164 **
00165 ** This can return PR_FAILURE if index is invalid (ie., beyond the current
00166 ** high water mark) or memory is insufficient to allocate an exanded vector.
00167 */
00168 
00169 PR_IMPLEMENT(PRStatus) PR_SetThreadPrivate(PRUintn index, void *priv)
00170 {
00171     PRThread *self = PR_GetCurrentThread();
00172 
00173     /*
00174     ** The index being set might not have a sufficient vector in this
00175     ** thread. But if the index has been allocated, it's okay to go
00176     ** ahead and extend this one now.
00177     */
00178     if ((index >= _PR_TPD_LIMIT) || (index >= _pr_tpd_highwater))
00179     {
00180         PR_SetError(PR_TPD_RANGE_ERROR, 0);
00181         return PR_FAILURE;
00182     }
00183 
00184     PR_ASSERT(((NULL == self->privateData) && (0 == self->tpdLength))
00185         || ((NULL != self->privateData) && (0 != self->tpdLength)));
00186 
00187     if ((NULL == self->privateData) || (self->tpdLength <= index))
00188     {
00189         void *extension = PR_CALLOC(_pr_tpd_length * sizeof(void*));
00190         if (NULL == extension)
00191         {
00192             PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
00193             return PR_FAILURE;
00194         }
00195         if (self->privateData) {
00196             (void)memcpy(
00197                 extension, self->privateData,
00198                 self->tpdLength * sizeof(void*));
00199             PR_DELETE(self->privateData);
00200         }
00201         self->tpdLength = _pr_tpd_length;
00202         self->privateData = (void**)extension;
00203     }
00204     /*
00205     ** There wasn't much chance of having to call the destructor
00206     ** unless the slot already existed.
00207     */
00208     else if (self->privateData[index] && _pr_tpd_destructors[index])
00209     {
00210         void *data = self->privateData[index];
00211         self->privateData[index] = NULL;
00212         (*_pr_tpd_destructors[index])(data);
00213     }
00214 
00215     PR_ASSERT(index < self->tpdLength);
00216     self->privateData[index] = priv;
00217 
00218     return PR_SUCCESS;
00219 }
00220 
00221 /*
00222 ** Recover the per-thread-private data for the current thread. "index" is
00223 ** the index into the per-thread private data table. 
00224 **
00225 ** The returned value may be NULL which is indistinguishable from an error 
00226 ** condition.
00227 **
00228 */
00229 
00230 PR_IMPLEMENT(void*) PR_GetThreadPrivate(PRUintn index)
00231 {
00232     PRThread *self = PR_GetCurrentThread();
00233     void *tpd = ((NULL == self->privateData) || (index >= self->tpdLength)) ?
00234         NULL : self->privateData[index];
00235 
00236     return tpd;
00237 }
00238 
00239 /*
00240 ** Destroy the thread's private data, if any exists. This is called at
00241 ** thread termination time only. There should be no threading issues
00242 ** since this is being called by the thread itself.
00243 */
00244 void _PR_DestroyThreadPrivate(PRThread* self)
00245 {
00246 #define _PR_TPD_DESTRUCTOR_ITERATIONS 4
00247 
00248     if (NULL != self->privateData)  /* we have some */
00249     {
00250         PRBool clean;
00251         PRUint32 index;
00252         PRInt32 passes = _PR_TPD_DESTRUCTOR_ITERATIONS;
00253         PR_ASSERT(0 != self->tpdLength);
00254         do
00255         {
00256             clean = PR_TRUE;
00257             for (index = 0; index < self->tpdLength; ++index)
00258             {
00259                 void *priv = self->privateData[index];  /* extract */
00260                 if (NULL != priv)  /* we have data at this index */
00261                 {
00262                     if (NULL != _pr_tpd_destructors[index])
00263                     {
00264                         self->privateData[index] = NULL;  /* precondition */
00265                         (*_pr_tpd_destructors[index])(priv);  /* destroy */
00266                         clean = PR_FALSE;  /* unknown side effects */
00267                     }
00268                 }
00269             }
00270         } while ((--passes > 0) && !clean);  /* limit # of passes */
00271         /*
00272         ** We give up after a fixed number of passes. Any non-NULL
00273         ** thread-private data value with a registered destructor
00274         ** function is not destroyed.
00275         */
00276         memset(self->privateData, 0, self->tpdLength * sizeof(void*));
00277     }
00278 }  /* _PR_DestroyThreadPrivate */
00279 
00280 #endif /* !XP_BEOS */