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 + -
显示快捷键?