LCOV - code coverage report
Current view: directory - nsprpub/pr/src/threads - prtpd.c (source / functions) Found Hit Coverage
Test: app.info Lines: 66 54 81.8 %
Date: 2012-06-02 Functions: 6 5 83.3 %

       1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is the Netscape Portable Runtime (NSPR).
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Netscape Communications Corporation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 1998-2000
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *
      24                 :  * Alternatively, the contents of this file may be used under the terms of
      25                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      26                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      27                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      28                 :  * of those above. If you wish to allow use of your version of this file only
      29                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      30                 :  * use your version of this file under the terms of the MPL, indicate your
      31                 :  * decision by deleting the provisions above and replace them with the notice
      32                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      33                 :  * the provisions above, a recipient may use your version of this file under
      34                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      35                 :  *
      36                 :  * ***** END LICENSE BLOCK ***** */
      37                 : 
      38                 : /*
      39                 : ** Thread Private Data
      40                 : **
      41                 : ** There is an aribitrary limit on the number of keys that will be allocated
      42                 : ** by the runtime. It's largish, so it is intended to be a sanity check, not
      43                 : ** an impediment.
      44                 : **
      45                 : ** There is a counter, initialized to zero and incremented every time a
      46                 : ** client asks for a new key, that holds the high water mark for keys. All
      47                 : ** threads logically have the same high water mark and are permitted to
      48                 : ** ask for TPD up to that key value.
      49                 : **
      50                 : ** The vector to hold the TPD are allocated when PR_SetThreadPrivate() is
      51                 : ** called. The size of the vector will be some value greater than or equal
      52                 : ** to the current high water mark. Each thread has its own TPD length and
      53                 : ** vector.
      54                 : **
      55                 : ** Threads that get private data for keys they have not set (or perhaps
      56                 : ** don't even exist for that thread) get a NULL return. If the key is
      57                 : ** beyond the high water mark, an error will be returned.
      58                 : */
      59                 : 
      60                 : /*
      61                 : ** As of this time, BeOS has its own TPD implementation.  Integrating
      62                 : ** this standard one is a TODO for anyone with a bit of spare time on
      63                 : ** their hand.  For now, we just #ifdef out this whole file and use
      64                 : ** the routines in pr/src/btthreads/
      65                 : */
      66                 : 
      67                 : #ifndef XP_BEOS
      68                 : 
      69                 : #include "primpl.h"
      70                 : 
      71                 : #include <string.h>
      72                 : 
      73                 : #if defined(WIN95)
      74                 : /*
      75                 : ** Some local variables report warnings on Win95 because the code paths 
      76                 : ** using them are conditioned on HAVE_CUSTOME_USER_THREADS.
      77                 : ** The pragma suppresses the warning.
      78                 : ** 
      79                 : */
      80                 : #pragma warning(disable : 4101)
      81                 : #endif
      82                 : 
      83                 : #define _PR_TPD_LIMIT 128               /* arbitary limit on the TPD slots */
      84                 : static PRInt32 _pr_tpd_length = 0;      /* current length of destructor vector */
      85                 : static PRInt32 _pr_tpd_highwater = 0;   /* next TPD key to be assigned */
      86                 : static PRThreadPrivateDTOR *_pr_tpd_destructors = NULL;
      87                 :                                         /* the destructors are associated with
      88                 :                                             the keys, therefore asserting that
      89                 :                                             the TPD key depicts the data's 'type' */
      90                 : 
      91                 : /*
      92                 : ** Initialize the thread private data manipulation
      93                 : */
      94           20034 : void _PR_InitTPD(void)
      95                 : {
      96           20034 :     _pr_tpd_destructors = (PRThreadPrivateDTOR*)
      97           20034 :         PR_CALLOC(_PR_TPD_LIMIT * sizeof(PRThreadPrivateDTOR*));
      98           20034 :     PR_ASSERT(NULL != _pr_tpd_destructors);
      99           20034 :     _pr_tpd_length = _PR_TPD_LIMIT;
     100           20034 : }
     101                 : 
     102                 : /*
     103                 : ** Clean up the thread private data manipulation
     104                 : */
     105               0 : void _PR_CleanupTPD(void)
     106                 : {
     107               0 : }  /* _PR_CleanupTPD */
     108                 : 
     109                 : /*
     110                 : ** This routine returns a new index for per-thread-private data table. 
     111                 : ** The index is visible to all threads within a process. This index can 
     112                 : ** be used with the PR_SetThreadPrivate() and PR_GetThreadPrivate() routines 
     113                 : ** to save and retrieve data associated with the index for a thread.
     114                 : **
     115                 : ** The index independently maintains specific values for each binding thread. 
     116                 : ** A thread can only get access to its own thread-specific-data.
     117                 : **
     118                 : ** Upon a new index return the value associated with the index for all threads
     119                 : ** is NULL, and upon thread creation the value associated with all indices for 
     120                 : ** that thread is NULL. 
     121                 : **
     122                 : **     "dtor" is the destructor function to invoke when the private
     123                 : **       data is set or destroyed
     124                 : **
     125                 : ** Returns PR_FAILURE if the total number of indices will exceed the maximun 
     126                 : ** allowed.
     127                 : */
     128                 : 
     129           47844 : PR_IMPLEMENT(PRStatus) PR_NewThreadPrivateIndex(
     130                 :     PRUintn *newIndex, PRThreadPrivateDTOR dtor)
     131                 : {
     132                 :     PRStatus rv;
     133                 :     PRInt32 index;
     134                 : 
     135           47844 :     if (!_pr_initialized) _PR_ImplicitInitialization();
     136                 : 
     137           47844 :     PR_ASSERT(NULL != newIndex);
     138           47844 :     PR_ASSERT(NULL != _pr_tpd_destructors);
     139                 : 
     140           47844 :     index = PR_ATOMIC_INCREMENT(&_pr_tpd_highwater) - 1;  /* allocate index */
     141           47844 :     if (_PR_TPD_LIMIT <= index)
     142                 :     {
     143               0 :         PR_SetError(PR_TPD_RANGE_ERROR, 0);
     144               0 :         rv = PR_FAILURE;  /* that's just wrong */
     145                 :     }
     146                 :     else
     147                 :     {
     148           47844 :         _pr_tpd_destructors[index] = dtor;  /* record destructor @index */
     149           47844 :         *newIndex = (PRUintn)index;  /* copy into client's location */
     150           47844 :         rv = PR_SUCCESS;  /* that's okay */
     151                 :     }
     152                 : 
     153           47844 :     return rv;
     154                 : }
     155                 : 
     156                 : /*
     157                 : ** Define some per-thread-private data.
     158                 : **     "index" is an index into the per-thread private data table
     159                 : **     "priv" is the per-thread-private data 
     160                 : **
     161                 : ** If the per-thread private data table has a previously registered
     162                 : ** destructor function and a non-NULL per-thread-private data value,
     163                 : ** the destructor function is invoked.
     164                 : **
     165                 : ** This can return PR_FAILURE if index is invalid (ie., beyond the current
     166                 : ** high water mark) or memory is insufficient to allocate an exanded vector.
     167                 : */
     168                 : 
     169        53460716 : PR_IMPLEMENT(PRStatus) PR_SetThreadPrivate(PRUintn index, void *priv)
     170                 : {
     171        53460716 :     PRThread *self = PR_GetCurrentThread();
     172                 : 
     173                 :     /*
     174                 :     ** The index being set might not have a sufficient vector in this
     175                 :     ** thread. But if the index has been allocated, it's okay to go
     176                 :     ** ahead and extend this one now.
     177                 :     */
     178        53460040 :     if ((index >= _PR_TPD_LIMIT) || (index >= _pr_tpd_highwater))
     179                 :     {
     180               0 :         PR_SetError(PR_TPD_RANGE_ERROR, 0);
     181               0 :         return PR_FAILURE;
     182                 :     }
     183                 : 
     184        53460096 :     PR_ASSERT(((NULL == self->privateData) && (0 == self->tpdLength))
     185                 :         || ((NULL != self->privateData) && (0 != self->tpdLength)));
     186                 : 
     187        53460392 :     if ((NULL == self->privateData) || (self->tpdLength <= index))
     188           29153 :     {
     189           29134 :         void *extension = PR_CALLOC(_pr_tpd_length * sizeof(void*));
     190           29153 :         if (NULL == extension)
     191                 :         {
     192               0 :             PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
     193               0 :             return PR_FAILURE;
     194                 :         }
     195           29153 :         if (self->privateData) {
     196               0 :             (void)memcpy(
     197               0 :                 extension, self->privateData,
     198               0 :                 self->tpdLength * sizeof(void*));
     199               0 :             PR_DELETE(self->privateData);
     200                 :         }
     201           29153 :         self->tpdLength = _pr_tpd_length;
     202           29153 :         self->privateData = (void**)extension;
     203                 :     }
     204                 :     /*
     205                 :     ** There wasn't much chance of having to call the destructor
     206                 :     ** unless the slot already existed.
     207                 :     */
     208        53431258 :     else if (self->privateData[index] && _pr_tpd_destructors[index])
     209                 :     {
     210           11116 :         void *data = self->privateData[index];
     211           11116 :         self->privateData[index] = NULL;
     212           11116 :         (*_pr_tpd_destructors[index])(data);
     213                 :     }
     214                 : 
     215        53460305 :     PR_ASSERT(index < self->tpdLength);
     216        53460305 :     self->privateData[index] = priv;
     217                 : 
     218        53460305 :     return PR_SUCCESS;
     219                 : }
     220                 : 
     221                 : /*
     222                 : ** Recover the per-thread-private data for the current thread. "index" is
     223                 : ** the index into the per-thread private data table. 
     224                 : **
     225                 : ** The returned value may be NULL which is indistinguishable from an error 
     226                 : ** condition.
     227                 : **
     228                 : */
     229                 : 
     230       340780859 : PR_IMPLEMENT(void*) PR_GetThreadPrivate(PRUintn index)
     231                 : {
     232       340780859 :     PRThread *self = PR_GetCurrentThread();
     233      1022234242 :     void *tpd = ((NULL == self->privateData) || (index >= self->tpdLength)) ?
     234       681484224 :         NULL : self->privateData[index];
     235                 : 
     236       340750018 :     return tpd;
     237                 : }
     238                 : 
     239                 : /*
     240                 : ** Destroy the thread's private data, if any exists. This is called at
     241                 : ** thread termination time only. There should be no threading issues
     242                 : ** since this is being called by the thread itself.
     243                 : */
     244           30602 : void _PR_DestroyThreadPrivate(PRThread* self)
     245                 : {
     246                 : #define _PR_TPD_DESTRUCTOR_ITERATIONS 4
     247                 : 
     248           30602 :     if (NULL != self->privateData)  /* we have some */
     249                 :     {
     250                 :         PRBool clean;
     251                 :         PRUint32 index;
     252            9282 :         PRInt32 passes = _PR_TPD_DESTRUCTOR_ITERATIONS;
     253            9282 :         PR_ASSERT(0 != self->tpdLength);
     254                 :         do
     255                 :         {
     256            9301 :             clean = PR_TRUE;
     257         1199829 :             for (index = 0; index < self->tpdLength; ++index)
     258                 :             {
     259         1190528 :                 void *priv = self->privateData[index];  /* extract */
     260         1190528 :                 if (NULL != priv)  /* we have data at this index */
     261                 :                 {
     262              27 :                     if (NULL != _pr_tpd_destructors[index])
     263                 :                     {
     264              27 :                         self->privateData[index] = NULL;  /* precondition */
     265              27 :                         (*_pr_tpd_destructors[index])(priv);  /* destroy */
     266              27 :                         clean = PR_FALSE;  /* unknown side effects */
     267                 :                     }
     268                 :                 }
     269                 :             }
     270            9301 :         } while ((--passes > 0) && !clean);  /* limit # of passes */
     271                 :         /*
     272                 :         ** We give up after a fixed number of passes. Any non-NULL
     273                 :         ** thread-private data value with a registered destructor
     274                 :         ** function is not destroyed.
     275                 :         */
     276            9282 :         memset(self->privateData, 0, self->tpdLength * sizeof(void*));
     277                 :     }
     278           30602 : }  /* _PR_DestroyThreadPrivate */
     279                 : 
     280                 : #endif /* !XP_BEOS */

Generated by: LCOV version 1.7