Back to index

lightning-sunbird  0.9+nobinonly
Classes | Defines | Functions
arena.c File Reference
#include "base.h"
#include "prlock.h"
#include "plarena.h"
#include <string.h>

Go to the source code of this file.

Classes

struct  NSSArenaStr
struct  nssArenaMarkStr
struct  pointer_header

Defines

#define MARK_MAGIC   0x4d41524b /* "MARK" how original */

Functions

NSS_IMPLEMENT NSSArena * NSSArena_Create (void)
NSS_IMPLEMENT NSSArena * nssArena_Create (void)
NSS_IMPLEMENT PRStatus NSSArena_Destroy (NSSArena *arena)
NSS_IMPLEMENT PRStatus nssArena_Destroy (NSSArena *arena)
static voidnss_zalloc_arena_locked (NSSArena *arena, PRUint32 size)
NSS_IMPLEMENT nssArenaMark * nssArena_Mark (NSSArena *arena)
static PRStatus nss_arena_unmark_release (NSSArena *arena, nssArenaMark *arenaMark, PRBool release)
NSS_IMPLEMENT PRStatus nssArena_Release (NSSArena *arena, nssArenaMark *arenaMark)
NSS_IMPLEMENT PRStatus nssArena_Unmark (NSSArena *arena, nssArenaMark *arenaMark)
NSS_IMPLEMENT voidnss_ZAlloc (NSSArena *arenaOpt, PRUint32 size)
NSS_IMPLEMENT PRStatus nss_ZFreeIf (void *pointer)
NSS_EXTERN voidnss_ZRealloc (void *pointer, PRUint32 newSize)

Class Documentation

struct NSSArenaStr

Definition at line 89 of file arena.c.

Collaboration diagram for NSSArenaStr:
Class Members
PRLock * lock
PLArenaPool pool
struct nssArenaMarkStr

Definition at line 109 of file arena.c.

Class Members
PRUint32 magic
void * mark
struct pointer_header

Definition at line 816 of file arena.c.

Class Members
NSSArena * arena
PRUint32 size

Define Documentation

#define MARK_MAGIC   0x4d41524b /* "MARK" how original */

Definition at line 121 of file arena.c.


Function Documentation

static PRStatus nss_arena_unmark_release ( NSSArena *  arena,
nssArenaMark *  arenaMark,
PRBool  release 
) [static]

Definition at line 652 of file arena.c.

{
  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 */

    PR_ARENA_RELEASE(&arena->pool, inner_mark);
    /* No error return */
  }

  PR_Unlock(arena->lock);
  return PR_SUCCESS;
}

Here is the call graph for this function:

Here is the caller graph for this function:

NSS_IMPLEMENT void* nss_ZAlloc ( NSSArena *  arenaOpt,
PRUint32  size 
)

Definition at line 875 of file arena.c.

{
  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*/
}

Here is the call graph for this function:

static void * nss_zalloc_arena_locked ( NSSArena *  arena,
PRUint32  size 
) [static]

Definition at line 823 of file arena.c.

{
  void *p;
  void *rv;
  struct pointer_header *h;
  PRUint32 my_size = size + sizeof(struct pointer_header);
  PR_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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 956 of file arena.c.

{
  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 */

    PR_Lock(h->arena->lock);
    if( (PRLock *)NULL == h->arena->lock ) {
      /* Just got destroyed.. so this pointer is invalid */
      nss_SetError(NSS_ERROR_INVALID_POINTER);
      return PR_FAILURE;
    }

    (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*/
}

Here is the call graph for this function:

NSS_EXTERN void* nss_ZRealloc ( void pointer,
PRUint32  newSize 
)

Definition at line 1023 of file arena.c.

{
  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;
  }

  if( (NSSArena *)NULL == h->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(h->arena) ) {
      return (void *)NULL;
    }
#endif /* NSSDEBUG */

    PR_Lock(h->arena->lock);
    if( (PRLock *)NULL == h->arena->lock ) {
      /* Just got destroyed.. so this pointer is invalid */
      nss_SetError(NSS_ERROR_INVALID_POINTER);
      return (void *)NULL;
    }

#ifdef ARENA_THREADMARK
    if( (PRThread *)NULL != h->arena->marking_thread ) {
      if( PR_GetCurrentThread() != h->arena->marking_thread ) {
        PR_Unlock(h->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(h->arena->lock);
      return pointer;
    }

    PR_ARENA_ALLOCATE(p, &h->arena->pool, my_newSize);
    if( (void *)NULL == p ) {
      PR_Unlock(h->arena->lock);
      nss_SetError(NSS_ERROR_NO_MEMORY);
      return (void *)NULL;
    }

    new_h = (struct pointer_header *)p;
    new_h->arena = h->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(new_h->arena->lock);
    return rv;
  }
  /*NOTREACHED*/
}

Here is the call graph for this function:

Definition at line 381 of file arena.c.

Here is the call graph for this function:

Definition at line 406 of file arena.c.

{
  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;
}

Here is the call graph for this function:

NSS_IMPLEMENT PRStatus NSSArena_Destroy ( NSSArena *  arena)

Definition at line 478 of file arena.c.

{
  nss_ClearErrorStack();

#ifdef DEBUG
  if( PR_SUCCESS != nssArena_verifyPointer(arena) ) {
    return PR_FAILURE;
  }
#endif /* DEBUG */

  return nssArena_Destroy(arena);
}

Here is the call graph for this function:

NSS_IMPLEMENT PRStatus nssArena_Destroy ( NSSArena *  arena)

Definition at line 511 of file arena.c.

{
  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) ) {
    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;
}

Here is the call graph for this function:

NSS_IMPLEMENT nssArenaMark* nssArena_Mark ( NSSArena *  arena)

Definition at line 575 of file arena.c.

{
  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;
}

Here is the call graph for this function:

NSS_IMPLEMENT PRStatus nssArena_Release ( NSSArena *  arena,
nssArenaMark *  arenaMark 
)

Definition at line 768 of file arena.c.

{
  return nss_arena_unmark_release(arena, arenaMark, PR_TRUE);
}

Here is the call graph for this function:

NSS_IMPLEMENT PRStatus nssArena_Unmark ( NSSArena *  arena,
nssArenaMark *  arenaMark 
)

Definition at line 800 of file arena.c.

{
  return nss_arena_unmark_release(arena, arenaMark, PR_FALSE);
}

Here is the call graph for this function: