nsprpub/pr/src/threads/prtpd.c

changeset 0
6474c204b198
     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 */

mercurial