diff options
-rw-r--r-- | lib/ds/plarena.c | 154 | ||||
-rw-r--r-- | lib/tests/Makefile | 3 | ||||
-rw-r--r-- | lib/tests/arena.c | 115 |
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(); |