arena.c
上传用户:lyxiangda
上传日期:2007-01-12
资源大小:3042k
文件大小:28k
源码类别:

CA认证

开发平台:

WINDOWS

  1. /* 
  2.  * The contents of this file are subject to the Mozilla Public
  3.  * License Version 1.1 (the "License"); you may not use this file
  4.  * except in compliance with the License. You may obtain a copy of
  5.  * the License at http://www.mozilla.org/MPL/
  6.  * 
  7.  * Software distributed under the License is distributed on an "AS
  8.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  9.  * implied. See the License for the specific language governing
  10.  * rights and limitations under the License.
  11.  * 
  12.  * The Original Code is the Netscape security libraries.
  13.  * 
  14.  * The Initial Developer of the Original Code is Netscape
  15.  * Communications Corporation.  Portions created by Netscape are 
  16.  * Copyright (C) 1994-2000 Netscape Communications Corporation.  All
  17.  * Rights Reserved.
  18.  * 
  19.  * Contributor(s):
  20.  * 
  21.  * Alternatively, the contents of this file may be used under the
  22.  * terms of the GNU General Public License Version 2 or later (the
  23.  * "GPL"), in which case the provisions of the GPL are applicable 
  24.  * instead of those above.  If you wish to allow use of your 
  25.  * version of this file only under the terms of the GPL and not to
  26.  * allow others to use your version of this file under the MPL,
  27.  * indicate your decision by deleting the provisions above and
  28.  * replace them with the notice and other provisions required by
  29.  * the GPL.  If you do not delete the provisions above, a recipient
  30.  * may use your version of this file under either the MPL or the
  31.  * GPL.
  32.  */
  33. #ifdef DEBUG
  34. static const char CVS_ID[] = "@(#) $RCSfile: arena.c,v $ $Revision: 1.2 $ $Date: 2000/04/19 21:23:13 $ $Name: NSS_3_1_1_RTM $";
  35. #endif /* DEBUG */
  36. /*
  37.  * arena.c
  38.  *
  39.  * This contains the implementation of NSS's thread-safe arenas.
  40.  */
  41. #ifndef BASE_H
  42. #include "base.h"
  43. #endif /* BASE_H */
  44. #ifdef ARENA_THREADMARK
  45. #include "prthread.h"
  46. #endif /* ARENA_THREADMARK */
  47. #include "prlock.h"
  48. #include "plarena.h"
  49. /*
  50.  * NSSArena
  51.  *
  52.  * This is based on NSPR's arena code, but it is threadsafe.
  53.  *
  54.  * The public methods relating to this type are:
  55.  *
  56.  *  NSSArena_Create  -- constructor
  57.  *  NSSArena_Destroy
  58.  *
  59.  * The nonpublic methods relating to this type are:
  60.  *
  61.  *  nssArena_Create  -- constructor
  62.  *  nssArena_Destroy
  63.  *  nssArena_Mark
  64.  *  nssArena_Release
  65.  *  nssArena_Unmark
  66.  * 
  67.  *  nss_ZAlloc
  68.  *  nss_ZFreeIf
  69.  *  nss_ZRealloc
  70.  *
  71.  * In debug builds, the following calls are available:
  72.  *
  73.  *  nssArena_verifyPointer
  74.  *  nssArena_registerDestructor
  75.  *  nssArena_deregisterDestructor
  76.  */
  77. struct NSSArenaStr {
  78.   PLArenaPool pool;
  79.   PRLock *lock;
  80. #ifdef ARENA_THREADMARK
  81.   PRThread *marking_thread;
  82.   nssArenaMark *first_mark;
  83.   nssArenaMark *last_mark;
  84. #endif /* ARENA_THREADMARK */
  85. #ifdef ARENA_DESTRUCTOR_LIST
  86.   struct arena_destructor_node *first_destructor;
  87.   struct arena_destructor_node *last_destructor;
  88. #endif /* ARENA_DESTRUCTOR_LIST */
  89. };
  90. /*
  91.  * nssArenaMark
  92.  *
  93.  * This type is used to mark the current state of an NSSArena.
  94.  */
  95. struct nssArenaMarkStr {
  96.   PRUint32 magic;
  97.   void *mark;
  98. #ifdef ARENA_THREADMARK
  99.   nssArenaMark *next;
  100. #endif /* ARENA_THREADMARK */
  101. #ifdef ARENA_DESTRUCTOR_LIST
  102.   struct arena_destructor_node *next_destructor;
  103.   struct arena_destructor_node *prev_destructor;
  104. #endif /* ARENA_DESTRUCTOR_LIST */
  105. };
  106. #define MARK_MAGIC 0x4d41524b /* "MARK" how original */
  107. /*
  108.  * But first, the pointer-tracking code
  109.  */
  110. #ifdef DEBUG
  111. extern const NSSError NSS_ERROR_INTERNAL_ERROR;
  112. static nssPointerTracker arena_pointer_tracker;
  113. static PRStatus
  114. arena_add_pointer
  115. (
  116.   const NSSArena *arena
  117. )
  118. {
  119.   PRStatus rv;
  120.   rv = nssPointerTracker_initialize(&arena_pointer_tracker);
  121.   if( PR_SUCCESS != rv ) {
  122.     return rv;
  123.   }
  124.   rv = nssPointerTracker_add(&arena_pointer_tracker, arena);
  125.   if( PR_SUCCESS != rv ) {
  126.     NSSError e = NSS_GetError();
  127.     if( NSS_ERROR_NO_MEMORY != e ) {
  128.       nss_SetError(NSS_ERROR_INTERNAL_ERROR);
  129.     }
  130.     return rv;
  131.   }
  132.   return PR_SUCCESS;
  133. }
  134. static PRStatus
  135. arena_remove_pointer
  136. (
  137.   const NSSArena *arena
  138. )
  139. {
  140.   PRStatus rv;
  141.   rv = nssPointerTracker_remove(&arena_pointer_tracker, arena);
  142.   if( PR_SUCCESS != rv ) {
  143.     nss_SetError(NSS_ERROR_INTERNAL_ERROR);
  144.   }
  145.   return rv;
  146. }
  147. /*
  148.  * nssArena_verifyPointer
  149.  *
  150.  * This method is only present in debug builds.
  151.  *
  152.  * If the specified pointer is a valid pointer to an NSSArena object,
  153.  * this routine will return PR_SUCCESS.  Otherwise, it will put an
  154.  * error on the error stack and return PR_FAILURE.
  155.  *
  156.  * The error may be one of the following values:
  157.  *  NSS_ERROR_INVALID_ARENA
  158.  *
  159.  * Return value:
  160.  *  PR_SUCCESS if the pointer is valid
  161.  *  PR_FAILURE if it isn't
  162.  */
  163. NSS_IMPLEMENT PRStatus
  164. nssArena_verifyPointer
  165. (
  166.   const NSSArena *arena
  167. )
  168. {
  169.   PRStatus rv;
  170.   rv = nssPointerTracker_initialize(&arena_pointer_tracker);
  171.   if( PR_SUCCESS != rv ) {
  172.     /*
  173.      * This is a little disingenious.  We have to initialize the
  174.      * tracker, because someone could "legitimately" try to verify
  175.      * an arena pointer before one is ever created.  And this step
  176.      * might fail, due to lack of memory.  But the only way that
  177.      * this step can fail is if it's doing the call_once stuff,
  178.      * (later calls just no-op).  And if it didn't no-op, there
  179.      * aren't any valid arenas.. so the argument certainly isn't one.
  180.      */
  181.     nss_SetError(NSS_ERROR_INVALID_ARENA);
  182.     return PR_FAILURE;
  183.   }
  184.   rv = nssPointerTracker_verify(&arena_pointer_tracker, arena);
  185.   if( PR_SUCCESS != rv ) {
  186.     nss_SetError(NSS_ERROR_INVALID_ARENA);
  187.     return PR_FAILURE;
  188.   }
  189.   return PR_SUCCESS;
  190. }
  191. #endif /* DEBUG */
  192. #ifdef ARENA_DESTRUCTOR_LIST
  193. struct arena_destructor_node {
  194.   struct arena_destructor_node *next;
  195.   struct arena_destructor_node *prev;
  196.   void (*destructor)(void *argument);
  197.   void *arg;
  198. };
  199. /*
  200.  * nssArena_registerDestructor
  201.  *
  202.  * This routine stores a pointer to a callback and an arbitrary
  203.  * pointer-sized argument in the arena, at the current point in
  204.  * the mark stack.  If the arena is destroyed, or an "earlier"
  205.  * mark is released, then this destructor will be called at that
  206.  * time.  Note that the destructor will be called with the arena
  207.  * locked, which means the destructor may free memory in that
  208.  * arena, but it may not allocate or cause to be allocated any
  209.  * memory.  This callback facility was included to support our
  210.  * debug-version pointer-tracker feature; overuse runs counter to
  211.  * the the original intent of arenas.  This routine returns a 
  212.  * PRStatus value; if successful, it will return PR_SUCCESS.  If 
  213.  * unsuccessful, it will set an error on the error stack and 
  214.  * return PR_FAILURE.
  215.  *
  216.  * The error may be one of the following values:
  217.  *  NSS_ERROR_INVALID_ARENA
  218.  *  NSS_ERROR_NO_MEMORY
  219.  *
  220.  * Return value:
  221.  *  PR_SUCCESS
  222.  *  PR_FAILURE
  223.  */
  224. NSS_IMPLEMENT PRStatus
  225. nssArena_registerDestructor
  226. (
  227.   NSSArena *arena,
  228.   void (*destructor)(void *argument),
  229.   void *arg
  230. )
  231. {
  232.   struct arena_destructor_node *it;
  233. #ifdef NSSDEBUG
  234.   if( PR_SUCCESS != nssArena_verifyPointer(arena) ) {
  235.     return PR_FAILURE;
  236.   }
  237. #endif /* NSSDEBUG */
  238.   
  239.   it = nss_ZNEW(arena, struct arena_destructor_node);
  240.   if( (struct arena_destructor_node *)NULL == it ) {
  241.     return PR_FAILURE;
  242.   }
  243.   it->prev = arena->last_destructor;
  244.   arena->last_destructor->next = it;
  245.   arena->last_destructor = it;
  246.   it->destructor = destructor;
  247.   it->arg = arg;
  248.   if( (nssArenaMark *)NULL != arena->last_mark ) {
  249.     arena->last_mark->prev_destructor = it->prev;
  250.     arena->last_mark->next_destructor = it->next;
  251.   }
  252.   return PR_SUCCESS;
  253. }
  254. NSS_IMPLEMENT PRStatus
  255. nssArena_deregisterDestructor
  256. (
  257.   NSSArena *arena,
  258.   void (*destructor)(void *argument),
  259.   void *arg
  260. )
  261. {
  262.   struct arena_destructor_node *it;
  263. #ifdef NSSDEBUG
  264.   if( PR_SUCCESS != nssArena_verifyPointer(arena) ) {
  265.     return PR_FAILURE;
  266.   }
  267. #endif /* NSSDEBUG */
  268.   for( it = arena->first_destructor; it; it = it->next ) {
  269.     if( (it->destructor == destructor) && (it->arg == arg) ) {
  270.       break;
  271.     }
  272.   }
  273.   if( (struct arena_destructor_node *)NULL == it ) {
  274.     nss_SetError(NSS_ERROR_NOT_FOUND);
  275.     return PR_FAILURE;
  276.   }
  277.   if( it == arena->first_destructor ) {
  278.     arena->first_destructor = it->next;
  279.   }
  280.   if( it == arena->last_destructor ) {
  281.     arena->last_destructor = it->prev;
  282.   }
  283.   if( (struct arena_destructor_node *)NULL != it->prev ) {
  284.     it->prev->next = it->next;
  285.   }
  286.   if( (struct arena_destructor_node *)NULL != it->next ) {
  287.     it->next->prev = it->prev;
  288.   }
  289.   {
  290.     nssArenaMark *m;
  291.     for( m = arena->first_mark; m; m = m->next ) {
  292.       if( m->next_destructor == it ) {
  293.         m->next_destructor = it->next;
  294.       }
  295.       if( m->prev_destructor == it ) {
  296.         m->prev_destructor = it->prev;
  297.       }
  298.     }
  299.   }
  300.   nss_ZFreeIf(it);
  301.   return PR_SUCCESS;
  302. }
  303. static void
  304. nss_arena_call_destructor_chain
  305. (
  306.   struct arena_destructor_node *it
  307. )
  308. {
  309.   for( ; it ; it = it->next ) {
  310.     (*(it->destructor))(it->arg);
  311.   }
  312. }
  313. #endif /* ARENA_DESTRUCTOR_LIST */
  314. /*
  315.  * NSSArena_Create
  316.  *
  317.  * This routine creates a new memory arena.  This routine may return
  318.  * NULL upon error, in which case it will have created an error stack.
  319.  *
  320.  * The top-level error may be one of the following values:
  321.  *  NSS_ERROR_NO_MEMORY
  322.  *
  323.  * Return value:
  324.  *  NULL upon error
  325.  *  A pointer to an NSSArena upon success
  326.  */
  327. NSS_IMPLEMENT NSSArena *
  328. NSSArena_Create
  329. (
  330.   void
  331. )
  332. {
  333.   nss_ClearErrorStack();
  334.   return nssArena_Create();
  335. }
  336. /*
  337.  * nssArena_Create
  338.  *
  339.  * This routine creates a new memory arena.  This routine may return
  340.  * NULL upon error, in which case it will have set an error on the 
  341.  * error stack.
  342.  *
  343.  * The error may be one of the following values:
  344.  *  NSS_ERROR_NO_MEMORY
  345.  *
  346.  * Return value:
  347.  *  NULL upon error
  348.  *  A pointer to an NSSArena upon success
  349.  */
  350. NSS_IMPLEMENT NSSArena *
  351. nssArena_Create
  352. (
  353.   void
  354. )
  355. {
  356.   NSSArena *rv = (NSSArena *)NULL;
  357.   rv = nss_ZNEW((NSSArena *)NULL, NSSArena);
  358.   if( (NSSArena *)NULL == rv ) {
  359.     nss_SetError(NSS_ERROR_NO_MEMORY);
  360.     return (NSSArena *)NULL;
  361.   }
  362.   rv->lock = PR_NewLock();
  363.   if( (PRLock *)NULL == rv->lock ) {
  364.     (void)nss_ZFreeIf(rv);
  365.     nss_SetError(NSS_ERROR_NO_MEMORY);
  366.     return (NSSArena *)NULL;
  367.   }
  368.   /*
  369.    * Arena sizes.  The current security code has 229 occurrences of
  370.    * PORT_NewArena.  The default chunksizes specified break down as
  371.    *
  372.    *  Size    Mult.   Specified as
  373.    *   512       1    512
  374.    *  1024       7    1024
  375.    *  2048       5    2048
  376.    *  2048       5    CRMF_DEFAULT_ARENA_SIZE
  377.    *  2048     190    DER_DEFAULT_CHUNKSIZE
  378.    *  2048      20    SEC_ASN1_DEFAULT_ARENA_SIZE
  379.    *  4096       1    4096
  380.    *
  381.    * Obviously this "default chunksize" flexibility isn't very 
  382.    * useful to us, so I'll just pick 2048.
  383.    */
  384.   PL_InitArenaPool(&rv->pool, "NSS", 2048, sizeof(double));
  385. #ifdef DEBUG
  386.   {
  387.     PRStatus st;
  388.     st = arena_add_pointer(rv);
  389.     if( PR_SUCCESS != st ) {
  390.       PL_FinishArenaPool(&rv->pool);
  391.       PR_DestroyLock(rv->lock);
  392.       (void)nss_ZFreeIf(rv);
  393.       return (NSSArena *)NULL;
  394.     }
  395.   }
  396. #endif /* DEBUG */
  397.   return rv;
  398. }
  399. /*
  400.  * NSSArena_Destroy
  401.  *
  402.  * This routine will destroy the specified arena, freeing all memory
  403.  * allocated from it.  This routine returns a PRStatus value; if 
  404.  * successful, it will return PR_SUCCESS.  If unsuccessful, it will
  405.  * create an error stack and return PR_FAILURE.
  406.  *
  407.  * The top-level error may be one of the following values:
  408.  *  NSS_ERROR_INVALID_ARENA
  409.  *
  410.  * Return value:
  411.  *  PR_SUCCESS upon success
  412.  *  PR_FAILURE upon failure
  413.  */
  414. NSS_IMPLEMENT PRStatus
  415. NSSArena_Destroy
  416. (
  417.   NSSArena *arena
  418. )
  419. {
  420.   nss_ClearErrorStack();
  421. #ifdef DEBUG
  422.   if( PR_SUCCESS != nssArena_verifyPointer(arena) ) {
  423.     return PR_FAILURE;
  424.   }
  425. #endif /* DEBUG */
  426.   return nssArena_Destroy(arena);
  427. }
  428. /*
  429.  * nssArena_Destroy
  430.  *
  431.  * This routine will destroy the specified arena, freeing all memory
  432.  * allocated from it.  This routine returns a PRStatus value; if 
  433.  * successful, it will return PR_SUCCESS.  If unsuccessful, it will
  434.  * set an error on the error stack and return PR_FAILURE.
  435.  *
  436.  * The error may be one of the following values:
  437.  *  NSS_ERROR_INVALID_ARENA
  438.  *
  439.  * Return value:
  440.  *  PR_SUCCESS
  441.  *  PR_FAILURE
  442.  */
  443. NSS_IMPLEMENT PRStatus
  444. nssArena_Destroy
  445. (
  446.   NSSArena *arena
  447. )
  448. {
  449.   PRLock *lock;
  450. #ifdef NSSDEBUG
  451.   if( PR_SUCCESS != nssArena_verifyPointer(arena) ) {
  452.     return PR_FAILURE;
  453.   }
  454. #endif /* NSSDEBUG */
  455.   PR_Lock(arena->lock);
  456.   if( (PRLock *)NULL == arena->lock ) {
  457.     /* Just got destroyed */
  458.     nss_SetError(NSS_ERROR_INVALID_ARENA);
  459.     return PR_FAILURE;
  460.   }
  461.   
  462. #ifdef DEBUG
  463.   if( PR_SUCCESS != arena_remove_pointer(arena) ) {
  464.     return PR_FAILURE;
  465.   }
  466. #endif /* DEBUG */
  467. #ifdef ARENA_DESTRUCTOR_LIST
  468.   /* Note that the arena is locked at this time */
  469.   nss_arena_call_destructor_chain(arena->first_destructor);
  470. #endif /* ARENA_DESTRUCTOR_LIST */
  471.   PL_FinishArenaPool(&arena->pool);
  472.   lock = arena->lock;
  473.   arena->lock = (PRLock *)NULL;
  474.   PR_Unlock(lock);
  475.   PR_DestroyLock(lock);
  476.   (void)nss_ZFreeIf(arena);
  477.   return PR_SUCCESS;
  478. }
  479. /*
  480.  * nssArena_Mark
  481.  *
  482.  * This routine "marks" the current state of an arena.  Space
  483.  * allocated after the arena has been marked can be freed by
  484.  * releasing the arena back to the mark with nssArena_Release,
  485.  * or committed by calling nssArena_Unmark.  When successful, 
  486.  * this routine returns a valid nssArenaMark pointer.  This 
  487.  * routine may return NULL upon error, in which case it will 
  488.  * have set an error on the error stack.
  489.  *
  490.  * The error may be one of the following values:
  491.  *  NSS_ERROR_INVALID_ARENA
  492.  *  NSS_ERROR_NO_MEMORY
  493.  *  NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD
  494.  *
  495.  * Return value:
  496.  *  NULL upon failure
  497.  *  An nssArenaMark pointer upon success
  498.  */
  499. NSS_IMPLEMENT nssArenaMark *
  500. nssArena_Mark
  501. (
  502.   NSSArena *arena
  503. )
  504. {
  505.   nssArenaMark *rv;
  506.   void *p;
  507. #ifdef NSSDEBUG
  508.   if( PR_SUCCESS != nssArena_verifyPointer(arena) ) {
  509.     return (nssArenaMark *)NULL;
  510.   }
  511. #endif /* NSSDEBUG */
  512.   PR_Lock(arena->lock);
  513.   if( (PRLock *)NULL == arena->lock ) {
  514.     /* Just got destroyed */
  515.     nss_SetError(NSS_ERROR_INVALID_ARENA);
  516.     return (nssArenaMark *)NULL;
  517.   }
  518. #ifdef ARENA_THREADMARK
  519.   if( (PRThread *)NULL == arena->marking_thread ) {
  520.     /* Unmarked.  Store our thread ID */
  521.     arena->marking_thread = PR_GetCurrentThread();
  522.     /* This call never fails. */
  523.   } else {
  524.     /* Marked.  Verify it's the current thread */
  525.     if( PR_GetCurrentThread() != arena->marking_thread ) {
  526.       PR_Unlock(arena->lock);
  527.       nss_SetError(NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD);
  528.       return (nssArenaMark *)NULL;
  529.     }
  530.   }
  531. #endif /* ARENA_THREADMARK */
  532.   p = PL_ARENA_MARK(&arena->pool);
  533.   /* No error possible */
  534.   /* Do this after the mark */
  535.   rv = nss_ZNEW(arena, nssArenaMark);
  536.   if( (nssArenaMark *)NULL == rv ) {
  537.     PR_Unlock(arena->lock);
  538.     nss_SetError(NSS_ERROR_NO_MEMORY);
  539.     return (nssArenaMark *)NULL;
  540.   }
  541. #ifdef ARENA_THREADMARK
  542.   arena->last_mark->next = rv;
  543.   arena->last_mark = rv;
  544. #endif /* ARENA_THREADMARK */
  545.   rv->mark = p;
  546.   rv->magic = MARK_MAGIC;
  547. #ifdef ARENA_DESTRUCTOR_LIST
  548.   rv->prev_destructor = arena->last_destructor;
  549. #endif /* ARENA_DESTRUCTOR_LIST */
  550.   PR_Unlock(arena->lock);
  551.   return rv;
  552. }
  553. /*
  554.  * nss_arena_unmark_release
  555.  *
  556.  * This static routine implements the routines nssArena_Release
  557.  * ans nssArena_Unmark, which are almost identical.
  558.  */
  559. static PRStatus
  560. nss_arena_unmark_release
  561. (
  562.   NSSArena *arena,
  563.   nssArenaMark *arenaMark,
  564.   PRBool release
  565. )
  566. {
  567.   void *inner_mark;
  568. #ifdef NSSDEBUG
  569.   if( PR_SUCCESS != nssArena_verifyPointer(arena) ) {
  570.     return PR_FAILURE;
  571.   }
  572. #endif /* NSSDEBUG */
  573.   if( MARK_MAGIC != arenaMark->magic ) {
  574.     nss_SetError(NSS_ERROR_INVALID_ARENA_MARK);
  575.     return PR_FAILURE;
  576.   }
  577.   PR_Lock(arena->lock);
  578.   if( (PRLock *)NULL == arena->lock ) {
  579.     /* Just got destroyed */
  580.     nss_SetError(NSS_ERROR_INVALID_ARENA);
  581.     return PR_FAILURE;
  582.   }
  583. #ifdef ARENA_THREADMARK
  584.   if( (PRThread *)NULL != arena->marking_thread ) {
  585.     if( PR_GetCurrentThread() != arena->marking_thread ) {
  586.       PR_Unlock(arena->lock);
  587.       nss_SetError(NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD);
  588.       return PR_FAILURE;
  589.     }
  590.   }
  591. #endif /* ARENA_THREADMARK */
  592.   if( MARK_MAGIC != arenaMark->magic ) {
  593.     /* Just got released */
  594.     PR_Unlock(arena->lock);
  595.     nss_SetError(NSS_ERROR_INVALID_ARENA_MARK);
  596.     return PR_FAILURE;
  597.   }
  598.   arenaMark->magic = 0;
  599.   inner_mark = arenaMark->mark;
  600. #ifdef ARENA_THREADMARK
  601.   {
  602.     nssArenaMark **pMark = &arena->first_mark;
  603.     nssArenaMark *rest;
  604.     nssArenaMark *last = (nssArenaMark *)NULL;
  605.     /* Find this mark */
  606.     while( *pMark != arenaMark ) {
  607.       last = *pMark;
  608.       pMark = &(*pMark)->next;
  609.     }
  610.     /* Remember the pointer, then zero it */
  611.     rest = (*pMark)->next;
  612.     *pMark = (nssArenaMark *)NULL;
  613.     arena->last_mark = last;
  614.     /* Invalidate any later marks being implicitly released */
  615.     for( ; (nssArenaMark *)NULL != rest; rest = rest->next ) {
  616.       rest->magic = 0;
  617.     }
  618.     /* If we just got rid of the first mark, clear the thread ID */
  619.     if( (nssArenaMark *)NULL == arena->first_mark ) {
  620.       arena->marking_thread = (PRThread *)NULL;
  621.     }
  622.   }
  623. #endif /* ARENA_THREADMARK */
  624.   if( release ) {
  625. #ifdef ARENA_DESTRUCTOR_LIST
  626.     if( (struct arena_destructor_node *)NULL != arenaMark->prev_destructor ) {
  627.       arenaMark->prev_destructor->next = (struct arena_destructor_node *)NULL;
  628.     }
  629.     arena->last_destructor = arenaMark->prev_destructor;
  630.     /* Note that the arena is locked at this time */
  631.     nss_arena_call_destructor_chain(arenaMark->next_destructor);
  632. #endif /* ARENA_DESTRUCTOR_LIST */
  633.     PR_ARENA_RELEASE(&arena->pool, inner_mark);
  634.     /* No error return */
  635.   }
  636.   PR_Unlock(arena->lock);
  637.   return PR_SUCCESS;
  638. }
  639. /*
  640.  * nssArena_Release
  641.  *
  642.  * This routine invalidates and releases all memory allocated from
  643.  * the specified arena after the point at which the specified mark
  644.  * was obtained.  This routine returns a PRStatus value; if successful,
  645.  * it will return PR_SUCCESS.  If unsuccessful, it will set an error
  646.  * on the error stack and return PR_FAILURE.
  647.  *
  648.  * The error may be one of the following values:
  649.  *  NSS_ERROR_INVALID_ARENA
  650.  *  NSS_ERROR_INVALID_ARENA_MARK
  651.  *  NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD
  652.  *
  653.  * Return value:
  654.  *  PR_SUCCESS
  655.  *  PR_FAILURE
  656.  */
  657. NSS_IMPLEMENT PRStatus
  658. nssArena_Release
  659. (
  660.   NSSArena *arena,
  661.   nssArenaMark *arenaMark
  662. )
  663. {
  664.   return nss_arena_unmark_release(arena, arenaMark, PR_TRUE);
  665. }
  666. /*
  667.  * nssArena_Unmark
  668.  *
  669.  * This routine "commits" the indicated mark and any marks after
  670.  * it, making them unreleasable.  Note that any earlier marks can
  671.  * still be released, and such a release will invalidate these
  672.  * later unmarked regions.  If an arena is to be safely shared by
  673.  * more than one thread, all marks must be either released or
  674.  * unmarked.  This routine returns a PRStatus value; if successful,
  675.  * it will return PR_SUCCESS.  If unsuccessful, it will set an error
  676.  * on the error stack and return PR_FAILURE.
  677.  *
  678.  * The error may be one of the following values:
  679.  *  NSS_ERROR_INVALID_ARENA
  680.  *  NSS_ERROR_INVALID_ARENA_MARK
  681.  *  NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD
  682.  *
  683.  * Return value:
  684.  *  PR_SUCCESS
  685.  *  PR_FAILURE
  686.  */
  687. NSS_IMPLEMENT PRStatus
  688. nssArena_Unmark
  689. (
  690.   NSSArena *arena,
  691.   nssArenaMark *arenaMark
  692. )
  693. {
  694.   return nss_arena_unmark_release(arena, arenaMark, PR_FALSE);
  695. }
  696. /*
  697.  * We prefix this header to all allocated blocks.  It is a multiple
  698.  * of the alignment size.  Note that this usage of a header may make
  699.  * purify spew bogus warnings about "potentially leaked blocks" of
  700.  * memory; if that gets too annoying we can add in a pointer to the
  701.  * header in the header itself.  There's not a lot of safety here;
  702.  * maybe we should add a magic value?
  703.  */
  704. struct pointer_header {
  705.   NSSArena *arena;
  706.   PRUint32 size;
  707. };
  708. /*
  709.  * nss_ZAlloc
  710.  *
  711.  * This routine allocates and zeroes a section of memory of the 
  712.  * size, and returns to the caller a pointer to that memory.  If
  713.  * the optional arena argument is non-null, the memory will be
  714.  * obtained from that arena; otherwise, the memory will be obtained
  715.  * from the heap.  This routine may return NULL upon error, in
  716.  * which case it will have set an error upon the error stack.  The
  717.  * value specified for size may be zero; in which case a valid 
  718.  * zero-length block of memory will be allocated.  This block may
  719.  * be expanded by calling nss_ZRealloc.
  720.  *
  721.  * The error may be one of the following values:
  722.  *  NSS_ERROR_INVALID_ARENA
  723.  *  NSS_ERROR_NO_MEMORY
  724.  *  NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD
  725.  *
  726.  * Return value:
  727.  *  NULL upon error
  728.  *  A pointer to the new segment of zeroed memory
  729.  */
  730. NSS_IMPLEMENT void *
  731. nss_ZAlloc
  732. (
  733.   NSSArena *arenaOpt,
  734.   PRUint32 size
  735. )
  736. {
  737.   struct pointer_header *h;
  738.   PRUint32 my_size = size + sizeof(struct pointer_header);
  739.   if( my_size < sizeof(struct pointer_header) ) {
  740.     /* Wrapped */
  741.     nss_SetError(NSS_ERROR_NO_MEMORY);
  742.     return (void *)NULL;
  743.   }
  744.   if( (NSSArena *)NULL == arenaOpt ) {
  745.     /* Heap allocation, no locking required. */
  746.     h = (struct pointer_header *)PR_Calloc(1, my_size);
  747.     if( (struct pointer_header *)NULL == h ) {
  748.       nss_SetError(NSS_ERROR_NO_MEMORY);
  749.       return (void *)NULL;
  750.     }
  751.     h->arena = (NSSArena *)NULL;
  752.     h->size = size;
  753.     /* We used calloc: it's already zeroed */
  754.     return (void *)((char *)h + sizeof(struct pointer_header));
  755.   } else {
  756.     void *p;
  757.     void *rv;
  758.     /* Arena allocation */
  759. #ifdef NSSDEBUG
  760.     if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
  761.       return (void *)NULL;
  762.     }
  763. #endif /* NSSDEBUG */
  764.     PR_Lock(arenaOpt->lock);
  765.     if( (PRLock *)NULL == arenaOpt->lock ) {
  766.       /* Just got destroyed */
  767.       nss_SetError(NSS_ERROR_INVALID_ARENA);
  768.       return (void *)NULL;
  769.     }
  770. #ifdef ARENA_THREADMARK
  771.     if( (PRThread *)NULL != arenaOpt->marking_thread ) {
  772.       if( PR_GetCurrentThread() != arenaOpt->marking_thread ) {
  773.         nss_SetError(NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD);
  774.         PR_Unlock(arenaOpt->lock);
  775.         return (void *)NULL;
  776.       }
  777.     }
  778. #endif /* ARENA_THREADMARK */
  779.     PR_ARENA_ALLOCATE(p, &arenaOpt->pool, my_size);
  780.     if( (void *)NULL == p ) {
  781.       PR_Unlock(arenaOpt->lock);
  782.       nss_SetError(NSS_ERROR_NO_MEMORY);
  783.       return (void *)NULL;
  784.     }
  785.     /* 
  786.      * Do this before we unlock.  This way if the user is using
  787.      * an arena in one thread while destroying it in another, he'll
  788.      * fault/FMR in his code, not ours.
  789.      */
  790.     h = (struct pointer_header *)p;
  791.     h->arena = arenaOpt;
  792.     h->size = size;
  793.     rv = (void *)((char *)h + sizeof(struct pointer_header));
  794.     (void)nsslibc_memset(rv, 0, size);
  795.     PR_Unlock(arenaOpt->lock);
  796.     return rv;
  797.   }
  798.   /*NOTREACHED*/
  799. }
  800. /*
  801.  * nss_ZFreeIf
  802.  *
  803.  * If the specified pointer is non-null, then the region of memory 
  804.  * to which it points -- which must have been allocated with 
  805.  * nss_ZAlloc -- will be zeroed and released.  This routine 
  806.  * returns a PRStatus value; if successful, it will return PR_SUCCESS.
  807.  * If unsuccessful, it will set an error on the error stack and return 
  808.  * PR_FAILURE.
  809.  *
  810.  * The error may be one of the following values:
  811.  *  NSS_ERROR_INVALID_POINTER
  812.  *
  813.  * Return value:
  814.  *  PR_SUCCESS
  815.  *  PR_FAILURE
  816.  */
  817. NSS_IMPLEMENT PRStatus
  818. nss_ZFreeIf
  819. (
  820.   void *pointer
  821. )
  822. {
  823.   struct pointer_header *h;
  824.   if( (void *)NULL == pointer ) {
  825.     return PR_SUCCESS;
  826.   }
  827.   h = (struct pointer_header *)&((char *)pointer)
  828.     [ - sizeof(struct pointer_header) ];
  829.   /* Check any magic here */
  830.   if( (NSSArena *)NULL == h->arena ) {
  831.     /* Heap */
  832.     (void)nsslibc_memset(pointer, 0, h->size);
  833.     PR_Free(h);
  834.     return PR_SUCCESS;
  835.   } else {
  836.     /* Arena */
  837. #ifdef NSSDEBUG
  838.     if( PR_SUCCESS != nssArena_verifyPointer(h->arena) ) {
  839.       return PR_FAILURE;
  840.     }
  841. #endif /* NSSDEBUG */
  842.     PR_Lock(h->arena->lock);
  843.     if( (PRLock *)NULL == h->arena->lock ) {
  844.       /* Just got destroyed.. so this pointer is invalid */
  845.       nss_SetError(NSS_ERROR_INVALID_POINTER);
  846.       return PR_FAILURE;
  847.     }
  848.     (void)nsslibc_memset(pointer, 0, h->size);
  849.     /* No way to "free" it within an NSPR arena. */
  850.     PR_Unlock(h->arena->lock);
  851.     return PR_SUCCESS;
  852.   }
  853.   /*NOTREACHED*/
  854. }
  855. /*
  856.  * nss_ZRealloc
  857.  *
  858.  * This routine reallocates a block of memory obtained by calling
  859.  * nss_ZAlloc or nss_ZRealloc.  The portion of memory 
  860.  * between the new and old sizes -- which is either being newly
  861.  * obtained or released -- is in either case zeroed.  This routine 
  862.  * may return NULL upon failure, in which case it will have placed 
  863.  * an error on the error stack.
  864.  *
  865.  * The error may be one of the following values:
  866.  *  NSS_ERROR_INVALID_POINTER
  867.  *  NSS_ERROR_NO_MEMORY
  868.  *  NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD
  869.  *
  870.  * Return value:
  871.  *  NULL upon error
  872.  *  A pointer to the replacement segment of memory
  873.  */
  874. NSS_EXTERN void *
  875. nss_ZRealloc
  876. (
  877.   void *pointer,
  878.   PRUint32 newSize
  879. )
  880. {
  881.   struct pointer_header *h, *new_h;
  882.   PRUint32 my_newSize = newSize + sizeof(struct pointer_header);
  883.   void *rv;
  884.   if( my_newSize < sizeof(struct pointer_header) ) {
  885.     /* Wrapped */
  886.     nss_SetError(NSS_ERROR_NO_MEMORY);
  887.     return (void *)NULL;
  888.   }
  889.   if( (void *)NULL == pointer ) {
  890.     nss_SetError(NSS_ERROR_INVALID_POINTER);
  891.     return (void *)NULL;
  892.   }
  893.   h = (struct pointer_header *)&((char *)pointer)
  894.     [ - sizeof(struct pointer_header) ];
  895.   /* Check any magic here */
  896.   if( newSize == h->size ) {
  897.     /* saves thrashing */
  898.     return pointer;
  899.   }
  900.   if( (NSSArena *)NULL == h->arena ) {
  901.     /* Heap */
  902.     new_h = (struct pointer_header *)PR_Calloc(1, my_newSize);
  903.     if( (struct pointer_header *)NULL == new_h ) {
  904.       nss_SetError(NSS_ERROR_NO_MEMORY);
  905.       return (void *)NULL;
  906.     }
  907.     new_h->arena = (NSSArena *)NULL;
  908.     new_h->size = newSize;
  909.     rv = (void *)((char *)new_h + sizeof(struct pointer_header));
  910.     if( newSize > h->size ) {
  911.       (void)nsslibc_memcpy(rv, pointer, h->size);
  912.       (void)nsslibc_memset(&((char *)rv)[ h->size ], 
  913.                            0, (newSize - h->size));
  914.     } else {
  915.       (void)nsslibc_memcpy(rv, pointer, newSize);
  916.     }
  917.     (void)nsslibc_memset(pointer, 0, h->size);
  918.     h->size = 0;
  919.     PR_Free(h);
  920.     return rv;
  921.   } else {
  922.     void *p;
  923.     /* Arena */
  924. #ifdef NSSDEBUG
  925.     if( PR_SUCCESS != nssArena_verifyPointer(h->arena) ) {
  926.       return (void *)NULL;
  927.     }
  928. #endif /* NSSDEBUG */
  929.     PR_Lock(h->arena->lock);
  930.     if( (PRLock *)NULL == h->arena->lock ) {
  931.       /* Just got destroyed.. so this pointer is invalid */
  932.       nss_SetError(NSS_ERROR_INVALID_POINTER);
  933.       return (void *)NULL;
  934.     }
  935. #ifdef ARENA_THREADMARK
  936.     if( (PRThread *)NULL != h->arena->marking_thread ) {
  937.       if( PR_GetCurrentThread() != h->arena->marking_thread ) {
  938.         PR_Unlock(h->arena->lock);
  939.         nss_SetError(NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD);
  940.         return (void *)NULL;
  941.       }
  942.     }
  943. #endif /* ARENA_THREADMARK */
  944.     if( newSize < h->size ) {
  945.       /*
  946.        * We have no general way of returning memory to the arena
  947.        * (mark/release doesn't work because things may have been
  948.        * allocated after this object), so the memory is gone
  949.        * anyway.  We might as well just return the same pointer to
  950.        * the user, saying "yeah, uh-hunh, you can only use less of
  951.        * it now."  We'll zero the leftover part, of course.  And
  952.        * in fact we might as well *not* adjust h->size-- this way,
  953.        * if the user reallocs back up to something not greater than
  954.        * the original size, then voila, there's the memory!  This
  955.        * way a thrash big/small/big/small doesn't burn up the arena.
  956.        */
  957.       char *extra = &((char *)pointer)[ newSize ];
  958.       (void)nsslibc_memset(extra, 0, (h->size - newSize));
  959.       PR_Unlock(h->arena->lock);
  960.       return pointer;
  961.     }
  962.     PR_ARENA_ALLOCATE(p, &h->arena->pool, my_newSize);
  963.     if( (void *)NULL == p ) {
  964.       PR_Unlock(h->arena->lock);
  965.       nss_SetError(NSS_ERROR_NO_MEMORY);
  966.       return (void *)NULL;
  967.     }
  968.     new_h = (struct pointer_header *)p;
  969.     new_h->arena = h->arena;
  970.     new_h->size = newSize;
  971.     rv = (void *)((char *)h + sizeof(struct pointer_header));
  972.     (void)nsslibc_memcpy(rv, pointer, h->size);
  973.     (void)nsslibc_memset(&((char *)rv)[ h->size ], 0, 
  974.                          (newSize - h->size));
  975.     (void)nsslibc_memset(pointer, 0, h->size);
  976.     h->arena = (NSSArena *)NULL;
  977.     h->size = 0;
  978.     PR_Unlock(h->arena->lock);
  979.     return rv;
  980.   }
  981.   /*NOTREACHED*/
  982. }