home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / nsprpub / pr / src / threads / prtpd.c < prev   
Encoding:
C/C++ Source or Header  |  1998-04-08  |  9.6 KB  |  297 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /*
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  * 
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  * 
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. #include "primpl.h"
  20.  
  21. #include <string.h>
  22.  
  23. /*
  24. ** Thread Private Data
  25. **
  26. ** There is an aribitrary limit on the number of keys that will be allocated
  27. ** by the runtime. It's largish, so it is intended to be a sanity check, not
  28. ** an impediment.
  29. **
  30. ** There is a counter, initialized to zero and incremented every time a
  31. ** client asks for a new key, that holds the high water mark for keys. All
  32. ** threads logically have the same high water mark and are permitted to
  33. ** ask for TPD up to that key value.
  34. **
  35. ** The vector to hold the TPD are allocated when PR_SetThreadPrivate() is
  36. ** called. The size of the vector will be some value greater than or equal
  37. ** to the current high water mark. Each thread has its own TPD length and
  38. ** vector.
  39. **
  40. ** Threads that get private data for keys they have not set (or perhaps
  41. ** don't even exist for that thread) get a NULL return. If the key is
  42. ** beyond the high water mark, an error will be returned.
  43. */
  44.  
  45. #define _PR_TPD_MODULO 8                /* vectors are extended by this much */
  46. #define _PR_TPD_LIMIT 128               /* arbitary limit on the TPD slots */
  47. static PRUintn _pr_tpd_highwater = 0;   /* next TPD key to be assigned */
  48. static PRUintn _pr_tpd_length = 0;      /* current length of destructor vector */
  49. PRThreadPrivateDTOR *_pr_tpd_destructors = NULL;
  50.                                         /* the destructors are associated with
  51.                                             the keys, therefore asserting that
  52.                                             the TPD key depicts the data's 'type' */
  53.  
  54. /* Lock protecting the index assignment of per-thread-private data table */
  55. #ifdef _PR_NO_PREEMPT
  56. #define _PR_NEW_LOCK_TPINDEX()
  57. #define _PR_FREE_LOCK_TPINDEX()
  58. #define _PR_LOCK_TPINDEX()
  59. #define _PR_UNLOCK_TPINDEX()
  60. #else
  61. #ifdef _PR_LOCAL_THREADS_ONLY
  62. #define _PR_NEW_LOCK_TPINDEX()
  63. #define _PR_FREE_LOCK_TPINDEX()
  64. #define _PR_LOCK_TPINDEX() _PR_INTSOFF(_is)
  65. #define _PR_UNLOCK_TPINDEX() _PR_INTSON(_is)
  66. #else
  67. static PRLock *_pr_threadPrivateIndexLock;
  68. #define _PR_NEW_LOCK_TPINDEX() (_pr_threadPrivateIndexLock = PR_NewLock())
  69. #define _PR_FREE_LOCK_TPINDEX() (PR_DestroyLock(_pr_threadPrivateIndexLock))
  70. #define _PR_LOCK_TPINDEX() PR_Lock(_pr_threadPrivateIndexLock)
  71. #define _PR_UNLOCK_TPINDEX() PR_Unlock(_pr_threadPrivateIndexLock)
  72. #endif
  73. #endif
  74.  
  75. /*
  76. ** Initialize the thread private data manipulation
  77. */
  78. void _PR_InitTPD()
  79. {
  80.     _PR_NEW_LOCK_TPINDEX();
  81. }
  82.  
  83. /*
  84. ** Clean up the thread private data manipulation
  85. */
  86. void _PR_CleanupTPD(void)
  87. {
  88.     _PR_FREE_LOCK_TPINDEX();
  89. }
  90.  
  91. /*
  92. ** This routine returns a new index for per-thread-private data table. 
  93. ** The index is visible to all threads within a process. This index can 
  94. ** be used with the PR_SetThreadPrivate() and PR_GetThreadPrivate() routines 
  95. ** to save and retrieve data associated with the index for a thread.
  96. **
  97. ** The index independently maintains specific values for each binding thread. 
  98. ** A thread can only get access to its own thread-specific-data.
  99. **
  100. ** Upon a new index return the value associated with the index for all threads
  101. ** is NULL, and upon thread creation the value associated with all indices for 
  102. ** that thread is NULL. 
  103. **
  104. **     "dtor" is the destructor function to invoke when the private
  105. **       data is destroyed
  106. **
  107. ** Returns PR_FAILURE if the total number of indices will exceed the maximun 
  108. ** allowed.
  109. */
  110.  
  111. PR_IMPLEMENT(PRStatus) PR_NewThreadPrivateIndex(
  112.     PRUintn *newIndex, PRThreadPrivateDTOR dtor)
  113. {
  114.     PRStatus rv;
  115.  
  116.     if (!_pr_initialized) _PR_ImplicitInitialization();
  117.  
  118.  
  119.     if (_pr_tpd_highwater >= _PR_TPD_LIMIT)
  120.     {
  121.         PR_SetError(PR_TPD_RANGE_ERROR, 0);
  122.         rv = PR_FAILURE;  /* that's just wrong */
  123.     }
  124.     else
  125.     {
  126.         PRThreadPrivateDTOR *old = NULL;
  127.         PRIntn _is;
  128.  
  129.         _PR_LOCK_TPINDEX();
  130.         if (_pr_tpd_highwater >= _pr_tpd_length)
  131.         {
  132.             old = _pr_tpd_destructors;
  133.             _pr_tpd_destructors = PR_CALLOC(
  134.                 (_pr_tpd_length + _PR_TPD_MODULO) * sizeof(PRThreadPrivateDTOR*));
  135.             if (NULL == _pr_tpd_destructors)
  136.             {
  137.                 _pr_tpd_destructors = old; old = NULL;
  138.                 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
  139.                 rv = PR_FAILURE;  /* that's just wrong */
  140.                 goto failed;  /* then extract one's self */
  141.             }
  142.             else
  143.             {
  144.                 memcpy(
  145.                     _pr_tpd_destructors, old,
  146.                     _pr_tpd_length * sizeof(PRThreadPrivateDTOR*));
  147.                 _pr_tpd_length += _PR_TPD_MODULO;
  148.             }
  149.         }
  150.         
  151.         *newIndex = _pr_tpd_highwater++;  /* this is really all we wanted */
  152.         _pr_tpd_destructors[*newIndex] = dtor;  /* record destructor @index */
  153.  
  154. failed:
  155.         _PR_UNLOCK_TPINDEX();
  156.         if (NULL != old) PR_DELETE(old);
  157.         rv = PR_SUCCESS;
  158.     }
  159.  
  160.     return rv;
  161. }
  162.  
  163. /*
  164. ** Define some per-thread-private data.
  165. **     "index" is an index into the per-thread private data table
  166. **     "priv" is the per-thread-private data 
  167. **
  168. ** If the per-thread private data table has a previously registered
  169. ** destructor function and a non-NULL per-thread-private data value,
  170. ** the destructor function is invoked.
  171. **
  172. ** This can return PR_FAILURE if index is invalid (ie., beyond the current
  173. ** high water mark) or memory is insufficient to allocate an exanded vector.
  174. */
  175.  
  176. PR_IMPLEMENT(PRStatus) PR_SetThreadPrivate(PRUintn index, void *priv)
  177. {
  178.     PRStatus rv = PR_SUCCESS;
  179.     PRThread *self = PR_GetCurrentThread();
  180.  
  181.     /*
  182.     ** The index being set might not have a sufficient vector in this
  183.     ** thread. But if the index has been allocated, it's okay to go
  184.     ** ahead and extend this one now.
  185.     */
  186.     if (index >= _pr_tpd_highwater)
  187.     {
  188.         PR_ASSERT(index < _pr_tpd_highwater);
  189.         PR_SetError(PR_TPD_RANGE_ERROR, 0);
  190.         rv = PR_FAILURE;
  191.     }
  192.     else
  193.     {
  194.         PRIntn _is;
  195.  
  196.         _PR_LOCK_TPINDEX();
  197.         if ((NULL == self->privateData) || (self->tpdLength <= index))
  198.         {
  199.             void *extension = PR_CALLOC(_pr_tpd_length * sizeof(void*));
  200.             PR_ASSERT(
  201.                 ((NULL == self->privateData) && (0 == self->tpdLength))
  202.                 || ((NULL != self->privateData) && (0 != self->tpdLength)));
  203.             if (NULL != extension)
  204.             {
  205.                 (void)memcpy(
  206.                     extension, self->privateData,
  207.                     self->tpdLength * sizeof(void*));
  208.                 self->tpdLength = _pr_tpd_length;
  209.                 self->privateData = extension;
  210.             }
  211.         }
  212.         /*
  213.         ** There wasn't much chance of having to call the destructor
  214.         ** unless the slot already existed.
  215.         */
  216.         else if (self->privateData[index] && _pr_tpd_destructors[index])
  217.         {
  218.             void *data = self->privateData[index];
  219.             self->privateData[index] = NULL;
  220.             _PR_UNLOCK_TPINDEX();
  221.             (*_pr_tpd_destructors[index])(data);
  222.             _PR_LOCK_TPINDEX();
  223.         }
  224.  
  225.         /*
  226.         ** If the thread's private data is still NULL, then we couldn't
  227.         ** fix the problem. We must be outa-memory (again).
  228.         */
  229.         if (NULL == self->privateData)
  230.         {
  231.             PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
  232.             rv = PR_FAILURE;
  233.         }
  234.         else self->privateData[index] = priv;
  235.         _PR_UNLOCK_TPINDEX();
  236.     }
  237.  
  238.     return rv;
  239. }
  240.  
  241. /*
  242. ** Recover the per-thread-private data for the current thread. "index" is
  243. ** the index into the per-thread private data table. 
  244. **
  245. ** The returned value may be NULL which is indistinguishable from an error 
  246. ** condition.
  247. **
  248. */
  249.  
  250. PR_IMPLEMENT(void*) PR_GetThreadPrivate(uintn index)
  251. {
  252.     PRThread *self = PR_GetCurrentThread();
  253.     void *tpd = ((NULL == self->privateData) || (index >= self->tpdLength)) ?
  254.         NULL : self->privateData[index];
  255.  
  256.     return tpd;
  257. }
  258.  
  259. PR_IMPLEMENT(PRStatus) PR_SetThreadExit(PRUintn index, PRThreadExit func, void *arg)
  260. {
  261.     _PRPerThreadExit *pte;
  262.     PRThread *thread = _PR_MD_CURRENT_THREAD();
  263.  
  264.     if (index >= thread->numExits) {
  265.     if (thread->ptes) {
  266.         thread->ptes = (_PRPerThreadExit*)
  267.         PR_REALLOC(thread->ptes, (index+1) * sizeof(_PRPerThreadExit));
  268.     } else {
  269.         thread->ptes = (_PRPerThreadExit*)
  270.             PR_CALLOC(index+1 * sizeof(_PRPerThreadExit));
  271.     }
  272.     if (!thread->ptes) {
  273.         PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
  274.         return PR_FAILURE;
  275.     }
  276.     thread->numExits = index + 1;
  277.     }
  278.     pte = &thread->ptes[index];
  279.     pte->func = func;
  280.     pte->arg = arg;
  281.     return PR_SUCCESS;
  282. }
  283.  
  284. PR_IMPLEMENT(PRThreadExit) PR_GetThreadExit(PRUintn index, void **argp)
  285. {
  286.     _PRPerThreadExit *pte;
  287.     PRThread *thread = _PR_MD_CURRENT_THREAD();
  288.  
  289.     if (index >= thread->numExits) {
  290.     if (argp) *argp = 0;
  291.     return 0;
  292.     }
  293.     pte = &thread->ptes[index];
  294.     if (argp) *argp = pte->arg;
  295.     return pte->func;
  296. }
  297.