Backout c661f2c5cd87 and bf22fcece06e (from bug 1252639) because NSPR changes aren't supposed to land on mozilla-inbound.

--HG--
extra : rebase_source : 360a3cc50807b991a421e7d163d7d5442eef59e7
This commit is contained in:
Nicholas Nethercote 2016-03-09 15:36:02 +11:00
Родитель b954395165
Коммит 1d9d77e07a
3 изменённых файлов: 210 добавлений и 92 удалений

Просмотреть файл

@ -17,6 +17,8 @@
#include "prlock.h"
#include "prinit.h"
static PLArena *arena_freelist;
#ifdef PL_ARENAMETER
static PLArenaStats *arena_stats_list;
@ -27,6 +29,49 @@ static PLArenaStats *arena_stats_list;
#define PL_ARENA_DEFAULT_ALIGN sizeof(double)
static PRLock *arenaLock;
static PRCallOnceType once;
static const PRCallOnceType pristineCallOnce;
/*
** InitializeArenas() -- Initialize arena operations.
**
** InitializeArenas() is called exactly once and only once from
** LockArena(). This function creates the arena protection
** lock: arenaLock.
**
** Note: If the arenaLock cannot be created, InitializeArenas()
** fails quietly, returning only PR_FAILURE. This percolates up
** to the application using the Arena API. He gets no arena
** from PL_ArenaAllocate(). It's up to him to fail gracefully
** or recover.
**
*/
static PRStatus InitializeArenas( void )
{
PR_ASSERT( arenaLock == NULL );
arenaLock = PR_NewLock();
if ( arenaLock == NULL )
return PR_FAILURE;
else
return PR_SUCCESS;
} /* end ArenaInitialize() */
static PRStatus LockArena( void )
{
PRStatus rc = PR_CallOnce( &once, InitializeArenas );
if ( PR_FAILURE != rc )
PR_Lock( arenaLock );
return(rc);
} /* end LockArena() */
static void UnlockArena( void )
{
PR_Unlock( arenaLock );
return;
} /* end UnlockArena() */
PR_IMPLEMENT(void) PL_InitArenaPool(
PLArenaPool *pool, const char *name, PRUint32 size, PRUint32 align)
{
@ -79,7 +124,14 @@ PR_IMPLEMENT(void) PL_InitArenaPool(
** pool.
**
** First, try to satisfy the request from arenas starting at
** pool->current. Then try to allocate a new arena from the heap.
** pool->current.
**
** If there is not enough space in the arena pool->current, try
** to claim an arena, on a first fit basis, from the global
** freelist (arena_freelist).
**
** If no arena in arena_freelist is suitable, then try to
** allocate a new arena from the heap.
**
** Returns: pointer to allocated space or NULL
**
@ -117,6 +169,37 @@ PR_IMPLEMENT(void *) PL_ArenaAllocate(PLArenaPool *pool, PRUint32 nb)
} while( NULL != (a = a->next) );
}
/* attempt to allocate from arena_freelist */
{
PLArena *p; /* previous pointer, for unlinking from freelist */
/* lock the arena_freelist. Make access to the freelist MT-Safe */
if ( PR_FAILURE == LockArena())
return(0);
for ( a = arena_freelist, p = NULL; a != NULL ; p = a, a = a->next ) {
if ( nb <= a->limit - a->base ) {
if ( p == NULL )
arena_freelist = a->next;
else
p->next = a->next;
UnlockArena();
a->avail = a->base;
rp = (char *)a->avail;
a->avail += nb;
/* the newly allocated arena is linked after pool->current
* and becomes pool->current */
a->next = pool->current->next;
pool->current->next = a;
pool->current = a;
if ( NULL == pool->first.next )
pool->first.next = a;
return(rp);
}
}
UnlockArena();
}
/* attempt to allocate from the heap */
{
PRUint32 sz = PR_MAX(pool->arenasize, nb);
@ -163,11 +246,10 @@ PR_IMPLEMENT(void *) PL_ArenaGrow(
return newp;
}
PR_IMPLEMENT(void) PL_ClearArenaPool(PLArenaPool *pool, PRInt32 pattern)
static void ClearArenaList(PLArena *a, PRInt32 pattern)
{
PLArena *a;
for (a = pool->first.next; a; a = a->next) {
for (; a; a = a->next) {
PR_ASSERT(a->base <= a->avail && a->avail <= a->limit);
a->avail = a->base;
PL_CLEAR_UNUSED_PATTERN(a, pattern);
@ -175,25 +257,48 @@ PR_IMPLEMENT(void) PL_ClearArenaPool(PLArenaPool *pool, PRInt32 pattern)
}
}
PR_IMPLEMENT(void) PL_ClearArenaPool(PLArenaPool *pool, PRInt32 pattern)
{
ClearArenaList(pool->first.next, pattern);
}
/*
* Free tail arenas linked after head, which may not be the true list head.
* Reset pool->current to point to head in case it pointed at a tail arena.
*/
static void FreeArenaList(PLArenaPool *pool, PLArena *head)
static void FreeArenaList(PLArenaPool *pool, PLArena *head, PRBool reallyFree)
{
PLArena *a = head->next;
PLArena **ap, *a;
ap = &head->next;
a = *ap;
if (!a)
return;
head->next = NULL;
#ifdef DEBUG
ClearArenaList(a, PL_FREE_PATTERN);
#endif
do {
PLArena *tmp = a;
a = a->next;
PL_CLEAR_ARENA(tmp);
PL_COUNT_ARENA(pool,--);
PR_DELETE(tmp);
} while (a);
if (reallyFree) {
do {
*ap = a->next;
PL_CLEAR_ARENA(a);
PL_COUNT_ARENA(pool,--);
PR_DELETE(a);
} while ((a = *ap) != 0);
} else {
/* Insert the whole arena chain at the front of the freelist. */
do {
PL_MAKE_MEM_NOACCESS((void*)(*ap)->base,
(*ap)->limit - (*ap)->base);
ap = &(*ap)->next;
} while (*ap);
LockArena();
*ap = arena_freelist;
arena_freelist = a;
head->next = 0;
UnlockArena();
}
pool->current = head;
}
@ -205,7 +310,7 @@ PR_IMPLEMENT(void) PL_ArenaRelease(PLArenaPool *pool, char *mark)
for (a = &pool->first; a; a = a->next) {
if (PR_UPTRDIFF(mark, a->base) <= PR_UPTRDIFF(a->avail, a->base)) {
a->avail = (PRUword)PL_ARENA_ALIGN(pool, mark);
FreeArenaList(pool, a);
FreeArenaList(pool, a, PR_FALSE);
return;
}
}
@ -213,13 +318,13 @@ PR_IMPLEMENT(void) PL_ArenaRelease(PLArenaPool *pool, char *mark)
PR_IMPLEMENT(void) PL_FreeArenaPool(PLArenaPool *pool)
{
FreeArenaList(pool, &pool->first);
FreeArenaList(pool, &pool->first, PR_FALSE);
COUNT(pool, ndeallocs);
}
PR_IMPLEMENT(void) PL_FinishArenaPool(PLArenaPool *pool)
{
FreeArenaList(pool, &pool->first);
FreeArenaList(pool, &pool->first, PR_TRUE);
#ifdef PL_ARENAMETER
{
PLArenaStats *stats, **statsp;
@ -243,6 +348,19 @@ PR_IMPLEMENT(void) PL_CompactArenaPool(PLArenaPool *ap)
PR_IMPLEMENT(void) PL_ArenaFinish(void)
{
PLArena *a, *next;
for (a = arena_freelist; a; a = next) {
next = a->next;
PR_DELETE(a);
}
arena_freelist = NULL;
if (arenaLock) {
PR_DestroyLock(arenaLock);
arenaLock = NULL;
}
once = pristineCallOnce;
}
PR_IMPLEMENT(size_t) PL_SizeOfArenaPoolExcludingPool(

Просмотреть файл

@ -13,6 +13,7 @@
* Also supports LIFO allocation (PL_ARENA_MARK/PL_ARENA_RELEASE).
*/
#include "prtypes.h"
#include "plarenas.h"
PR_BEGIN_EXTERN_C
@ -46,8 +47,6 @@ struct PLArenaStats {
};
#endif
typedef struct PLArenaPool PLArenaPool;
struct PLArenaPool {
PLArena first; /* first arena in pool list */
PLArena *current; /* arena from which to allocate space */
@ -226,74 +225,6 @@ PR_IMPORT(void) __asan_unpoison_memory_region(void const volatile *addr, size_t
(a) = 0; \
PR_END_MACRO
/*
** Initialize an arena pool with the given name for debugging and metering,
** with a minimum gross size per arena of size bytes. The net size per arena
** is smaller than the gross size by a header of four pointers plus any
** necessary padding for alignment.
**
** Note: choose a gross size that's a power of two to avoid the heap allocator
** rounding the size up.
**/
PR_EXTERN(void) PL_InitArenaPool(
PLArenaPool *pool, const char *name, PRUint32 size, PRUint32 align);
/*
** Finish using arenas, freeing all memory associated with them.
** NOTE: this function is now a no-op. If you want to free a single
** PLArenaPoolUse use PL_FreeArenaPool() or PL_FinishArenaPool().
**/
PR_EXTERN(void) PL_ArenaFinish(void);
/*
** Free the arenas in pool. The user may continue to allocate from pool
** after calling this function. There is no need to call PL_InitArenaPool()
** again unless PL_FinishArenaPool(pool) has been called.
**/
PR_EXTERN(void) PL_FreeArenaPool(PLArenaPool *pool);
/*
** Free the arenas in pool and finish using it altogether.
**/
PR_EXTERN(void) PL_FinishArenaPool(PLArenaPool *pool);
/*
** Compact all of the arenas in a pool so that no space is wasted.
** NOT IMPLEMENTED. Do not use.
**/
PR_EXTERN(void) PL_CompactArenaPool(PLArenaPool *pool);
/*
** Friend functions used by the PL_ARENA_*() macros.
**
** WARNING: do not call these functions directly. Always use the
** PL_ARENA_*() macros.
**/
PR_EXTERN(void *) PL_ArenaAllocate(PLArenaPool *pool, PRUint32 nb);
PR_EXTERN(void *) PL_ArenaGrow(
PLArenaPool *pool, void *p, PRUint32 size, PRUint32 incr);
PR_EXTERN(void) PL_ArenaRelease(PLArenaPool *pool, char *mark);
/*
** memset contents of all arenas in pool to pattern
*/
PR_EXTERN(void) PL_ClearArenaPool(PLArenaPool *pool, PRInt32 pattern);
/*
** A function like malloc_size() or malloc_usable_size() that measures the
** size of a heap block.
*/
typedef size_t (*PLMallocSizeFn)(const void *ptr);
/*
** Measure all memory used by a PLArenaPool, excluding the PLArenaPool
** structure.
*/
PR_EXTERN(size_t) PL_SizeOfArenaPoolExcludingPool(
const PLArenaPool *pool, PLMallocSizeFn mallocSizeOf);
#ifdef PL_ARENAMETER
#include <stdio.h>

Просмотреть файл

@ -3,10 +3,79 @@
* 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/. */
#ifndef PLARENAS_H
#define PLARENAS_H
PR_BEGIN_EXTERN_C
typedef struct PLArenaPool PLArenaPool;
/*
** PLArena-related declarations used to be split between plarenas.h and
** plarena.h. That split wasn't useful, so now all the declarations are in
** plarena.h. However, this file still exists so that any old code that
** includes it will still work.
** Initialize an arena pool with the given name for debugging and metering,
** with a minimum gross size per arena of size bytes. The net size per arena
** is smaller than the gross size by a header of four pointers plus any
** necessary padding for alignment.
**
** Note: choose a gross size that's a power of two to avoid the heap allocator
** rounding the size up.
**/
#include "plarena.h"
PR_EXTERN(void) PL_InitArenaPool(
PLArenaPool *pool, const char *name, PRUint32 size, PRUint32 align);
/*
** Finish using arenas, freeing all memory associated with them.
**/
PR_EXTERN(void) PL_ArenaFinish(void);
/*
** Free the arenas in pool. The user may continue to allocate from pool
** after calling this function. There is no need to call PL_InitArenaPool()
** again unless PL_FinishArenaPool(pool) has been called.
**/
PR_EXTERN(void) PL_FreeArenaPool(PLArenaPool *pool);
/*
** Free the arenas in pool and finish using it altogether.
**/
PR_EXTERN(void) PL_FinishArenaPool(PLArenaPool *pool);
/*
** Compact all of the arenas in a pool so that no space is wasted.
** NOT IMPLEMENTED. Do not use.
**/
PR_EXTERN(void) PL_CompactArenaPool(PLArenaPool *pool);
/*
** Friend functions used by the PL_ARENA_*() macros.
**
** WARNING: do not call these functions directly. Always use the
** PL_ARENA_*() macros.
**/
PR_EXTERN(void *) PL_ArenaAllocate(PLArenaPool *pool, PRUint32 nb);
PR_EXTERN(void *) PL_ArenaGrow(
PLArenaPool *pool, void *p, PRUint32 size, PRUint32 incr);
PR_EXTERN(void) PL_ArenaRelease(PLArenaPool *pool, char *mark);
/*
** memset contents of all arenas in pool to pattern
*/
PR_EXTERN(void) PL_ClearArenaPool(PLArenaPool *pool, PRInt32 pattern);
/*
** A function like malloc_size() or malloc_usable_size() that measures the
** size of a heap block.
*/
typedef size_t (*PLMallocSizeFn)(const void *ptr);
/*
** Measure all memory used by a PLArenaPool, excluding the PLArenaPool
** structure.
*/
PR_EXTERN(size_t) PL_SizeOfArenaPoolExcludingPool(
const PLArenaPool *pool, PLMallocSizeFn mallocSizeOf);
PR_END_EXTERN_C
#endif /* PLARENAS_H */