| Index: nss/lib/base/arena.c
|
| diff --git a/nss/lib/base/arena.c b/nss/lib/base/arena.c
|
| deleted file mode 100644
|
| index b8e64643ddde230beff9cab63824fbd3d444ddd8..0000000000000000000000000000000000000000
|
| --- a/nss/lib/base/arena.c
|
| +++ /dev/null
|
| @@ -1,1143 +0,0 @@
|
| -/* This Source Code Form is subject to the terms of the Mozilla Public
|
| - * License, v. 2.0. If a copy of the MPL was not distributed with this
|
| - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
| -
|
| -/*
|
| - * 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"
|
| -
|
| -#include <string.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
|
| - * NSS_ZAlloc
|
| - * NSS_ZRealloc
|
| - * NSS_ZFreeIf
|
| - *
|
| - * 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 DEBUG
|
| -extern const NSSError NSS_ERROR_INTERNAL_ERROR;
|
| -
|
| -static nssPointerTracker arena_pointer_tracker;
|
| -
|
| -static PRStatus
|
| -arena_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 PRStatus
|
| -arena_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 PRStatus
|
| -nssArena_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_LIST
|
| -
|
| -struct 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 PRStatus
|
| -nssArena_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 PRStatus
|
| -nssArena_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 void
|
| -nss_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 PRStatus
|
| -NSSArena_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 PRStatus
|
| -nssArena_Destroy(NSSArena *arena)
|
| -{
|
| - PRLock *lock;
|
| -
|
| -#ifdef NSSDEBUG
|
| - if (PR_SUCCESS != nssArena_verifyPointer(arena)) {
|
| - return PR_FAILURE;
|
| - }
|
| -#endif /* NSSDEBUG */
|
| -
|
| - if ((PRLock *)NULL == arena->lock) {
|
| - /* Just got destroyed */
|
| - nss_SetError(NSS_ERROR_INVALID_ARENA);
|
| - return PR_FAILURE;
|
| - }
|
| - PR_Lock(arena->lock);
|
| -
|
| -#ifdef DEBUG
|
| - if (PR_SUCCESS != arena_remove_pointer(arena)) {
|
| - PR_Unlock(arena->lock);
|
| - 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;
|
| -}
|
| -
|
| -static void *nss_zalloc_arena_locked(NSSArena *arena, PRUint32 size);
|
| -
|
| -/*
|
| - * 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:
|
| - * NULL upon failure
|
| - * An nssArenaMark pointer upon success
|
| - */
|
| -
|
| -NSS_IMPLEMENT nssArenaMark *
|
| -nssArena_Mark(NSSArena *arena)
|
| -{
|
| - nssArenaMark *rv;
|
| - void *p;
|
| -
|
| -#ifdef NSSDEBUG
|
| - if (PR_SUCCESS != nssArena_verifyPointer(arena)) {
|
| - return (nssArenaMark *)NULL;
|
| - }
|
| -#endif /* NSSDEBUG */
|
| -
|
| - if ((PRLock *)NULL == arena->lock) {
|
| - /* Just got destroyed */
|
| - nss_SetError(NSS_ERROR_INVALID_ARENA);
|
| - return (nssArenaMark *)NULL;
|
| - }
|
| - PR_Lock(arena->lock);
|
| -
|
| -#ifdef ARENA_THREADMARK
|
| - if ((PRThread *)NULL == arena->marking_thread) {
|
| - /* Unmarked. Store our thread ID */
|
| - arena->marking_thread = PR_GetCurrentThread();
|
| - /* This call never fails. */
|
| - } else {
|
| - /* Marked. Verify it's the current thread */
|
| - if (PR_GetCurrentThread() != arena->marking_thread) {
|
| - PR_Unlock(arena->lock);
|
| - nss_SetError(NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD);
|
| - return (nssArenaMark *)NULL;
|
| - }
|
| - }
|
| -#endif /* ARENA_THREADMARK */
|
| -
|
| - p = PL_ARENA_MARK(&arena->pool);
|
| - /* No error possible */
|
| -
|
| - /* Do this after the mark */
|
| - rv = (nssArenaMark *)nss_zalloc_arena_locked(arena, sizeof(nssArenaMark));
|
| - if ((nssArenaMark *)NULL == rv) {
|
| - PR_Unlock(arena->lock);
|
| - nss_SetError(NSS_ERROR_NO_MEMORY);
|
| - return (nssArenaMark *)NULL;
|
| - }
|
| -
|
| -#ifdef ARENA_THREADMARK
|
| - if ((nssArenaMark *)NULL == arena->first_mark) {
|
| - arena->first_mark = rv;
|
| - arena->last_mark = rv;
|
| - } else {
|
| - arena->last_mark->next = rv;
|
| - arena->last_mark = rv;
|
| - }
|
| -#endif /* ARENA_THREADMARK */
|
| -
|
| - rv->mark = p;
|
| - rv->magic = MARK_MAGIC;
|
| -
|
| -#ifdef ARENA_DESTRUCTOR_LIST
|
| - rv->prev_destructor = arena->last_destructor;
|
| -#endif /* ARENA_DESTRUCTOR_LIST */
|
| -
|
| - PR_Unlock(arena->lock);
|
| -
|
| - return rv;
|
| -}
|
| -
|
| -/*
|
| - * nss_arena_unmark_release
|
| - *
|
| - * This static routine implements the routines nssArena_Release
|
| - * ans nssArena_Unmark, which are almost identical.
|
| - */
|
| -
|
| -static PRStatus
|
| -nss_arena_unmark_release(NSSArena *arena, nssArenaMark *arenaMark,
|
| - PRBool release)
|
| -{
|
| - void *inner_mark;
|
| -
|
| -#ifdef NSSDEBUG
|
| - if (PR_SUCCESS != nssArena_verifyPointer(arena)) {
|
| - return PR_FAILURE;
|
| - }
|
| -#endif /* NSSDEBUG */
|
| -
|
| - if (MARK_MAGIC != arenaMark->magic) {
|
| - nss_SetError(NSS_ERROR_INVALID_ARENA_MARK);
|
| - return PR_FAILURE;
|
| - }
|
| -
|
| - if ((PRLock *)NULL == arena->lock) {
|
| - /* Just got destroyed */
|
| - nss_SetError(NSS_ERROR_INVALID_ARENA);
|
| - return PR_FAILURE;
|
| - }
|
| - PR_Lock(arena->lock);
|
| -
|
| -#ifdef ARENA_THREADMARK
|
| - if ((PRThread *)NULL != arena->marking_thread) {
|
| - if (PR_GetCurrentThread() != arena->marking_thread) {
|
| - PR_Unlock(arena->lock);
|
| - nss_SetError(NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD);
|
| - return PR_FAILURE;
|
| - }
|
| - }
|
| -#endif /* ARENA_THREADMARK */
|
| -
|
| - if (MARK_MAGIC != arenaMark->magic) {
|
| - /* Just got released */
|
| - PR_Unlock(arena->lock);
|
| - nss_SetError(NSS_ERROR_INVALID_ARENA_MARK);
|
| - return PR_FAILURE;
|
| - }
|
| -
|
| - arenaMark->magic = 0;
|
| - inner_mark = arenaMark->mark;
|
| -
|
| -#ifdef ARENA_THREADMARK
|
| - {
|
| - nssArenaMark **pMark = &arena->first_mark;
|
| - nssArenaMark *rest;
|
| - nssArenaMark *last = (nssArenaMark *)NULL;
|
| -
|
| - /* Find this mark */
|
| - while (*pMark != arenaMark) {
|
| - last = *pMark;
|
| - pMark = &(*pMark)->next;
|
| - }
|
| -
|
| - /* Remember the pointer, then zero it */
|
| - rest = (*pMark)->next;
|
| - *pMark = (nssArenaMark *)NULL;
|
| -
|
| - arena->last_mark = last;
|
| -
|
| - /* Invalidate any later marks being implicitly released */
|
| - for (; (nssArenaMark *)NULL != rest; rest = rest->next) {
|
| - rest->magic = 0;
|
| - }
|
| -
|
| - /* If we just got rid of the first mark, clear the thread ID */
|
| - if ((nssArenaMark *)NULL == arena->first_mark) {
|
| - arena->marking_thread = (PRThread *)NULL;
|
| - }
|
| - }
|
| -#endif /* ARENA_THREADMARK */
|
| -
|
| - if (release) {
|
| -#ifdef ARENA_DESTRUCTOR_LIST
|
| - if ((struct arena_destructor_node *)NULL !=
|
| - arenaMark->prev_destructor) {
|
| - arenaMark->prev_destructor->next =
|
| - (struct arena_destructor_node *)NULL;
|
| - }
|
| - arena->last_destructor = arenaMark->prev_destructor;
|
| -
|
| - /* Note that the arena is locked at this time */
|
| - nss_arena_call_destructor_chain(arenaMark->next_destructor);
|
| -#endif /* ARENA_DESTRUCTOR_LIST */
|
| -
|
| - PL_ARENA_RELEASE(&arena->pool, inner_mark);
|
| - /* No error return */
|
| - }
|
| -
|
| - PR_Unlock(arena->lock);
|
| - return PR_SUCCESS;
|
| -}
|
| -
|
| -/*
|
| - * nssArena_Release
|
| - *
|
| - * This routine invalidates and releases all memory allocated from
|
| - * the specified arena after the point at which the specified mark
|
| - * was obtained. 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_INVALID_ARENA_MARK
|
| - * NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD
|
| - *
|
| - * Return value:
|
| - * PR_SUCCESS
|
| - * PR_FAILURE
|
| - */
|
| -
|
| -NSS_IMPLEMENT PRStatus
|
| -nssArena_Release(NSSArena *arena, nssArenaMark *arenaMark)
|
| -{
|
| - return nss_arena_unmark_release(arena, arenaMark, PR_TRUE);
|
| -}
|
| -
|
| -/*
|
| - * nssArena_Unmark
|
| - *
|
| - * This routine "commits" the indicated mark and any marks after
|
| - * it, making them unreleasable. Note that any earlier marks can
|
| - * still be released, and such a release will invalidate these
|
| - * later unmarked regions. If an arena is to be safely shared by
|
| - * more than one thread, all marks must be either released or
|
| - * unmarked. 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_INVALID_ARENA_MARK
|
| - * NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD
|
| - *
|
| - * Return value:
|
| - * PR_SUCCESS
|
| - * PR_FAILURE
|
| - */
|
| -
|
| -NSS_IMPLEMENT PRStatus
|
| -nssArena_Unmark(NSSArena *arena, nssArenaMark *arenaMark)
|
| -{
|
| - return nss_arena_unmark_release(arena, arenaMark, PR_FALSE);
|
| -}
|
| -
|
| -/*
|
| - * We prefix this header to all allocated blocks. It is a multiple
|
| - * of the alignment size. Note that this usage of a header may make
|
| - * purify spew bogus warnings about "potentially leaked blocks" of
|
| - * memory; if that gets too annoying we can add in a pointer to the
|
| - * header in the header itself. There's not a lot of safety here;
|
| - * maybe we should add a magic value?
|
| - */
|
| -struct pointer_header {
|
| - NSSArena *arena;
|
| - PRUint32 size;
|
| -};
|
| -
|
| -static void *
|
| -nss_zalloc_arena_locked(NSSArena *arena, PRUint32 size)
|
| -{
|
| - void *p;
|
| - void *rv;
|
| - struct pointer_header *h;
|
| - PRUint32 my_size = size + sizeof(struct pointer_header);
|
| - PL_ARENA_ALLOCATE(p, &arena->pool, my_size);
|
| - if ((void *)NULL == p) {
|
| - nss_SetError(NSS_ERROR_NO_MEMORY);
|
| - return (void *)NULL;
|
| - }
|
| - /*
|
| - * Do this before we unlock. This way if the user is using
|
| - * an arena in one thread while destroying it in another, he'll
|
| - * fault/FMR in his code, not ours.
|
| - */
|
| - h = (struct pointer_header *)p;
|
| - h->arena = arena;
|
| - h->size = size;
|
| - rv = (void *)((char *)h + sizeof(struct pointer_header));
|
| - (void)nsslibc_memset(rv, 0, size);
|
| - return rv;
|
| -}
|
| -
|
| -/*
|
| - * NSS_ZAlloc
|
| - *
|
| - * This routine allocates and zeroes a section of memory of the
|
| - * size, and returns to the caller a pointer to that memory. If
|
| - * the optional arena argument is non-null, the memory will be
|
| - * obtained from that arena; otherwise, the memory will be obtained
|
| - * from the heap. This routine may return NULL upon error, in
|
| - * which case it will have set an error upon the error stack. The
|
| - * value specified for size may be zero; in which case a valid
|
| - * zero-length block of memory will be allocated. This block may
|
| - * be expanded by calling NSS_ZRealloc.
|
| - *
|
| - * 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:
|
| - * NULL upon error
|
| - * A pointer to the new segment of zeroed memory
|
| - */
|
| -
|
| -NSS_IMPLEMENT void *
|
| -NSS_ZAlloc(NSSArena *arenaOpt, PRUint32 size)
|
| -{
|
| - return nss_ZAlloc(arenaOpt, size);
|
| -}
|
| -
|
| -/*
|
| - * nss_ZAlloc
|
| - *
|
| - * This routine allocates and zeroes a section of memory of the
|
| - * size, and returns to the caller a pointer to that memory. If
|
| - * the optional arena argument is non-null, the memory will be
|
| - * obtained from that arena; otherwise, the memory will be obtained
|
| - * from the heap. This routine may return NULL upon error, in
|
| - * which case it will have set an error upon the error stack. The
|
| - * value specified for size may be zero; in which case a valid
|
| - * zero-length block of memory will be allocated. This block may
|
| - * be expanded by calling nss_ZRealloc.
|
| - *
|
| - * 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:
|
| - * NULL upon error
|
| - * A pointer to the new segment of zeroed memory
|
| - */
|
| -
|
| -NSS_IMPLEMENT void *
|
| -nss_ZAlloc(NSSArena *arenaOpt, PRUint32 size)
|
| -{
|
| - struct pointer_header *h;
|
| - PRUint32 my_size = size + sizeof(struct pointer_header);
|
| -
|
| - if (my_size < sizeof(struct pointer_header)) {
|
| - /* Wrapped */
|
| - nss_SetError(NSS_ERROR_NO_MEMORY);
|
| - return (void *)NULL;
|
| - }
|
| -
|
| - if ((NSSArena *)NULL == arenaOpt) {
|
| - /* Heap allocation, no locking required. */
|
| - h = (struct pointer_header *)PR_Calloc(1, my_size);
|
| - if ((struct pointer_header *)NULL == h) {
|
| - nss_SetError(NSS_ERROR_NO_MEMORY);
|
| - return (void *)NULL;
|
| - }
|
| -
|
| - h->arena = (NSSArena *)NULL;
|
| - h->size = size;
|
| - /* We used calloc: it's already zeroed */
|
| -
|
| - return (void *)((char *)h + sizeof(struct pointer_header));
|
| - } else {
|
| - void *rv;
|
| -/* Arena allocation */
|
| -#ifdef NSSDEBUG
|
| - if (PR_SUCCESS != nssArena_verifyPointer(arenaOpt)) {
|
| - return (void *)NULL;
|
| - }
|
| -#endif /* NSSDEBUG */
|
| -
|
| - if ((PRLock *)NULL == arenaOpt->lock) {
|
| - /* Just got destroyed */
|
| - nss_SetError(NSS_ERROR_INVALID_ARENA);
|
| - return (void *)NULL;
|
| - }
|
| - PR_Lock(arenaOpt->lock);
|
| -
|
| -#ifdef ARENA_THREADMARK
|
| - if ((PRThread *)NULL != arenaOpt->marking_thread) {
|
| - if (PR_GetCurrentThread() != arenaOpt->marking_thread) {
|
| - nss_SetError(NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD);
|
| - PR_Unlock(arenaOpt->lock);
|
| - return (void *)NULL;
|
| - }
|
| - }
|
| -#endif /* ARENA_THREADMARK */
|
| -
|
| - rv = nss_zalloc_arena_locked(arenaOpt, size);
|
| -
|
| - PR_Unlock(arenaOpt->lock);
|
| - return rv;
|
| - }
|
| - /*NOTREACHED*/
|
| -}
|
| -
|
| -/*
|
| - * NSS_ZFreeIf
|
| - *
|
| - * If the specified pointer is non-null, then the region of memory
|
| - * to which it points -- which must have been allocated with
|
| - * NSS_ZAlloc -- will be zeroed and released. 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_POINTER
|
| - *
|
| - * Return value:
|
| - * PR_SUCCESS
|
| - * PR_FAILURE
|
| - */
|
| -NSS_IMPLEMENT PRStatus
|
| -NSS_ZFreeIf(void *pointer)
|
| -{
|
| - return nss_ZFreeIf(pointer);
|
| -}
|
| -
|
| -/*
|
| - * nss_ZFreeIf
|
| - *
|
| - * If the specified pointer is non-null, then the region of memory
|
| - * to which it points -- which must have been allocated with
|
| - * nss_ZAlloc -- will be zeroed and released. 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_POINTER
|
| - *
|
| - * Return value:
|
| - * PR_SUCCESS
|
| - * PR_FAILURE
|
| - */
|
| -
|
| -NSS_IMPLEMENT PRStatus
|
| -nss_ZFreeIf(void *pointer)
|
| -{
|
| - struct pointer_header *h;
|
| -
|
| - if ((void *)NULL == pointer) {
|
| - return PR_SUCCESS;
|
| - }
|
| -
|
| - h = (struct pointer_header *)((char *)pointer -
|
| - sizeof(struct pointer_header));
|
| -
|
| - /* Check any magic here */
|
| -
|
| - if ((NSSArena *)NULL == h->arena) {
|
| - /* Heap */
|
| - (void)nsslibc_memset(pointer, 0, h->size);
|
| - PR_Free(h);
|
| - return PR_SUCCESS;
|
| - } else {
|
| -/* Arena */
|
| -#ifdef NSSDEBUG
|
| - if (PR_SUCCESS != nssArena_verifyPointer(h->arena)) {
|
| - return PR_FAILURE;
|
| - }
|
| -#endif /* NSSDEBUG */
|
| -
|
| - if ((PRLock *)NULL == h->arena->lock) {
|
| - /* Just got destroyed.. so this pointer is invalid */
|
| - nss_SetError(NSS_ERROR_INVALID_POINTER);
|
| - return PR_FAILURE;
|
| - }
|
| - PR_Lock(h->arena->lock);
|
| -
|
| - (void)nsslibc_memset(pointer, 0, h->size);
|
| -
|
| - /* No way to "free" it within an NSPR arena. */
|
| -
|
| - PR_Unlock(h->arena->lock);
|
| - return PR_SUCCESS;
|
| - }
|
| - /*NOTREACHED*/
|
| -}
|
| -
|
| -/*
|
| - * NSS_ZRealloc
|
| - *
|
| - * This routine reallocates a block of memory obtained by calling
|
| - * nss_ZAlloc or nss_ZRealloc. The portion of memory
|
| - * between the new and old sizes -- which is either being newly
|
| - * obtained or released -- is in either case zeroed. This routine
|
| - * may return NULL upon failure, in which case it will have placed
|
| - * an error on the error stack.
|
| - *
|
| - * The error may be one of the following values:
|
| - * NSS_ERROR_INVALID_POINTER
|
| - * NSS_ERROR_NO_MEMORY
|
| - * NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD
|
| - *
|
| - * Return value:
|
| - * NULL upon error
|
| - * A pointer to the replacement segment of memory
|
| - */
|
| -
|
| -NSS_EXTERN void *
|
| -NSS_ZRealloc(void *pointer, PRUint32 newSize)
|
| -{
|
| - return nss_ZRealloc(pointer, newSize);
|
| -}
|
| -
|
| -/*
|
| - * nss_ZRealloc
|
| - *
|
| - * This routine reallocates a block of memory obtained by calling
|
| - * nss_ZAlloc or nss_ZRealloc. The portion of memory
|
| - * between the new and old sizes -- which is either being newly
|
| - * obtained or released -- is in either case zeroed. This routine
|
| - * may return NULL upon failure, in which case it will have placed
|
| - * an error on the error stack.
|
| - *
|
| - * The error may be one of the following values:
|
| - * NSS_ERROR_INVALID_POINTER
|
| - * NSS_ERROR_NO_MEMORY
|
| - * NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD
|
| - *
|
| - * Return value:
|
| - * NULL upon error
|
| - * A pointer to the replacement segment of memory
|
| - */
|
| -
|
| -NSS_EXTERN void *
|
| -nss_ZRealloc(void *pointer, PRUint32 newSize)
|
| -{
|
| - NSSArena *arena;
|
| - struct pointer_header *h, *new_h;
|
| - PRUint32 my_newSize = newSize + sizeof(struct pointer_header);
|
| - void *rv;
|
| -
|
| - if (my_newSize < sizeof(struct pointer_header)) {
|
| - /* Wrapped */
|
| - nss_SetError(NSS_ERROR_NO_MEMORY);
|
| - return (void *)NULL;
|
| - }
|
| -
|
| - if ((void *)NULL == pointer) {
|
| - nss_SetError(NSS_ERROR_INVALID_POINTER);
|
| - return (void *)NULL;
|
| - }
|
| -
|
| - h = (struct pointer_header *)((char *)pointer -
|
| - sizeof(struct pointer_header));
|
| -
|
| - /* Check any magic here */
|
| -
|
| - if (newSize == h->size) {
|
| - /* saves thrashing */
|
| - return pointer;
|
| - }
|
| -
|
| - arena = h->arena;
|
| - if (!arena) {
|
| - /* Heap */
|
| - new_h = (struct pointer_header *)PR_Calloc(1, my_newSize);
|
| - if ((struct pointer_header *)NULL == new_h) {
|
| - nss_SetError(NSS_ERROR_NO_MEMORY);
|
| - return (void *)NULL;
|
| - }
|
| -
|
| - new_h->arena = (NSSArena *)NULL;
|
| - new_h->size = newSize;
|
| - rv = (void *)((char *)new_h + sizeof(struct pointer_header));
|
| -
|
| - if (newSize > h->size) {
|
| - (void)nsslibc_memcpy(rv, pointer, h->size);
|
| - (void)nsslibc_memset(&((char *)rv)[h->size], 0,
|
| - (newSize - h->size));
|
| - } else {
|
| - (void)nsslibc_memcpy(rv, pointer, newSize);
|
| - }
|
| -
|
| - (void)nsslibc_memset(pointer, 0, h->size);
|
| - h->size = 0;
|
| - PR_Free(h);
|
| -
|
| - return rv;
|
| - } else {
|
| - void *p;
|
| -/* Arena */
|
| -#ifdef NSSDEBUG
|
| - if (PR_SUCCESS != nssArena_verifyPointer(arena)) {
|
| - return (void *)NULL;
|
| - }
|
| -#endif /* NSSDEBUG */
|
| -
|
| - if (!arena->lock) {
|
| - /* Just got destroyed.. so this pointer is invalid */
|
| - nss_SetError(NSS_ERROR_INVALID_POINTER);
|
| - return (void *)NULL;
|
| - }
|
| - PR_Lock(arena->lock);
|
| -
|
| -#ifdef ARENA_THREADMARK
|
| - if (arena->marking_thread) {
|
| - if (PR_GetCurrentThread() != arena->marking_thread) {
|
| - PR_Unlock(arena->lock);
|
| - nss_SetError(NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD);
|
| - return (void *)NULL;
|
| - }
|
| - }
|
| -#endif /* ARENA_THREADMARK */
|
| -
|
| - if (newSize < h->size) {
|
| - /*
|
| - * We have no general way of returning memory to the arena
|
| - * (mark/release doesn't work because things may have been
|
| - * allocated after this object), so the memory is gone
|
| - * anyway. We might as well just return the same pointer to
|
| - * the user, saying "yeah, uh-hunh, you can only use less of
|
| - * it now." We'll zero the leftover part, of course. And
|
| - * in fact we might as well *not* adjust h->size-- this way,
|
| - * if the user reallocs back up to something not greater than
|
| - * the original size, then voila, there's the memory! This
|
| - * way a thrash big/small/big/small doesn't burn up the arena.
|
| - */
|
| - char *extra = &((char *)pointer)[newSize];
|
| - (void)nsslibc_memset(extra, 0, (h->size - newSize));
|
| - PR_Unlock(arena->lock);
|
| - return pointer;
|
| - }
|
| -
|
| - PL_ARENA_ALLOCATE(p, &arena->pool, my_newSize);
|
| - if ((void *)NULL == p) {
|
| - PR_Unlock(arena->lock);
|
| - nss_SetError(NSS_ERROR_NO_MEMORY);
|
| - return (void *)NULL;
|
| - }
|
| -
|
| - new_h = (struct pointer_header *)p;
|
| - new_h->arena = arena;
|
| - new_h->size = newSize;
|
| - rv = (void *)((char *)new_h + sizeof(struct pointer_header));
|
| - if (rv != pointer) {
|
| - (void)nsslibc_memcpy(rv, pointer, h->size);
|
| - (void)nsslibc_memset(pointer, 0, h->size);
|
| - }
|
| - (void)nsslibc_memset(&((char *)rv)[h->size], 0, (newSize - h->size));
|
| - h->arena = (NSSArena *)NULL;
|
| - h->size = 0;
|
| - PR_Unlock(arena->lock);
|
| - return rv;
|
| - }
|
| - /*NOTREACHED*/
|
| -}
|
| -
|
| -PRStatus
|
| -nssArena_Shutdown(void)
|
| -{
|
| - PRStatus rv = PR_SUCCESS;
|
| -#ifdef DEBUG
|
| - rv = nssPointerTracker_finalize(&arena_pointer_tracker);
|
| -#endif
|
| - return rv;
|
| -}
|
|
|