Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
-#if HAVE_CONFIG_H
#include <config.h>
-#endif
-#include <assert.h>
+#include "pool.h"
+#include "command.h"
+#include "error.h"
#include <stdlib.h>
#include "alloc.h"
-#include "pool.h"
#include "str.h"
/* Fast, low-overhead memory block suballocator. */
This structure is used to keep track of them. */
struct pool_gizmo
{
+ struct pool *pool;
struct pool_gizmo *prev;
struct pool_gizmo *next;
simplified functionality. */
/*#define DISCRETE_BLOCKS 1*/
-/* Enable debug code if appropriate. */
-#undef DEBUGGING
-#if SELF_TEST
-#define DEBUGGING 1
-#endif
-
/* Size of each block allocated in the pool, in bytes.
Should be at least 1k. */
#ifndef BLOCK_SIZE
/* 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 *);
\f
/* General routines. */
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;
}
}
}
+
+/* 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);
+ }
+}
\f
/* Suballocation routines. */
{
assert (pool != NULL);
-#if !DISCRETE_BLOCKS /* Help identify source of bugs for Checker users. */
+#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)
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);
}
-/* Duplicates STRING within POOL and returns a pointer to the
- duplicate. */
+/* 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
+ duplicate. For use only with strings, because the returned
+ pointere may not be aligned properly for other types. */
char *
-pool_strdup (struct pool *pool, const char *string)
+pool_strndup (struct pool *pool, const char *string, size_t length)
{
- size_t amt;
- void *p;
+ size_t size;
+ char *copy;
assert (pool && string);
- amt = strlen (string) + 1;
+ 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 + amt <= BLOCK_SIZE)
+ if (b->ofs + size <= BLOCK_SIZE)
{
- p = ((char *) b) + b->ofs;
- b->ofs += amt;
+ copy = ((char *) b) + b->ofs;
+ b->ofs += size;
}
else
-#endif
- p = pool_alloc (pool, amt);
+ copy = pool_alloc (pool, size);
}
+#else
+ copy = pool_alloc (pool, size);
+#endif
- memcpy (p, string, amt);
- return p;
+ memcpy (copy, string, length);
+ copy[length] = '\0';
+ return copy;
+}
+
+/* Duplicates null-terminated STRING, within POOL, and returns a
+ pointer to the duplicate. For use only with strings, because
+ the returned pointere may not be aligned properly for other
+ types. */
+char *
+pool_strdup (struct pool *pool, const char *string)
+{
+ return pool_strndup (pool, string, strlen (string));
}
\f
/* Standard allocation routines. */
{
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;
}
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);
}
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;
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)
{
}
{
- 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;
}
}
\f
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)
pool->gizmos = gizmo;
gizmo->serial = serial++;
+
+ check_gizmo (pool, gizmo);
}
/* Removes GIZMO from POOL's gizmo list. */
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
free_gizmo (struct pool_gizmo *gizmo)
{
assert (gizmo != NULL);
-
+
switch (gizmo->type)
{
case POOL_GIZMO_MALLOC:
assert (0);
}
}
-\f
-/* 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 */
\f
/* Self-test routine. */
-#if SELF_TEST
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
/* 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 (;;)
{
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:
-*/