X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fpool.c;h=45938fe9716c316a6f708c22a5a232cedbd66e22;hb=05e356b2a3087e819ef3b5388e29c822f41502e1;hp=0f5663d1f064c5b6813d86dd3644c2bdf687c51a;hpb=fcb9e49b2a2d57af7c001ae5d2eda9ac443ba36b;p=pspp diff --git a/src/pool.c b/src/pool.c index 0f5663d1f0..45938fe971 100644 --- a/src/pool.c +++ b/src/pool.c @@ -17,13 +17,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#if HAVE_CONFIG_H #include -#endif -#include +#include "pool.h" +#include "command.h" +#include "error.h" #include #include "alloc.h" -#include "pool.h" #include "str.h" /* Fast, low-overhead memory block suballocator. */ @@ -56,6 +55,7 @@ enum This structure is used to keep track of them. */ struct pool_gizmo { + struct pool *pool; struct pool_gizmo *prev; struct pool_gizmo *next; @@ -112,10 +112,6 @@ union align simplified functionality. */ /*#define DISCRETE_BLOCKS 1*/ -/* Enable debug code if appropriate. */ -#if SELF_TEST -#endif - /* Size of each block allocated in the pool, in bytes. Should be at least 1k. */ #ifndef BLOCK_SIZE @@ -140,12 +136,9 @@ static long serial = 0; /* Prototypes. */ static void add_gizmo (struct pool *, struct pool_gizmo *); static void free_gizmo (struct pool_gizmo *); +static void free_all_gizmos (struct pool *pool); static void delete_gizmo (struct pool *, struct pool_gizmo *); - -#if !PSPP -static void *xmalloc (size_t); -static void *xrealloc (void *, size_t); -#endif +static void check_gizmo (struct pool *, struct pool_gizmo *); /* General routines. */ @@ -180,20 +173,13 @@ pool_destroy (struct pool *pool) if (pool == NULL) return; + /* Remove this pool from its parent's list of gizmos. */ if (pool->parent) - delete_gizmo (pool, - (void *) (((char *) pool) + POOL_SIZE + POOL_BLOCK_SIZE)); - - { - struct pool_gizmo *cur, *next; - - for (cur = pool->gizmos; cur; cur = next) - { - next = cur->next; - free_gizmo (cur); - } - } + delete_gizmo (pool->parent, (void *) (((char *) pool) + POOL_SIZE)); + free_all_gizmos (pool); + + /* Free all the memory. */ { struct pool_block *cur, *next; @@ -205,6 +191,34 @@ pool_destroy (struct pool *pool) } } } + +/* Release all the memory and gizmos in POOL. + Blocks are not given back with free() but kept for later + allocations. To give back memory, use a subpool instead. */ +void +pool_clear (struct pool *pool) +{ + free_all_gizmos (pool); + + /* Zero out block sizes. */ + { + struct pool_block *cur; + + cur = pool->blocks; + do + { + cur->ofs = POOL_BLOCK_SIZE; + if ((char *) cur + POOL_BLOCK_SIZE == (char *) pool) + { + cur->ofs += POOL_SIZE; + if (pool->parent != NULL) + cur->ofs += POOL_GIZMO_SIZE; + } + cur = cur->next; + } + while (cur != pool->blocks); + } +} /* Suballocation routines. */ @@ -215,9 +229,10 @@ pool_alloc (struct pool *pool, size_t amt) { assert (pool != NULL); -#if !DISCRETE_BLOCKS +#ifndef DISCRETE_BLOCKS if (amt <= MAX_SUBALLOC) { + /* If there is space in this block, take it. */ struct pool_block *b = pool->blocks; b->ofs = ROUND_UP (b->ofs, ALIGN_SIZE); if (b->ofs + amt <= BLOCK_SIZE) @@ -227,21 +242,47 @@ pool_alloc (struct pool *pool, size_t amt) return p; } - b = xmalloc (BLOCK_SIZE); - b->next = pool->blocks; - b->prev = pool->blocks->prev; - b->ofs = POOL_BLOCK_SIZE + amt; - - pool->blocks->prev->next = b; - pool->blocks = pool->blocks->prev = b; - - return ((char *) b) + POOL_BLOCK_SIZE; + /* No space in this block, so we must make other + arrangements. */ + if (b->next->ofs == 0) + { + /* The next block is empty. Use it. */ + b = b->next; + b->ofs = POOL_BLOCK_SIZE; + if ((char *) b + POOL_BLOCK_SIZE == (char *) pool) + b->ofs += POOL_SIZE; + } + else + { + /* Create a new block at the start of the list. */ + b = xmalloc (BLOCK_SIZE); + b->next = pool->blocks; + b->prev = pool->blocks->prev; + b->ofs = POOL_BLOCK_SIZE; + pool->blocks->prev->next = b; + pool->blocks->prev = b; + } + pool->blocks = b; + + /* Allocate space from B. */ + b->ofs += amt; + return ((char *) b) + b->ofs - amt; } else -#endif /* !DISCRETE_BLOCKS */ +#endif return pool_malloc (pool, amt); } +/* Allocates SIZE bytes in POOL, copies BUFFER into it, and + returns the new copy. */ +void * +pool_clone (struct pool *pool, const void *buffer, size_t size) +{ + void *block = pool_alloc (pool, size); + memcpy (block, buffer, size); + return block; +} + /* Duplicates STRING, which has LENGTH characters, within POOL, and returns a pointer to the duplicate. LENGTH should not include the null terminator, which is always added to the @@ -257,19 +298,21 @@ pool_strndup (struct pool *pool, const char *string, size_t length) size = length + 1; /* Note that strings need not be aligned on any boundary. */ +#ifndef DISCRETE_BLOCKS { -#if !DISCRETE_BLOCKS struct pool_block *const b = pool->blocks; if (b->ofs + size <= BLOCK_SIZE) { - copy = ((char *) b) + b->ofs; - b->ofs += size; + copy = ((char *) b) + b->ofs; + b->ofs += size; } else -#endif copy = pool_alloc (pool, size); } +#else + copy = pool_alloc (pool, size); +#endif memcpy (copy, string, length); copy[length] = '\0'; @@ -326,16 +369,17 @@ pool_realloc (struct pool *pool, void *p, size_t amt) { if (amt != 0) { - struct pool_gizmo *g; + struct pool_gizmo *g = (void *) (((char *) p) - POOL_GIZMO_SIZE); + check_gizmo (pool, g); - g = xrealloc (((char *) p) - POOL_GIZMO_SIZE, - amt + POOL_GIZMO_SIZE); + g = xrealloc (g, amt + POOL_GIZMO_SIZE); if (g->next) g->next->prev = g; if (g->prev) g->prev->next = g; else pool->gizmos = g; + check_gizmo (pool, g); return ((char *) g) + POOL_GIZMO_SIZE; } @@ -361,6 +405,7 @@ pool_free (struct pool *pool, void *p) if (pool != NULL && p != NULL) { struct pool_gizmo *g = (void *) (((char *) p) - POOL_GIZMO_SIZE); + check_gizmo (pool, g); delete_gizmo (pool, g); free (g); } @@ -383,7 +428,7 @@ pool_create_subpool (struct pool *pool) subpool = pool_create (); subpool->parent = pool; - g = (void *) (((char *) subpool) + subpool->blocks->ofs); + g = (void *) (((char *) subpool->blocks) + subpool->blocks->ofs); subpool->blocks->ofs += POOL_GIZMO_SIZE; g->type = POOL_GIZMO_SUBPOOL; @@ -495,7 +540,10 @@ pool_mark (struct pool *pool, struct pool_mark *mark) mark->serial = serial; } -/* Restores to POOL the state recorded in MARK. */ +/* Restores to POOL the state recorded in MARK. + Emptied blocks are not given back with free() but kept for + later allocations. To get that behavior, use a subpool + instead. */ void pool_release (struct pool *pool, const struct pool_mark *mark) { @@ -520,21 +568,20 @@ pool_release (struct pool *pool, const struct pool_mark *mark) } { - struct pool_block *cur, *next, *last; + struct pool_block *cur; - last = pool->blocks->prev; - for (cur = pool->blocks; cur != mark->block; cur = next) + for (cur = pool->blocks; cur != mark->block; cur = cur->next) { - next = cur->next; - assert (next != cur); - - free (cur); + cur->ofs = POOL_BLOCK_SIZE; + if ((char *) cur + POOL_BLOCK_SIZE == (char *) pool) + { + cur->ofs += POOL_SIZE; + if (pool->parent != NULL) + cur->ofs += POOL_GIZMO_SIZE; + } } - - cur->prev = last; - last->next = pool->blocks = cur; - - cur->ofs = mark->ofs; + pool->blocks = mark->block; + pool->blocks->ofs = mark->ofs; } } @@ -545,7 +592,8 @@ static void add_gizmo (struct pool *pool, struct pool_gizmo *gizmo) { assert (pool && gizmo); - + + gizmo->pool = pool; gizmo->next = pool->gizmos; gizmo->prev = NULL; if (pool->gizmos) @@ -553,6 +601,8 @@ add_gizmo (struct pool *pool, struct pool_gizmo *gizmo) pool->gizmos = gizmo; gizmo->serial = serial++; + + check_gizmo (pool, gizmo); } /* Removes GIZMO from POOL's gizmo list. */ @@ -560,7 +610,9 @@ static void delete_gizmo (struct pool *pool, struct pool_gizmo *gizmo) { assert (pool && gizmo); - + + check_gizmo (pool, gizmo); + if (gizmo->prev) gizmo->prev->next = gizmo->next; else @@ -575,7 +627,7 @@ static void free_gizmo (struct pool_gizmo *gizmo) { assert (gizmo != NULL); - + switch (gizmo->type) { case POOL_GIZMO_MALLOC: @@ -595,47 +647,33 @@ free_gizmo (struct pool_gizmo *gizmo) assert (0); } } - -/* Memory allocation. */ -#if !PSPP -/* Allocates SIZE bytes of space using malloc(). Aborts if out of - memory. */ -static void * -xmalloc (size_t size) +/* Free all the gizmos in POOL. */ +static void +free_all_gizmos (struct pool *pool) { - void *vp; - if (size == 0) - return NULL; - vp = malloc (size); - assert (vp != NULL); - if (vp == NULL) - abort (); - return vp; -} + struct pool_gizmo *cur, *next; -/* Reallocates P to be SIZE bytes long using realloc(). Aborts if out - of memory. */ -static void * -xrealloc (void *p, size_t size) -{ - if (p == NULL) - return xmalloc (size); - if (size == 0) + for (cur = pool->gizmos; cur; cur = next) { - free (p); - return NULL; + next = cur->next; + free_gizmo (cur); } - p = realloc (p, size); - if (p == NULL) - abort (); - return p; + pool->gizmos = NULL; +} + +static void +check_gizmo (struct pool *p, struct pool_gizmo *g) +{ + assert (g->pool == p); + assert (g->next == NULL || g->next->prev == g); + assert ((g->prev != NULL && g->prev->next == g) + || (g->prev == NULL && p->gizmos == g)); + } -#endif /* !PSPP */ /* Self-test routine. */ -#if SELF_TEST #include #include #include @@ -648,14 +686,9 @@ xrealloc (void *p, size_t size) /* Self-test routine. This is not exhaustive, but it can be useful. */ int -main (int argc, char **argv) +cmd_debug_pool (void) { - int seed; - - if (argc == 2) - seed = atoi (argv[1]); - else - seed = time (0) * 257 % 32768; + int seed = time (0) * 257 % 32768; for (;;) { @@ -734,12 +767,7 @@ main (int argc, char **argv) putchar ('\n'); } -} -#endif /* SELF_TEST */ + return CMD_SUCCESS; +} -/* - Local variables: - compile-command: "gcc -DSELF_TEST=1 -W -Wall -I. -o pool_test pool.c" - End: -*/