tracker.c
上传用户:lyxiangda
上传日期:2007-01-12
资源大小:3042k
文件大小:13k
源码类别:

CA认证

开发平台:

WINDOWS

  1. /* 
  2.  * The contents of this file are subject to the Mozilla Public
  3.  * License Version 1.1 (the "License"); you may not use this file
  4.  * except in compliance with the License. You may obtain a copy of
  5.  * the License at http://www.mozilla.org/MPL/
  6.  * 
  7.  * Software distributed under the License is distributed on an "AS
  8.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  9.  * implied. See the License for the specific language governing
  10.  * rights and limitations under the License.
  11.  * 
  12.  * The Original Code is the Netscape security libraries.
  13.  * 
  14.  * The Initial Developer of the Original Code is Netscape
  15.  * Communications Corporation.  Portions created by Netscape are 
  16.  * Copyright (C) 1994-2000 Netscape Communications Corporation.  All
  17.  * Rights Reserved.
  18.  * 
  19.  * Contributor(s):
  20.  * 
  21.  * Alternatively, the contents of this file may be used under the
  22.  * terms of the GNU General Public License Version 2 or later (the
  23.  * "GPL"), in which case the provisions of the GPL are applicable 
  24.  * instead of those above.  If you wish to allow use of your 
  25.  * version of this file only under the terms of the GPL and not to
  26.  * allow others to use your version of this file under the MPL,
  27.  * indicate your decision by deleting the provisions above and
  28.  * replace them with the notice and other provisions required by
  29.  * the GPL.  If you do not delete the provisions above, a recipient
  30.  * may use your version of this file under either the MPL or the
  31.  * GPL.
  32.  */
  33. #ifdef DEBUG
  34. static const char CVS_ID[] = "@(#) $RCSfile: tracker.c,v $ $Revision: 1.1 $ $Date: 2000/03/31 19:51:11 $ $Name: NSS_3_1_1_RTM $";
  35. #endif /* DEBUG */
  36. /*
  37.  * tracker.c
  38.  * 
  39.  * This file contains the code used by the pointer-tracking calls used
  40.  * in the debug builds to catch bad pointers.  The entire contents are
  41.  * only available in debug builds (both internal and external builds).
  42.  */
  43. #ifndef BASE_H
  44. #include "base.h"
  45. #endif /* BASE_H */
  46. #ifdef DEBUG
  47. /*
  48.  * call_once
  49.  *
  50.  * Unfortunately, NSPR's PR_CallOnce function doesn't accept a closure
  51.  * variable.  So I have a static version here which does.  This code 
  52.  * is based on NSPR's, and uses the NSPR function to initialize the
  53.  * required lock.
  54.  */
  55. /*
  56.  * The is the "once block" that's passed to the "real" PR_CallOnce
  57.  * function, to call the local initializer myOnceFunction once.
  58.  */
  59. static PRCallOnceType myCallOnce;
  60. /*
  61.  * This structure is used by the call_once function to make sure that
  62.  * any "other" threads calling the call_once don't return too quickly,
  63.  * before the initializer has finished.
  64.  */
  65. static struct {
  66.   PRLock *ml;
  67.   PRCondVar *cv;
  68. } mod_init;
  69. /*
  70.  * This is the initializer for the above mod_init structure.
  71.  */
  72. static PRStatus
  73. myOnceFunction
  74. (
  75.   void
  76. )
  77. {
  78.   mod_init.ml = PR_NewLock();
  79.   if( (PRLock *)NULL == mod_init.ml ) {
  80.     return PR_FAILURE;
  81.   }
  82.   mod_init.cv = PR_NewCondVar(mod_init.ml);
  83.   if( (PRCondVar *)NULL == mod_init.cv ) {
  84.     PR_DestroyLock(mod_init.ml);
  85.     mod_init.ml = (PRLock *)NULL;
  86.     return PR_FAILURE;
  87.   }
  88.   return PR_SUCCESS;
  89. }
  90. /*
  91.  * The nss call_once callback takes a closure argument.
  92.  */
  93. typedef PRStatus (PR_CALLBACK *nssCallOnceFN)(void *arg);
  94. /*
  95.  * NSS's call_once function.
  96.  */
  97. static PRStatus
  98. call_once
  99. (
  100.   PRCallOnceType *once,
  101.   nssCallOnceFN func,
  102.   void *arg
  103. )
  104. {
  105.   PRStatus rv;
  106.   if( !myCallOnce.initialized ) {
  107.     rv = PR_CallOnce(&myCallOnce, myOnceFunction);
  108.     if( PR_SUCCESS != rv ) {
  109.       return rv;
  110.     }
  111.   }
  112.   if( !once->initialized ) {
  113.     if( 0 == PR_AtomicSet(&once->inProgress, 1) ) {
  114.       once->status = (*func)(arg);
  115.       PR_Lock(mod_init.ml);
  116.       once->initialized = 1;
  117.       PR_NotifyAllCondVar(mod_init.cv);
  118.       PR_Unlock(mod_init.ml);
  119.     } else {
  120.       PR_Lock(mod_init.ml);
  121.       while( !once->initialized ) {
  122.         PR_WaitCondVar(mod_init.cv, PR_INTERVAL_NO_TIMEOUT);
  123.       }
  124.       PR_Unlock(mod_init.ml);
  125.     }
  126.   }
  127.   return once->status;
  128. }
  129. /*
  130.  * Now we actually get to my own "call once" payload function.
  131.  * But wait, to create the hash, I need a hash function!
  132.  */
  133. /*
  134.  * identity_hash
  135.  *
  136.  * This static callback is a PLHashFunction as defined in plhash.h
  137.  * It merely returns the value of the object pointer as its hash.
  138.  * There are no possible errors.
  139.  */
  140. static PR_CALLBACK PLHashNumber
  141. identity_hash
  142. (
  143.   const void *key
  144. )
  145. {
  146.   return (PLHashNumber)key;
  147. }
  148. /*
  149.  * trackerOnceFunc
  150.  *
  151.  * This function is called once, using the nssCallOnce function above.
  152.  * It creates a new pointer tracker object; initialising its hash
  153.  * table and protective lock.
  154.  */
  155. static PRStatus
  156. trackerOnceFunc
  157. (
  158.   void *arg
  159. )
  160. {
  161.   nssPointerTracker *tracker = (nssPointerTracker *)arg;
  162.   tracker->lock = PR_NewLock();
  163.   if( (PRLock *)NULL == tracker->lock ) {
  164.     return PR_FAILURE;
  165.   }
  166.   tracker->table = PL_NewHashTable(0, 
  167.                                    identity_hash, 
  168.                                    PL_CompareValues,
  169.                                    PL_CompareValues,
  170.                                    (PLHashAllocOps *)NULL, 
  171.                                    (void *)NULL);
  172.   if( (PLHashTable *)NULL == tracker->table ) {
  173.     PR_DestroyLock(tracker->lock);
  174.     tracker->lock = (PRLock *)NULL;
  175.     return PR_FAILURE;
  176.   }
  177.   return PR_SUCCESS;
  178. }
  179. /*
  180.  * nssPointerTracker_initialize
  181.  *
  182.  * This method is only present in debug builds.
  183.  * 
  184.  * This routine initializes an nssPointerTracker object.  Note that
  185.  * the object must have been declared *static* to guarantee that it
  186.  * is in a zeroed state initially.  This routine is idempotent, and
  187.  * may even be safely called by multiple threads simultaneously with 
  188.  * the same argument.  This routine returns a PRStatus value; if 
  189.  * successful, it will return PR_SUCCESS.  On failure it will set an 
  190.  * error on the error stack and return PR_FAILURE.
  191.  *
  192.  * The error may be one of the following values:
  193.  *  NSS_ERROR_NO_MEMORY
  194.  *
  195.  * Return value:
  196.  *  PR_SUCCESS
  197.  *  PR_FAILURE
  198.  */
  199. NSS_IMPLEMENT PRStatus
  200. nssPointerTracker_initialize
  201. (
  202.   nssPointerTracker *tracker
  203. )
  204. {
  205.   PRStatus rv = call_once(&tracker->once, trackerOnceFunc, tracker);
  206.   if( PR_SUCCESS != rv ) {
  207.     nss_SetError(NSS_ERROR_NO_MEMORY);
  208.   }
  209.   return rv;
  210. }
  211. #ifdef DONT_DESTROY_EMPTY_TABLES
  212. /* See same #ifdef below */
  213. /*
  214.  * count_entries
  215.  *
  216.  * This static routine is a PLHashEnumerator, as defined in plhash.h.
  217.  * It merely causes the enumeration function to count the number of
  218.  * entries.
  219.  */
  220. static PR_CALLBACK PRIntn
  221. count_entries
  222. (
  223.   PLHashEntry *he,
  224.   PRIntn index,
  225.   void *arg
  226. )
  227. {
  228.   return HT_ENUMERATE_NEXT;
  229. }
  230. #endif /* DONT_DESTROY_EMPTY_TABLES */
  231. /*
  232.  * zero_once
  233.  *
  234.  * This is a guaranteed zeroed once block.  It's used to help clear
  235.  * the tracker.
  236.  */
  237. static const PRCallOnceType zero_once;
  238. /*
  239.  * nssPointerTracker_finalize
  240.  *
  241.  * This method is only present in debug builds.
  242.  * 
  243.  * This routine returns the nssPointerTracker object to the pre-
  244.  * initialized state, releasing all resources used by the object.
  245.  * It will *NOT* destroy the objects being tracked by the pointer
  246.  * (should any remain), and therefore cannot be used to "sweep up"
  247.  * remaining objects.  This routine returns a PRStatus value; if
  248.  * successful, it will return PR_SUCCES.  On failure it will set an
  249.  * error on the error stack and return PR_FAILURE.  If any objects
  250.  * remain in the tracker when it is finalized, that will be treated
  251.  * as an error.
  252.  *
  253.  * The error may be one of the following values:
  254.  *  NSS_ERROR_INVALID_POINTER
  255.  *  NSS_ERROR_TRACKER_NOT_INITIALIZED
  256.  *  NSS_ERROR_TRACKER_NOT_EMPTY
  257.  *
  258.  * Return value:
  259.  *  PR_SUCCESS
  260.  *  PR_FAILURE
  261.  */
  262. NSS_IMPLEMENT PRStatus
  263. nssPointerTracker_finalize
  264. (
  265.   nssPointerTracker *tracker
  266. )
  267. {
  268.   PRLock *lock;
  269.   PRIntn count;
  270.   if( (nssPointerTracker *)NULL == tracker ) {
  271.     nss_SetError(NSS_ERROR_INVALID_POINTER);
  272.     return PR_FAILURE;
  273.   }
  274.   if( (PRLock *)NULL == tracker->lock ) {
  275.     nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED);
  276.     return PR_FAILURE;
  277.   }
  278.   lock = tracker->lock;
  279.   PR_Lock(lock);
  280.   if( (PLHashTable *)NULL == tracker->table ) {
  281.     PR_Unlock(lock);
  282.     nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED);
  283.     return PR_FAILURE;
  284.   }
  285. #ifdef DONT_DESTROY_EMPTY_TABLES
  286.   /*
  287.    * I changed my mind; I think we don't want this after all.
  288.    * Comments?
  289.    */
  290.   count = PL_HashTableEnumerateEntries(tracker->table, 
  291.                                        count_entries,
  292.                                        (void *)NULL);
  293.   if( 0 != count ) {
  294.     PR_Unlock(lock);
  295.     nss_SetError(NSS_ERROR_TRACKER_NOT_EMPTY);
  296.     return PR_FAILURE;
  297.   }
  298. #endif /* DONT_DESTROY_EMPTY_TABLES */
  299.   PL_HashTableDestroy(tracker->table);
  300.   /* memset(tracker, 0, sizeof(nssPointerTracker)); */
  301.   tracker->once = zero_once;
  302.   tracker->lock = (PRLock *)NULL;
  303.   tracker->table = (PLHashTable *)NULL;
  304.   PR_Unlock(lock);
  305.   PR_DestroyLock(lock);
  306.   return PR_SUCCESS;
  307. }
  308. /*
  309.  * nssPointerTracker_add
  310.  *
  311.  * This method is only present in debug builds.
  312.  *
  313.  * This routine adds the specified pointer to the nssPointerTracker
  314.  * object.  It should be called in constructor objects to register
  315.  * new valid objects.  The nssPointerTracker is threadsafe, but this
  316.  * call is not idempotent.  This routine returns a PRStatus value;
  317.  * if successful it will return PR_SUCCESS.  On failure it will set
  318.  * an error on the error stack and return PR_FAILURE.
  319.  *
  320.  * The error may be one of the following values:
  321.  *  NSS_ERROR_INVALID_POINTER
  322.  *  NSS_ERROR_NO_MEMORY
  323.  *  NSS_ERROR_TRACKER_NOT_INITIALIZED
  324.  *  NSS_ERROR_DUPLICATE_POINTER
  325.  *
  326.  * Return value:
  327.  *  PR_SUCCESS
  328.  *  PR_FAILURE
  329.  */
  330. NSS_IMPLEMENT PRStatus
  331. nssPointerTracker_add
  332. (
  333.   nssPointerTracker *tracker,
  334.   const void *pointer
  335. )
  336. {
  337.   void *check;
  338.   PLHashEntry *entry;
  339.   if( (nssPointerTracker *)NULL == tracker ) {
  340.     nss_SetError(NSS_ERROR_INVALID_POINTER);
  341.     return PR_FAILURE;
  342.   }
  343.   if( (PRLock *)NULL == tracker->lock ) {
  344.     nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED);
  345.     return PR_FAILURE;
  346.   }
  347.   PR_Lock(tracker->lock);
  348.   if( (PLHashTable *)NULL == tracker->table ) {
  349.     PR_Unlock(tracker->lock);
  350.     nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED);
  351.     return PR_FAILURE;
  352.   }
  353.   check = PL_HashTableLookup(tracker->table, pointer);
  354.   if( (void *)NULL != check ) {
  355.     PR_Unlock(tracker->lock);
  356.     nss_SetError(NSS_ERROR_DUPLICATE_POINTER);
  357.     return PR_FAILURE;
  358.   }
  359.   entry = PL_HashTableAdd(tracker->table, pointer, (void *)pointer);
  360.   PR_Unlock(tracker->lock);
  361.   if( (PLHashEntry *)NULL == entry ) {
  362.     nss_SetError(NSS_ERROR_NO_MEMORY);
  363.     return PR_FAILURE;
  364.   }
  365.   return PR_SUCCESS;
  366. }
  367.   
  368. /*
  369.  * nssPointerTracker_remove
  370.  *
  371.  * This method is only present in debug builds.
  372.  *
  373.  * This routine removes the specified pointer from the 
  374.  * nssPointerTracker object.  It does not call any destructor for the
  375.  * object; rather, this should be called from the object's destructor.
  376.  * The nssPointerTracker is threadsafe, but this call is not 
  377.  * idempotent.  This routine returns a PRStatus value; if successful 
  378.  * it will return PR_SUCCESS.  On failure it will set an error on the 
  379.  * error stack and return PR_FAILURE.
  380.  *
  381.  * The error may be one of the following values:
  382.  *  NSS_ERROR_INVALID_POINTER
  383.  *  NSS_ERROR_TRACKER_NOT_INITIALIZED
  384.  *  NSS_ERROR_POINTER_NOT_REGISTERED
  385.  *
  386.  * Return value:
  387.  *  PR_SUCCESS
  388.  *  PR_FAILURE
  389.  */
  390. NSS_IMPLEMENT PRStatus
  391. nssPointerTracker_remove
  392. (
  393.   nssPointerTracker *tracker,
  394.   const void *pointer
  395. )
  396. {
  397.   PRBool registered;
  398.   if( (nssPointerTracker *)NULL == tracker ) {
  399.     nss_SetError(NSS_ERROR_INVALID_POINTER);
  400.     return PR_FAILURE;
  401.   }
  402.   if( (PRLock *)NULL == tracker->lock ) {
  403.     nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED);
  404.     return PR_FAILURE;
  405.   }
  406.   PR_Lock(tracker->lock);
  407.   if( (PLHashTable *)NULL == tracker->table ) {
  408.     PR_Unlock(tracker->lock);
  409.     nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED);
  410.     return PR_FAILURE;
  411.   }
  412.   registered = PL_HashTableRemove(tracker->table, pointer);
  413.   PR_Unlock(tracker->lock);
  414.   if( !registered ) {
  415.     nss_SetError(NSS_ERROR_POINTER_NOT_REGISTERED);
  416.     return PR_FAILURE;
  417.   }
  418.   return PR_SUCCESS;
  419. }
  420. /*
  421.  * nssPointerTracker_verify
  422.  *
  423.  * This method is only present in debug builds.
  424.  *
  425.  * This routine verifies that the specified pointer has been registered
  426.  * with the nssPointerTracker object.  The nssPointerTracker object is
  427.  * threadsafe, and this call may be safely called from multiple threads
  428.  * simultaneously with the same arguments.  This routine returns a
  429.  * PRStatus value; if the pointer is registered this will return 
  430.  * PR_SUCCESS.  Otherwise it will set an error on the error stack and 
  431.  * return PR_FAILURE.  Although the error is suitable for leaving on 
  432.  * the stack, callers may wish to augment the information available by 
  433.  * placing a more type-specific error on the stack.
  434.  *
  435.  * The error may be one of the following values:
  436.  *  NSS_ERROR_INVALID_POINTER
  437.  *  NSS_ERROR_TRACKER_NOT_INITIALIZED
  438.  *  NSS_ERROR_POINTER_NOT_REGISTERED
  439.  *
  440.  * Return value:
  441.  *  PR_SUCCESS
  442.  *  PR_FAILRUE
  443.  */
  444. NSS_IMPLEMENT PRStatus
  445. nssPointerTracker_verify
  446. (
  447.   nssPointerTracker *tracker,
  448.   const void *pointer
  449. )
  450. {
  451.   void *check;
  452.   if( (nssPointerTracker *)NULL == tracker ) {
  453.     nss_SetError(NSS_ERROR_INVALID_POINTER);
  454.     return PR_FAILURE;
  455.   }
  456.   if( (PRLock *)NULL == tracker->lock ) {
  457.     nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED);
  458.     return PR_FAILURE;
  459.   }
  460.   PR_Lock(tracker->lock);
  461.   if( (PLHashTable *)NULL == tracker->table ) {
  462.     PR_Unlock(tracker->lock);
  463.     nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED);
  464.     return PR_FAILURE;
  465.   }
  466.   check = PL_HashTableLookup(tracker->table, pointer);
  467.   PR_Unlock(tracker->lock);
  468.   if( (void *)NULL == check ) {
  469.     nss_SetError(NSS_ERROR_POINTER_NOT_REGISTERED);
  470.     return PR_FAILURE;
  471.   }
  472.   return PR_SUCCESS;
  473. }
  474. #endif /* DEBUG */