summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/ds/plarena.c154
-rw-r--r--lib/tests/Makefile3
-rw-r--r--lib/tests/arena.c115
3 files changed, 206 insertions, 66 deletions
diff --git a/lib/ds/plarena.c b/lib/ds/plarena.c
index 45ac890b..e1eb7960 100644
--- a/lib/ds/plarena.c
+++ b/lib/ds/plarena.c
@@ -43,7 +43,7 @@
#include "prmem.h"
#include "prbit.h"
#include "prlog.h"
-#include "prmon.h"
+#include "prlock.h"
#include "prinit.h"
static PLArena *arena_freelist;
@@ -58,7 +58,7 @@ static PLArenaStats *arena_stats_list;
#define PL_ARENA_DEFAULT_ALIGN sizeof(double)
-static PRMonitor *arenaLock;
+static PRLock *arenaLock;
static PRCallOnceType once;
/*
@@ -78,7 +78,7 @@ static PRCallOnceType once;
static PRStatus InitializeArenas( void )
{
PR_ASSERT( arenaLock == NULL );
- arenaLock = PR_NewMonitor();
+ arenaLock = PR_NewLock();
if ( arenaLock == NULL )
return PR_FAILURE;
else
@@ -90,13 +90,13 @@ static PRStatus LockArena( void )
PRStatus rc = PR_CallOnce( &once, InitializeArenas );
if ( PR_FAILURE != rc )
- PR_EnterMonitor( arenaLock );
+ PR_Lock( arenaLock );
return(rc);
} /* end LockArena() */
static void UnlockArena( void )
{
- PR_ExitMonitor( arenaLock );
+ PR_Unlock( arenaLock );
return;
} /* end UnlockArena() */
@@ -114,7 +114,7 @@ PR_IMPLEMENT(void) PL_InitArenaPool(
pool->first.base = pool->first.avail = pool->first.limit =
(PRUword)PL_ARENA_ALIGN(pool, &pool->first + 1);
pool->current = &pool->first;
- pool->arenasize = size;
+ pool->arenasize = size;
#ifdef PL_ARENAMETER
memset(&pool->stats, 0, sizeof pool->stats);
pool->stats.name = strdup(name);
@@ -123,56 +123,112 @@ PR_IMPLEMENT(void) PL_InitArenaPool(
#endif
}
+
+/*
+** PL_ArenaAllocate() -- allocate space from an arena pool
+**
+** Description: PL_ArenaAllocate() allocates space from an arena
+** pool.
+**
+** First, try to satisfy the request from arenas starting at
+** 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
+**
+** Notes: The original implementation had some difficult to
+** solve bugs; the code was difficult to read. Sometimes it's
+** just easier to rewrite it. I did that. larryh.
+**
+** See also: bugzilla: 45343.
+**
+*/
+
PR_IMPLEMENT(void *) PL_ArenaAllocate(PLArenaPool *pool, PRUint32 nb)
{
- PLArena **ap, *a, *b;
- PRUint32 sz;
- void *p;
+ PLArena *a;
+ char *rp; /* returned pointer */
PR_ASSERT((nb & pool->mask) == 0);
-#if defined(WIN16)
- if (nb >= 60000U)
- return 0;
-#endif /* WIN16 */
- if ( PR_FAILURE == LockArena())
- return(0);
- ap = &arena_freelist;
- for (a = pool->current; a->avail + nb > a->limit; pool->current = a) {
- if (a->next) { /* move to next arena */
- a = a->next;
- continue;
- }
- while ((b = *ap) != 0) { /* reclaim a free arena */
- if (b->limit - b->base == pool->arenasize) {
- *ap = b->next;
- b->next = 0;
- a = a->next = b;
- COUNT(pool, nreclaims);
- goto claim;
+
+ nb = (PRUword)PL_ARENA_ALIGN(pool, nb); /* force alignment */
+
+ /* attempt to allocate from arenas at pool->current */
+ {
+ a = pool->current;
+ do {
+ if ( a->avail +nb <= a->limit ) {
+ pool->current = a;
+ rp = (void *)a->avail;
+ a->avail += nb;
+ return rp;
+ }
+ } 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 = p = arena_freelist; a != NULL ; p = a, a = a->next ) {
+ if ( a->base +nb <= a->limit ) {
+ if ( p == arena_freelist )
+ arena_freelist = a->next;
+ else
+ p->next = a->next;
+ UnlockArena();
+ a->avail = a->base;
+ rp = (void *)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);
}
- ap = &b->next;
}
- sz = PR_MAX(pool->arenasize, nb); /* allocate a new arena */
- sz += sizeof *a + pool->mask; /* header and alignment slop */
- b = (PLArena*)PR_MALLOC(sz);
- if (!b)
- {
- UnlockArena();
- return 0;
+ UnlockArena();
+ }
+
+ /* attempt to allocate from the heap */
+ {
+ PRUint32 sz = PR_MAX(pool->arenasize, nb);
+ sz += (PRUword)PL_ARENA_ALIGN(pool, sizeof(*a)); /* force alignment */
+ a = (PLArena*)PR_MALLOC(sz);
+ if ( NULL != a ) {
+ a->limit = (PRUword)a + sz;
+ a->base = a->avail = (PRUword)PL_ARENA_ALIGN(pool, a + 1);
+ rp = (void *)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;
+ PL_COUNT_ARENA(pool,++);
+ COUNT(pool, nmallocs);
+ return(rp);
}
- a = a->next = b;
- a->next = 0;
- a->limit = (PRUword)a + sz;
- PL_COUNT_ARENA(pool,++);
- COUNT(pool, nmallocs);
- claim:
- a->base = a->avail = (PRUword)PL_ARENA_ALIGN(pool, a + 1);
}
- UnlockArena();
- p = (void *)a->avail;
- a->avail += nb;
- return p;
-}
+
+ /* we got to here, and there's no memory to allocate */
+ return(NULL);
+} /* --- end PL_ArenaAllocate() --- */
PR_IMPLEMENT(void *) PL_ArenaGrow(
PLArenaPool *pool, void *p, PRUint32 size, PRUint32 incr)
@@ -236,7 +292,7 @@ PR_IMPLEMENT(void) PL_ArenaRelease(PLArenaPool *pool, char *mark)
for (a = pool->first.next; 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, PR_TRUE);
+ FreeArenaList(pool, a, PR_FALSE);
return;
}
}
diff --git a/lib/tests/Makefile b/lib/tests/Makefile
index 18495367..90d328c5 100644
--- a/lib/tests/Makefile
+++ b/lib/tests/Makefile
@@ -38,7 +38,7 @@ MOD_DEPTH = ../..
include $(MOD_DEPTH)/config/config.mk
ifeq ($(OS_ARCH), WINNT)
-DIRS = windows
+# DIRS = windows
endif
ifeq ($(OS_TARGET), WIN16)
@@ -46,6 +46,7 @@ OS_CFLAGS = $(OS_EXE_CFLAGS)
endif
CSRCS = \
+ arena.c \
string.c \
base64t.c
diff --git a/lib/tests/arena.c b/lib/tests/arena.c
index fa4b666d..7dd90f31 100644
--- a/lib/tests/arena.c
+++ b/lib/tests/arena.c
@@ -66,6 +66,43 @@ void DumpAll( void )
}
/*
+** Test Arena allocation.
+*/
+static void ArenaAllocate( void )
+{
+ PLArenaPool ap;
+ void *ptr;
+ PRInt32 i;
+
+ PL_InitArenaPool( &ap, "AllocArena", 2048, sizeof(double));
+ PR_LOG( tLM, PR_LOG_DEBUG, ("AA, InitPool -- Pool: %p. first: %p, current: %p, size: %d",
+ &ap, ap.first, ap.current, ap.arenasize ));
+
+ for( i = 0; i < 150; i++ )
+ {
+ PL_ARENA_ALLOCATE( ptr, &ap, 512 );
+ PR_LOG( tLM, PR_LOG_DEBUG,("AA, after alloc -- Pool: %p. first: %p, current: %p, size: %d",
+ &ap, ap.first, ap.current, ap.arenasize ));
+ PR_LOG( tLM, PR_LOG_DEBUG,(
+ "AA -- Pool: %p. alloc: %p ", &ap, ptr ));
+ }
+
+ PL_FreeArenaPool( &ap );
+
+ for( i = 0; i < 221; i++ )
+ {
+ PL_ARENA_ALLOCATE( ptr, &ap, 512 );
+ PR_LOG( tLM, PR_LOG_DEBUG,("AA, after alloc -- Pool: %p. first: %p, current: %p, size: %d",
+ &ap, ap.first, ap.current, ap.arenasize ));
+ PR_LOG( tLM, PR_LOG_DEBUG,(
+ "AA -- Pool: %p. alloc: %p ", &ap, ptr ));
+ }
+
+ PL_FreeArenaPool( &ap );
+
+ return;
+} /* end ArenaGrow() */
+/*
** Test Arena grow.
*/
static void ArenaGrow( void )
@@ -96,27 +133,71 @@ static void ArenaGrow( void )
static void MarkAndRelease( void )
{
PLArenaPool ap;
- void *ptr;
- void *mark;
+ void *ptr = NULL;
+ void *mark0, *mark1;
+ PRIntn i;
PL_InitArenaPool( &ap, "TheArena", 4096, sizeof(double));
- PL_ARENA_ALLOCATE( ptr, &ap, 512 );
+ mark0 = PL_ARENA_MARK( &ap );
+ PR_LOG( tLM, PR_LOG_DEBUG,
+ ("mark0. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p, m0: %p",
+ &ap, ap.first.next, ap.current, ap.arenasize, ptr, mark0 ));
- mark = PL_ARENA_MARK( &ap );
+ for( i = 0; i < 201; i++ )
+ {
+ PL_ARENA_ALLOCATE( ptr, &ap, 512 );
+ PR_LOG( tLM, PR_LOG_DEBUG,
+ ("mr. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p",
+ &ap, ap.first.next, ap.current, ap.arenasize, ptr ));
+ }
- PL_ARENA_ALLOCATE( ptr, &ap, 512 );
-
- PL_ARENA_RELEASE( &ap, mark );
- PL_ARENA_ALLOCATE( ptr, &ap, 512 );
+ mark1 = PL_ARENA_MARK( &ap );
+ PR_LOG( tLM, PR_LOG_DEBUG,
+ ("mark1. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p, m1: %p",
+ &ap, ap.first.next, ap.current, ap.arenasize, ptr, mark1 ));
- if ( ptr != mark )
- {
- failed_already = PR_TRUE;
- PR_LOG( tLM, PR_LOG_ERROR, ("Mark and Release failed: expected %p, got %p\n", mark, ptr));
- }
- else
- PR_LOG( tLM, PR_LOG_DEBUG, ("Mark and Release passed\n"));
+
+ for( i = 0; i < 225; i++ )
+ {
+ PL_ARENA_ALLOCATE( ptr, &ap, 512 );
+ PR_LOG( tLM, PR_LOG_DEBUG,
+ ("mr. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p",
+ &ap, ap.first.next, ap.current, ap.arenasize, ptr ));
+ }
+
+ PL_ARENA_RELEASE( &ap, mark1 );
+ PR_LOG( tLM, PR_LOG_DEBUG,
+ ("Release-1: %p -- Pool: %p. first: %p, current: %p, size: %d",
+ mark1, &ap, ap.first, ap.current, ap.arenasize ));
+
+ for( i = 0; i < 20; i++ )
+ {
+ PL_ARENA_ALLOCATE( ptr, &ap, 512 );
+ PR_LOG( tLM, PR_LOG_DEBUG,
+ ("mr. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p",
+ &ap, ap.first.next, ap.current, ap.arenasize, ptr ));
+ }
+
+ PL_ARENA_RELEASE( &ap, mark1 );
+ PR_LOG( tLM, PR_LOG_DEBUG,
+ ("Release-1. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p",
+ &ap, ap.first.next, ap.current, ap.arenasize, ptr ));
+
+ PL_ARENA_RELEASE( &ap, mark0 );
+ PR_LOG( tLM, PR_LOG_DEBUG,
+ ("Release-0. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p",
+ &ap, ap.first.next, ap.current, ap.arenasize, ptr ));
+
+ PL_FreeArenaPool( &ap );
+ PR_LOG( tLM, PR_LOG_DEBUG,
+ ("Free. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p",
+ &ap, ap.first.next, ap.current, ap.arenasize, ptr ));
+ PL_FinishArenaPool( &ap );
+ PR_LOG( tLM, PR_LOG_DEBUG,
+ ("Finish. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p",
+ &ap, ap.first.next, ap.current, ap.arenasize, ptr ));
+
return;
} /* end MarkAndRelease() */
@@ -302,8 +383,10 @@ PRIntn main(PRIntn argc, char *argv[])
tLM = PR_NewLogModule("testcase");
-
+#if 0
+ ArenaAllocate();
ArenaGrow();
+#endif
MarkAndRelease();