arena.c

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

C
1,122
字号
/*  * 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: arena.c,v $ $Revision: 1.2 $ $Date: 2000/04/19 21:23:13 $ $Name: NSS_3_1_1_RTM $";#endif /* DEBUG *//* * arena.c * * This contains the implementation of NSS's thread-safe arenas. */#ifndef BASE_H#include "base.h"#endif /* BASE_H */#ifdef ARENA_THREADMARK#include "prthread.h"#endif /* ARENA_THREADMARK */#include "prlock.h"#include "plarena.h"/* * NSSArena * * This is based on NSPR's arena code, but it is threadsafe. * * The public methods relating to this type are: * *  NSSArena_Create  -- constructor *  NSSArena_Destroy * * The nonpublic methods relating to this type are: * *  nssArena_Create  -- constructor *  nssArena_Destroy *  nssArena_Mark *  nssArena_Release *  nssArena_Unmark *  *  nss_ZAlloc *  nss_ZFreeIf *  nss_ZRealloc * * In debug builds, the following calls are available: * *  nssArena_verifyPointer *  nssArena_registerDestructor *  nssArena_deregisterDestructor */struct NSSArenaStr {  PLArenaPool pool;  PRLock *lock;#ifdef ARENA_THREADMARK  PRThread *marking_thread;  nssArenaMark *first_mark;  nssArenaMark *last_mark;#endif /* ARENA_THREADMARK */#ifdef ARENA_DESTRUCTOR_LIST  struct arena_destructor_node *first_destructor;  struct arena_destructor_node *last_destructor;#endif /* ARENA_DESTRUCTOR_LIST */};/* * nssArenaMark * * This type is used to mark the current state of an NSSArena. */struct nssArenaMarkStr {  PRUint32 magic;  void *mark;#ifdef ARENA_THREADMARK  nssArenaMark *next;#endif /* ARENA_THREADMARK */#ifdef ARENA_DESTRUCTOR_LIST  struct arena_destructor_node *next_destructor;  struct arena_destructor_node *prev_destructor;#endif /* ARENA_DESTRUCTOR_LIST */};#define MARK_MAGIC 0x4d41524b /* "MARK" how original *//* * But first, the pointer-tracking code */#ifdef DEBUGextern const NSSError NSS_ERROR_INTERNAL_ERROR;static nssPointerTracker arena_pointer_tracker;static PRStatusarena_add_pointer(  const NSSArena *arena){  PRStatus rv;  rv = nssPointerTracker_initialize(&arena_pointer_tracker);  if( PR_SUCCESS != rv ) {    return rv;  }  rv = nssPointerTracker_add(&arena_pointer_tracker, arena);  if( PR_SUCCESS != rv ) {    NSSError e = NSS_GetError();    if( NSS_ERROR_NO_MEMORY != e ) {      nss_SetError(NSS_ERROR_INTERNAL_ERROR);    }    return rv;  }  return PR_SUCCESS;}static PRStatusarena_remove_pointer(  const NSSArena *arena){  PRStatus rv;  rv = nssPointerTracker_remove(&arena_pointer_tracker, arena);  if( PR_SUCCESS != rv ) {    nss_SetError(NSS_ERROR_INTERNAL_ERROR);  }  return rv;}/* * nssArena_verifyPointer * * This method is only present in debug builds. * * If the specified pointer is a valid pointer to an NSSArena object, * this routine will return PR_SUCCESS.  Otherwise, it will put an * error on the error stack and return PR_FAILURE. * * The error may be one of the following values: *  NSS_ERROR_INVALID_ARENA * * Return value: *  PR_SUCCESS if the pointer is valid *  PR_FAILURE if it isn't */NSS_IMPLEMENT PRStatusnssArena_verifyPointer(  const NSSArena *arena){  PRStatus rv;  rv = nssPointerTracker_initialize(&arena_pointer_tracker);  if( PR_SUCCESS != rv ) {    /*     * This is a little disingenious.  We have to initialize the     * tracker, because someone could "legitimately" try to verify     * an arena pointer before one is ever created.  And this step     * might fail, due to lack of memory.  But the only way that     * this step can fail is if it's doing the call_once stuff,     * (later calls just no-op).  And if it didn't no-op, there     * aren't any valid arenas.. so the argument certainly isn't one.     */    nss_SetError(NSS_ERROR_INVALID_ARENA);    return PR_FAILURE;  }  rv = nssPointerTracker_verify(&arena_pointer_tracker, arena);  if( PR_SUCCESS != rv ) {    nss_SetError(NSS_ERROR_INVALID_ARENA);    return PR_FAILURE;  }  return PR_SUCCESS;}#endif /* DEBUG */#ifdef ARENA_DESTRUCTOR_LISTstruct arena_destructor_node {  struct arena_destructor_node *next;  struct arena_destructor_node *prev;  void (*destructor)(void *argument);  void *arg;};/* * nssArena_registerDestructor * * This routine stores a pointer to a callback and an arbitrary * pointer-sized argument in the arena, at the current point in * the mark stack.  If the arena is destroyed, or an "earlier" * mark is released, then this destructor will be called at that * time.  Note that the destructor will be called with the arena * locked, which means the destructor may free memory in that * arena, but it may not allocate or cause to be allocated any * memory.  This callback facility was included to support our * debug-version pointer-tracker feature; overuse runs counter to * the the original intent of arenas.  This routine returns a  * PRStatus value; if successful, it will return PR_SUCCESS.  If  * unsuccessful, 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_ARENA *  NSS_ERROR_NO_MEMORY * * Return value: *  PR_SUCCESS *  PR_FAILURE */NSS_IMPLEMENT PRStatusnssArena_registerDestructor(  NSSArena *arena,  void (*destructor)(void *argument),  void *arg){  struct arena_destructor_node *it;#ifdef NSSDEBUG  if( PR_SUCCESS != nssArena_verifyPointer(arena) ) {    return PR_FAILURE;  }#endif /* NSSDEBUG */    it = nss_ZNEW(arena, struct arena_destructor_node);  if( (struct arena_destructor_node *)NULL == it ) {    return PR_FAILURE;  }  it->prev = arena->last_destructor;  arena->last_destructor->next = it;  arena->last_destructor = it;  it->destructor = destructor;  it->arg = arg;  if( (nssArenaMark *)NULL != arena->last_mark ) {    arena->last_mark->prev_destructor = it->prev;    arena->last_mark->next_destructor = it->next;  }  return PR_SUCCESS;}NSS_IMPLEMENT PRStatusnssArena_deregisterDestructor(  NSSArena *arena,  void (*destructor)(void *argument),  void *arg){  struct arena_destructor_node *it;#ifdef NSSDEBUG  if( PR_SUCCESS != nssArena_verifyPointer(arena) ) {    return PR_FAILURE;  }#endif /* NSSDEBUG */  for( it = arena->first_destructor; it; it = it->next ) {    if( (it->destructor == destructor) && (it->arg == arg) ) {      break;    }  }  if( (struct arena_destructor_node *)NULL == it ) {    nss_SetError(NSS_ERROR_NOT_FOUND);    return PR_FAILURE;  }  if( it == arena->first_destructor ) {    arena->first_destructor = it->next;  }  if( it == arena->last_destructor ) {    arena->last_destructor = it->prev;  }  if( (struct arena_destructor_node *)NULL != it->prev ) {    it->prev->next = it->next;  }  if( (struct arena_destructor_node *)NULL != it->next ) {    it->next->prev = it->prev;  }  {    nssArenaMark *m;    for( m = arena->first_mark; m; m = m->next ) {      if( m->next_destructor == it ) {        m->next_destructor = it->next;      }      if( m->prev_destructor == it ) {        m->prev_destructor = it->prev;      }    }  }  nss_ZFreeIf(it);  return PR_SUCCESS;}static voidnss_arena_call_destructor_chain(  struct arena_destructor_node *it){  for( ; it ; it = it->next ) {    (*(it->destructor))(it->arg);  }}#endif /* ARENA_DESTRUCTOR_LIST *//* * NSSArena_Create * * This routine creates a new memory arena.  This routine may return * NULL upon error, in which case it will have created an error stack. * * The top-level error may be one of the following values: *  NSS_ERROR_NO_MEMORY * * Return value: *  NULL upon error *  A pointer to an NSSArena upon success */NSS_IMPLEMENT NSSArena *NSSArena_Create(  void){  nss_ClearErrorStack();  return nssArena_Create();}/* * nssArena_Create * * This routine creates a new memory arena.  This routine may return * NULL upon error, in which case it will have set an error on the  * error stack. * * The error may be one of the following values: *  NSS_ERROR_NO_MEMORY * * Return value: *  NULL upon error *  A pointer to an NSSArena upon success */NSS_IMPLEMENT NSSArena *nssArena_Create(  void){  NSSArena *rv = (NSSArena *)NULL;  rv = nss_ZNEW((NSSArena *)NULL, NSSArena);  if( (NSSArena *)NULL == rv ) {    nss_SetError(NSS_ERROR_NO_MEMORY);    return (NSSArena *)NULL;  }  rv->lock = PR_NewLock();  if( (PRLock *)NULL == rv->lock ) {    (void)nss_ZFreeIf(rv);    nss_SetError(NSS_ERROR_NO_MEMORY);    return (NSSArena *)NULL;  }  /*   * Arena sizes.  The current security code has 229 occurrences of   * PORT_NewArena.  The default chunksizes specified break down as   *   *  Size    Mult.   Specified as   *   512       1    512   *  1024       7    1024   *  2048       5    2048   *  2048       5    CRMF_DEFAULT_ARENA_SIZE   *  2048     190    DER_DEFAULT_CHUNKSIZE   *  2048      20    SEC_ASN1_DEFAULT_ARENA_SIZE   *  4096       1    4096   *   * Obviously this "default chunksize" flexibility isn't very    * useful to us, so I'll just pick 2048.   */  PL_InitArenaPool(&rv->pool, "NSS", 2048, sizeof(double));#ifdef DEBUG  {    PRStatus st;    st = arena_add_pointer(rv);    if( PR_SUCCESS != st ) {      PL_FinishArenaPool(&rv->pool);      PR_DestroyLock(rv->lock);      (void)nss_ZFreeIf(rv);      return (NSSArena *)NULL;    }  }#endif /* DEBUG */  return rv;}/* * NSSArena_Destroy * * This routine will destroy the specified arena, freeing all memory * allocated from it.  This routine returns a PRStatus value; if  * successful, it will return PR_SUCCESS.  If unsuccessful, it will * create an error stack and return PR_FAILURE. * * The top-level error may be one of the following values: *  NSS_ERROR_INVALID_ARENA * * Return value: *  PR_SUCCESS upon success *  PR_FAILURE upon failure */NSS_IMPLEMENT PRStatusNSSArena_Destroy(  NSSArena *arena){  nss_ClearErrorStack();#ifdef DEBUG  if( PR_SUCCESS != nssArena_verifyPointer(arena) ) {    return PR_FAILURE;  }#endif /* DEBUG */  return nssArena_Destroy(arena);}/* * nssArena_Destroy * * This routine will destroy the specified arena, freeing all memory * allocated from it.  This routine returns a PRStatus value; if  * successful, it will return PR_SUCCESS.  If unsuccessful, 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_ARENA * * Return value: *  PR_SUCCESS *  PR_FAILURE */NSS_IMPLEMENT PRStatusnssArena_Destroy(  NSSArena *arena){  PRLock *lock;#ifdef NSSDEBUG  if( PR_SUCCESS != nssArena_verifyPointer(arena) ) {    return PR_FAILURE;  }#endif /* NSSDEBUG */  PR_Lock(arena->lock);  if( (PRLock *)NULL == arena->lock ) {    /* Just got destroyed */    nss_SetError(NSS_ERROR_INVALID_ARENA);    return PR_FAILURE;  }  #ifdef DEBUG  if( PR_SUCCESS != arena_remove_pointer(arena) ) {    return PR_FAILURE;  }#endif /* DEBUG */#ifdef ARENA_DESTRUCTOR_LIST  /* Note that the arena is locked at this time */  nss_arena_call_destructor_chain(arena->first_destructor);#endif /* ARENA_DESTRUCTOR_LIST */  PL_FinishArenaPool(&arena->pool);  lock = arena->lock;  arena->lock = (PRLock *)NULL;  PR_Unlock(lock);  PR_DestroyLock(lock);  (void)nss_ZFreeIf(arena);  return PR_SUCCESS;}/* * nssArena_Mark * * This routine "marks" the current state of an arena.  Space * allocated after the arena has been marked can be freed by * releasing the arena back to the mark with nssArena_Release, * or committed by calling nssArena_Unmark.  When successful,  * this routine returns a valid nssArenaMark pointer.  This  * routine may return NULL upon error, in which case it will  * have set an error on the error stack. * * The error may be one of the following values: *  NSS_ERROR_INVALID_ARENA *  NSS_ERROR_NO_MEMORY *  NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD * * Return value:

⌨️ 快捷键说明

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