tracker.c

来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 545 行

C
545
字号
/*  * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ *  * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. *  * The Original Code is the Netscape security libraries. *  * The Initial Developer of the Original Code is Netscape * Communications Corporation.  Portions created by Netscape are  * Copyright (C) 1994-2000 Netscape Communications Corporation.  All * Rights Reserved. *  * Contributor(s): *  * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL"), in which case the provisions of the GPL are applicable  * instead of those above.  If you wish to allow use of your  * version of this file only under the terms of the GPL and not to * allow others to use your version of this file under the MPL, * indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by * the GPL.  If you do not delete the provisions above, a recipient * may use your version of this file under either the MPL or the * GPL. */#ifdef DEBUGstatic const char CVS_ID[] = "@(#) $RCSfile: tracker.c,v $ $Revision: 1.1 $ $Date: 2000/03/31 19:51:11 $ $Name: NSS_3_1_1_RTM $";#endif /* DEBUG *//* * tracker.c *  * This file contains the code used by the pointer-tracking calls used * in the debug builds to catch bad pointers.  The entire contents are * only available in debug builds (both internal and external builds). */#ifndef BASE_H#include "base.h"#endif /* BASE_H */#ifdef DEBUG/* * call_once * * Unfortunately, NSPR's PR_CallOnce function doesn't accept a closure * variable.  So I have a static version here which does.  This code  * is based on NSPR's, and uses the NSPR function to initialize the * required lock. *//* * The is the "once block" that's passed to the "real" PR_CallOnce * function, to call the local initializer myOnceFunction once. */static PRCallOnceType myCallOnce;/* * This structure is used by the call_once function to make sure that * any "other" threads calling the call_once don't return too quickly, * before the initializer has finished. */static struct {  PRLock *ml;  PRCondVar *cv;} mod_init;/* * This is the initializer for the above mod_init structure. */static PRStatusmyOnceFunction(  void){  mod_init.ml = PR_NewLock();  if( (PRLock *)NULL == mod_init.ml ) {    return PR_FAILURE;  }  mod_init.cv = PR_NewCondVar(mod_init.ml);  if( (PRCondVar *)NULL == mod_init.cv ) {    PR_DestroyLock(mod_init.ml);    mod_init.ml = (PRLock *)NULL;    return PR_FAILURE;  }  return PR_SUCCESS;}/* * The nss call_once callback takes a closure argument. */typedef PRStatus (PR_CALLBACK *nssCallOnceFN)(void *arg);/* * NSS's call_once function. */static PRStatuscall_once(  PRCallOnceType *once,  nssCallOnceFN func,  void *arg){  PRStatus rv;  if( !myCallOnce.initialized ) {    rv = PR_CallOnce(&myCallOnce, myOnceFunction);    if( PR_SUCCESS != rv ) {      return rv;    }  }  if( !once->initialized ) {    if( 0 == PR_AtomicSet(&once->inProgress, 1) ) {      once->status = (*func)(arg);      PR_Lock(mod_init.ml);      once->initialized = 1;      PR_NotifyAllCondVar(mod_init.cv);      PR_Unlock(mod_init.ml);    } else {      PR_Lock(mod_init.ml);      while( !once->initialized ) {        PR_WaitCondVar(mod_init.cv, PR_INTERVAL_NO_TIMEOUT);      }      PR_Unlock(mod_init.ml);    }  }  return once->status;}/* * Now we actually get to my own "call once" payload function. * But wait, to create the hash, I need a hash function! *//* * identity_hash * * This static callback is a PLHashFunction as defined in plhash.h * It merely returns the value of the object pointer as its hash. * There are no possible errors. */static PR_CALLBACK PLHashNumberidentity_hash(  const void *key){  return (PLHashNumber)key;}/* * trackerOnceFunc * * This function is called once, using the nssCallOnce function above. * It creates a new pointer tracker object; initialising its hash * table and protective lock. */static PRStatustrackerOnceFunc(  void *arg){  nssPointerTracker *tracker = (nssPointerTracker *)arg;  tracker->lock = PR_NewLock();  if( (PRLock *)NULL == tracker->lock ) {    return PR_FAILURE;  }  tracker->table = PL_NewHashTable(0,                                    identity_hash,                                    PL_CompareValues,                                   PL_CompareValues,                                   (PLHashAllocOps *)NULL,                                    (void *)NULL);  if( (PLHashTable *)NULL == tracker->table ) {    PR_DestroyLock(tracker->lock);    tracker->lock = (PRLock *)NULL;    return PR_FAILURE;  }  return PR_SUCCESS;}/* * nssPointerTracker_initialize * * This method is only present in debug builds. *  * This routine initializes an nssPointerTracker object.  Note that * the object must have been declared *static* to guarantee that it * is in a zeroed state initially.  This routine is idempotent, and * may even be safely called by multiple threads simultaneously with  * the same argument.  This routine returns a PRStatus value; if  * successful, it will return PR_SUCCESS.  On failure it will set an  * error on the error stack and return PR_FAILURE. * * The error may be one of the following values: *  NSS_ERROR_NO_MEMORY * * Return value: *  PR_SUCCESS *  PR_FAILURE */NSS_IMPLEMENT PRStatusnssPointerTracker_initialize(  nssPointerTracker *tracker){  PRStatus rv = call_once(&tracker->once, trackerOnceFunc, tracker);  if( PR_SUCCESS != rv ) {    nss_SetError(NSS_ERROR_NO_MEMORY);  }  return rv;}#ifdef DONT_DESTROY_EMPTY_TABLES/* See same #ifdef below *//* * count_entries * * This static routine is a PLHashEnumerator, as defined in plhash.h. * It merely causes the enumeration function to count the number of * entries. */static PR_CALLBACK PRIntncount_entries(  PLHashEntry *he,  PRIntn index,  void *arg){  return HT_ENUMERATE_NEXT;}#endif /* DONT_DESTROY_EMPTY_TABLES *//* * zero_once * * This is a guaranteed zeroed once block.  It's used to help clear * the tracker. */static const PRCallOnceType zero_once;/* * nssPointerTracker_finalize * * This method is only present in debug builds. *  * This routine returns the nssPointerTracker object to the pre- * initialized state, releasing all resources used by the object. * It will *NOT* destroy the objects being tracked by the pointer * (should any remain), and therefore cannot be used to "sweep up" * remaining objects.  This routine returns a PRStatus value; if * successful, it will return PR_SUCCES.  On failure it will set an * error on the error stack and return PR_FAILURE.  If any objects * remain in the tracker when it is finalized, that will be treated * as an error. * * The error may be one of the following values: *  NSS_ERROR_INVALID_POINTER *  NSS_ERROR_TRACKER_NOT_INITIALIZED *  NSS_ERROR_TRACKER_NOT_EMPTY * * Return value: *  PR_SUCCESS *  PR_FAILURE */NSS_IMPLEMENT PRStatusnssPointerTracker_finalize(  nssPointerTracker *tracker){  PRLock *lock;  PRIntn count;  if( (nssPointerTracker *)NULL == tracker ) {    nss_SetError(NSS_ERROR_INVALID_POINTER);    return PR_FAILURE;  }  if( (PRLock *)NULL == tracker->lock ) {    nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED);    return PR_FAILURE;  }  lock = tracker->lock;  PR_Lock(lock);  if( (PLHashTable *)NULL == tracker->table ) {    PR_Unlock(lock);    nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED);    return PR_FAILURE;  }#ifdef DONT_DESTROY_EMPTY_TABLES  /*   * I changed my mind; I think we don't want this after all.   * Comments?   */  count = PL_HashTableEnumerateEntries(tracker->table,                                        count_entries,                                       (void *)NULL);  if( 0 != count ) {    PR_Unlock(lock);    nss_SetError(NSS_ERROR_TRACKER_NOT_EMPTY);    return PR_FAILURE;  }#endif /* DONT_DESTROY_EMPTY_TABLES */  PL_HashTableDestroy(tracker->table);  /* memset(tracker, 0, sizeof(nssPointerTracker)); */  tracker->once = zero_once;  tracker->lock = (PRLock *)NULL;  tracker->table = (PLHashTable *)NULL;  PR_Unlock(lock);  PR_DestroyLock(lock);  return PR_SUCCESS;}/* * nssPointerTracker_add * * This method is only present in debug builds. * * This routine adds the specified pointer to the nssPointerTracker * object.  It should be called in constructor objects to register * new valid objects.  The nssPointerTracker is threadsafe, but this * call is not idempotent.  This routine returns a PRStatus value; * if successful it will return PR_SUCCESS.  On failure it will set * an error on the error stack and return PR_FAILURE. * * The error may be one of the following values: *  NSS_ERROR_INVALID_POINTER *  NSS_ERROR_NO_MEMORY *  NSS_ERROR_TRACKER_NOT_INITIALIZED *  NSS_ERROR_DUPLICATE_POINTER * * Return value: *  PR_SUCCESS *  PR_FAILURE */NSS_IMPLEMENT PRStatusnssPointerTracker_add(  nssPointerTracker *tracker,  const void *pointer){  void *check;  PLHashEntry *entry;  if( (nssPointerTracker *)NULL == tracker ) {    nss_SetError(NSS_ERROR_INVALID_POINTER);    return PR_FAILURE;  }  if( (PRLock *)NULL == tracker->lock ) {    nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED);    return PR_FAILURE;  }  PR_Lock(tracker->lock);  if( (PLHashTable *)NULL == tracker->table ) {    PR_Unlock(tracker->lock);    nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED);    return PR_FAILURE;  }  check = PL_HashTableLookup(tracker->table, pointer);  if( (void *)NULL != check ) {    PR_Unlock(tracker->lock);    nss_SetError(NSS_ERROR_DUPLICATE_POINTER);    return PR_FAILURE;  }  entry = PL_HashTableAdd(tracker->table, pointer, (void *)pointer);  PR_Unlock(tracker->lock);  if( (PLHashEntry *)NULL == entry ) {    nss_SetError(NSS_ERROR_NO_MEMORY);    return PR_FAILURE;  }  return PR_SUCCESS;}  /* * nssPointerTracker_remove * * This method is only present in debug builds. * * This routine removes the specified pointer from the  * nssPointerTracker object.  It does not call any destructor for the * object; rather, this should be called from the object's destructor. * The nssPointerTracker is threadsafe, but this call is not  * idempotent.  This routine returns a PRStatus value; if successful  * it will return PR_SUCCESS.  On failure it will set an error on the  * error stack and return PR_FAILURE. * * The error may be one of the following values: *  NSS_ERROR_INVALID_POINTER *  NSS_ERROR_TRACKER_NOT_INITIALIZED *  NSS_ERROR_POINTER_NOT_REGISTERED * * Return value: *  PR_SUCCESS *  PR_FAILURE */NSS_IMPLEMENT PRStatusnssPointerTracker_remove(  nssPointerTracker *tracker,  const void *pointer){  PRBool registered;  if( (nssPointerTracker *)NULL == tracker ) {    nss_SetError(NSS_ERROR_INVALID_POINTER);    return PR_FAILURE;  }  if( (PRLock *)NULL == tracker->lock ) {    nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED);    return PR_FAILURE;  }  PR_Lock(tracker->lock);  if( (PLHashTable *)NULL == tracker->table ) {    PR_Unlock(tracker->lock);    nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED);    return PR_FAILURE;  }  registered = PL_HashTableRemove(tracker->table, pointer);  PR_Unlock(tracker->lock);  if( !registered ) {    nss_SetError(NSS_ERROR_POINTER_NOT_REGISTERED);    return PR_FAILURE;  }  return PR_SUCCESS;}/* * nssPointerTracker_verify * * This method is only present in debug builds. * * This routine verifies that the specified pointer has been registered * with the nssPointerTracker object.  The nssPointerTracker object is * threadsafe, and this call may be safely called from multiple threads * simultaneously with the same arguments.  This routine returns a * PRStatus value; if the pointer is registered this will return  * PR_SUCCESS.  Otherwise it will set an error on the error stack and  * return PR_FAILURE.  Although the error is suitable for leaving on  * the stack, callers may wish to augment the information available by  * placing a more type-specific error on the stack. * * The error may be one of the following values: *  NSS_ERROR_INVALID_POINTER *  NSS_ERROR_TRACKER_NOT_INITIALIZED *  NSS_ERROR_POINTER_NOT_REGISTERED * * Return value: *  PR_SUCCESS *  PR_FAILRUE */NSS_IMPLEMENT PRStatusnssPointerTracker_verify(  nssPointerTracker *tracker,  const void *pointer){  void *check;  if( (nssPointerTracker *)NULL == tracker ) {    nss_SetError(NSS_ERROR_INVALID_POINTER);    return PR_FAILURE;  }  if( (PRLock *)NULL == tracker->lock ) {    nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED);    return PR_FAILURE;  }  PR_Lock(tracker->lock);  if( (PLHashTable *)NULL == tracker->table ) {    PR_Unlock(tracker->lock);    nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED);    return PR_FAILURE;  }  check = PL_HashTableLookup(tracker->table, pointer);  PR_Unlock(tracker->lock);  if( (void *)NULL == check ) {    nss_SetError(NSS_ERROR_POINTER_NOT_REGISTERED);    return PR_FAILURE;  }  return PR_SUCCESS;}#endif /* DEBUG */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?