LCOV - code coverage report
Current view: top level - nsprpub/pr/src/threads - prtpd.c (source / functions) Hit Total Coverage
Test: output.info Lines: 47 63 74.6 %
Date: 2017-07-14 16:53:18 Functions: 2 3 66.7 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13