X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Flibpspp%2Fpool.c;h=7f3175d477bde1d758f5f358378fa448b30a60ab;hb=refs%2Fbuilds%2F20110905030503%2Fpspp;hp=141d8ab40323b94fea587ce801369bde6938b7aa;hpb=c898fab12a050123972d9021b1ccb93cc2df0456;p=pspp
diff --git a/src/libpspp/pool.c b/src/libpspp/pool.c
index 141d8ab403..7f3175d477 100644
--- a/src/libpspp/pool.c
+++ b/src/libpspp/pool.c
@@ -1,29 +1,32 @@
-/* PSPP - computes sample statistics.
- Copyright (C) 2000 Free Software Foundation, Inc.
+/* PSPP - a program for statistical analysis.
+ Copyright (C) 2000, 2010, 2011 Free Software Foundation, Inc.
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of the
- License, or (at your option) any later version.
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301, USA. */
+ along with this program. If not, see . */
#include
-#include "pool.h"
+
+#include "libpspp/pool.h"
+
+#include
#include
-#include "alloc.h"
-#include
-#include "message.h"
-#include "size_max.h"
-#include "str.h"
+
+#include "libpspp/assertion.h"
+#include "libpspp/message.h"
+#include "libpspp/temp-file.h"
+#include "libpspp/str.h"
+
+#include "gl/xalloc.h"
/* Fast, low-overhead memory block suballocator. */
struct pool
@@ -34,7 +37,7 @@ struct pool
};
/* Pool block. */
-struct pool_block
+struct pool_block
{
struct pool_block *prev;
struct pool_block *next;
@@ -46,12 +49,13 @@ enum
{
POOL_GIZMO_MALLOC,
POOL_GIZMO_FILE,
+ POOL_GIZMO_TEMP_FILE,
POOL_GIZMO_SUBPOOL,
POOL_GIZMO_REGISTERED,
};
/* Pool routines can maintain objects (`gizmos') as well as doing
- suballocation.
+ suballocation.
This structure is used to keep track of them. */
struct pool_gizmo
{
@@ -65,7 +69,7 @@ struct pool_gizmo
/* Type-dependent info. */
union
{
- FILE *file; /* POOL_GIZMO_FILE. */
+ FILE *file; /* POOL_GIZMO_FILE, POOL_GIZMO_TEMP_FILE. */
struct pool *subpool; /* POOL_GIZMO_SUBPOOL. */
/* POOL_GIZMO_REGISTERED. */
@@ -147,7 +151,7 @@ pool_create (void)
block = xmalloc (BLOCK_SIZE);
block->prev = block->next = block;
block->ofs = POOL_BLOCK_SIZE + POOL_SIZE;
-
+
pool = (struct pool *) (((char *) block) + POOL_BLOCK_SIZE);
pool->parent = NULL;
pool->blocks = block;
@@ -163,7 +167,7 @@ pool_create (void)
Meant for use indirectly via pool_create_container(). */
void *
-pool_create_at_offset (size_t struct_size, size_t pool_member_offset)
+pool_create_at_offset (size_t struct_size, size_t pool_member_offset)
{
struct pool *pool;
char *struct_;
@@ -185,9 +189,9 @@ pool_destroy (struct pool *pool)
return;
/* Remove this pool from its parent's list of gizmos. */
- if (pool->parent)
+ if (pool->parent)
delete_gizmo (pool->parent, (void *) (((char *) pool) + POOL_SIZE));
-
+
free_all_gizmos (pool);
/* Free all the memory. */
@@ -205,25 +209,25 @@ 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. */
+ allocations. To give back memory, use a subpool instead. */
void
-pool_clear (struct pool *pool)
+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)
+ if ((char *) cur + POOL_BLOCK_SIZE == (char *) pool)
{
cur->ofs += POOL_SIZE;
if (pool->parent != NULL)
- cur->ofs += POOL_GIZMO_SIZE;
+ cur->ofs += POOL_GIZMO_SIZE;
}
cur = cur->next;
}
@@ -243,7 +247,7 @@ pool_alloc (struct pool *pool, size_t amt)
if (amt == 0)
return NULL;
-
+
#ifndef DISCRETE_BLOCKS
if (amt <= MAX_SUBALLOC)
{
@@ -259,7 +263,7 @@ pool_alloc (struct pool *pool, size_t amt)
/* No space in this block, so we must make other
arrangements. */
- if (b->next->ofs == 0)
+ if (b->next->ofs == 0)
{
/* The next block is empty. Use it. */
b = b->next;
@@ -267,7 +271,7 @@ pool_alloc (struct pool *pool, size_t amt)
if ((char *) b + POOL_BLOCK_SIZE == (char *) pool)
b->ofs += POOL_SIZE;
}
- else
+ else
{
/* Create a new block at the start of the list. */
b = xmalloc (BLOCK_SIZE);
@@ -295,13 +299,14 @@ pool_alloc (struct pool *pool, size_t amt)
void *
pool_alloc_unaligned (struct pool *pool, size_t amt)
{
- assert (pool != NULL);
+ if (pool == NULL)
+ return xmalloc (amt);
#ifndef DISCRETE_BLOCKS
/* Strings need not be aligned on any boundary, but some
operations may be more efficient when they are. However,
that's only going to help with reasonably long strings. */
- if (amt < ALIGN_SIZE)
+ if (amt < ALIGN_SIZE)
{
if (amt == 0)
return NULL;
@@ -328,7 +333,7 @@ pool_alloc_unaligned (struct pool *pool, size_t amt)
Terminates the program if the memory cannot be obtained,
including the case where N * S overflows the range of size_t. */
void *
-pool_nalloc (struct pool *pool, size_t n, size_t s)
+pool_nalloc (struct pool *pool, size_t n, size_t s)
{
if (xalloc_oversized (n, s))
xalloc_die ();
@@ -360,11 +365,24 @@ pool_clone_unaligned (struct pool *pool, const void *buffer, size_t size)
the returned pointere may not be aligned properly for other
types. */
char *
-pool_strdup (struct pool *pool, const char *string)
+pool_strdup (struct pool *pool, const char *string)
{
return pool_clone_unaligned (pool, string, strlen (string) + 1);
}
+/* Duplicates the SIZE bytes of STRING, plus a trailing 0 byte,
+ 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_strdup0 (struct pool *pool, const char *string, size_t size)
+{
+ char *new_string = pool_alloc_unaligned (pool, size + 1);
+ memcpy (new_string, string, size);
+ new_string[size] = '\0';
+ return new_string;
+}
+
/* Formats FORMAT with the given ARGS in memory allocated from
POOL and returns the formatted string. */
char *
@@ -382,9 +400,9 @@ pool_vasprintf (struct pool *pool, const char *format, va_list args_)
needed = vsnprintf (s, avail, format, args);
va_end (args);
- if (needed >= 0)
+ if (needed >= 0)
{
- if (needed < avail)
+ if (needed < avail)
{
/* Success. Reserve the space that was actually used. */
b->ofs += needed + 1;
@@ -400,7 +418,7 @@ pool_vasprintf (struct pool *pool, const char *format, va_list args_)
va_end (args);
}
}
- else
+ else
{
/* Some old libc's returned -1 when the destination string
was too short. This should be uncommon these days and
@@ -423,7 +441,7 @@ pool_asprintf (struct pool *pool, const char *format, ...)
{
va_list args;
char *string;
-
+
va_start (args, format);
string = pool_vasprintf (pool, format, args);
va_end (args);
@@ -465,13 +483,41 @@ pool_malloc (struct pool *pool, size_t amt)
Terminates the program if the memory cannot be obtained,
including the case where N * S overflows the range of size_t. */
void *
-pool_nmalloc (struct pool *pool, size_t n, size_t s)
+pool_nmalloc (struct pool *pool, size_t n, size_t s)
{
if (xalloc_oversized (n, s))
xalloc_die ();
return pool_malloc (pool, n * s);
}
+/* Allocates AMT bytes using malloc(), to be managed by POOL,
+ zeros the block, and returns a pointer to the beginning of the
+ block.
+ If POOL is a null pointer, then allocates a normal memory block
+ with xmalloc(). */
+void *
+pool_zalloc (struct pool *pool, size_t amt)
+{
+ void *p = pool_malloc (pool, amt);
+ memset (p, 0, amt);
+ return p;
+}
+
+/* Allocates and returns N elements of S bytes each, to be
+ managed by POOL, and zeros the block.
+ If POOL is a null pointer, then allocates a normal memory block
+ with malloc().
+ N must be nonnegative, S must be positive.
+ Terminates the program if the memory cannot be obtained,
+ including the case where N * S overflows the range of size_t. */
+void *
+pool_calloc (struct pool *pool, size_t n, size_t s)
+{
+ void *p = pool_nmalloc (pool, n, s);
+ memset (p, 0, n * s);
+ return p;
+}
+
/* Changes the allocation size of the specified memory block P managed
by POOL to AMT bytes and returns a pointer to the beginning of the
block.
@@ -657,7 +703,7 @@ pool_create_subpool (struct pool *pool)
g = (void *) (((char *) subpool->blocks) + subpool->blocks->ofs);
subpool->blocks->ofs += POOL_GIZMO_SIZE;
-
+
g->type = POOL_GIZMO_SUBPOOL;
g->p.subpool = subpool;
@@ -671,14 +717,14 @@ pool_create_subpool (struct pool *pool)
The subpool will be destroyed automatically when POOL is destroyed.
It may also be destroyed explicitly in advance. */
void
-pool_add_subpool (struct pool *pool, struct pool *subpool)
+pool_add_subpool (struct pool *pool, struct pool *subpool)
{
struct pool_gizmo *g;
assert (pool != NULL);
assert (subpool != NULL);
assert (subpool->parent == NULL);
-
+
g = pool_alloc (subpool, sizeof *g);
g->type = POOL_GIZMO_SUBPOOL;
g->p.subpool = subpool;
@@ -715,41 +761,78 @@ pool_fclose (struct pool *pool, FILE *file)
return fclose (file);
}
-/* Creates a temporary file with tmpfile() and returns a handle to it
- if successful or a null pointer if not.
+/* Attaches FILE to POOL.
The file will be closed automatically when POOL is destroyed, or it
may be closed explicitly in advance using pool_fclose(), or
detached from the pool with pool_detach_file(). */
+void
+pool_attach_file (struct pool *pool, FILE *file)
+{
+ struct pool_gizmo *g = pool_alloc (pool, sizeof *g);
+ g->type = POOL_GIZMO_FILE;
+ g->p.file = file;
+ add_gizmo (pool, g);
+}
+
+/* Detaches FILE from POOL. */
+void
+pool_detach_file (struct pool *pool, FILE *file)
+{
+ struct pool_gizmo *g;
+
+ for (g = pool->gizmos; g; g = g->next)
+ if (g->type == POOL_GIZMO_FILE && g->p.file == file)
+ {
+ delete_gizmo (pool, g);
+ return;
+ }
+}
+
+/* Creates a temporary file with create_temp_file() and returns a handle to it
+ if successful or a null pointer if not.
+ The file will be closed automatically when POOL is destroyed, or it
+ may be closed explicitly in advance using pool_fclose_temp_file(), or
+ detached from the pool with pool_detach_temp_file(). */
FILE *
-pool_tmpfile (struct pool *pool)
+pool_create_temp_file (struct pool *pool)
{
- FILE *file = tmpfile ();
+ FILE *file = create_temp_file ();
if (file != NULL)
- pool_attach_file (pool, file);
+ pool_attach_temp_file (pool, file);
return file;
}
-/* Attaches FILE to POOL.
+/* Closes file FILE managed by POOL.
+ FILE must have been opened with create_temp_file(). */
+void
+pool_fclose_temp_file (struct pool *pool, FILE *file)
+{
+ assert (pool && file);
+ pool_detach_temp_file (pool, file);
+ close_temp_file (file);
+}
+
+/* Attaches FILE, which must have been opened with create_temp_file(), to POOL.
The file will be closed automatically when POOL is destroyed, or it
- may be closed explicitly in advance using pool_fclose(), or
- detached from the pool with pool_detach_file(). */
+ may be closed explicitly in advance using pool_fclose_temp_file(), or
+ detached from the pool with pool_detach_temp_file(). */
void
-pool_attach_file (struct pool *pool, FILE *file)
+pool_attach_temp_file (struct pool *pool, FILE *file)
{
struct pool_gizmo *g = pool_alloc (pool, sizeof *g);
- g->type = POOL_GIZMO_FILE;
+ g->type = POOL_GIZMO_TEMP_FILE;
g->p.file = file;
add_gizmo (pool, g);
}
-/* Detaches FILE from POOL. */
+/* Detaches FILE that was opened with create_temp_file() from POOL. */
void
-pool_detach_file (struct pool *pool, FILE *file)
+pool_detach_temp_file (struct pool *pool, FILE *file)
{
struct pool_gizmo *g;
for (g = pool->gizmos; g; g = g->next)
- if (g->type == POOL_GIZMO_FILE && g->p.file == file)
+ if (g->type == POOL_GIZMO_TEMP_FILE && g->p.file == file)
{
delete_gizmo (pool, g);
return;
@@ -781,7 +864,7 @@ bool
pool_unregister (struct pool *pool, void *p)
{
assert (pool && p);
-
+
{
struct pool_gizmo *g;
@@ -792,7 +875,7 @@ pool_unregister (struct pool *pool, void *p)
return true;
}
}
-
+
return false;
}
@@ -814,12 +897,12 @@ pool_mark (struct pool *pool, struct pool_mark *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. */
+ instead. */
void
pool_release (struct pool *pool, const struct pool_mark *mark)
{
assert (pool && mark);
-
+
{
struct pool_gizmo *cur, *next;
@@ -837,18 +920,18 @@ pool_release (struct pool *pool, const struct pool_mark *mark)
else
pool->gizmos = NULL;
}
-
+
{
struct pool_block *cur;
- for (cur = pool->blocks; cur != mark->block; cur = cur->next)
+ for (cur = pool->blocks; cur != mark->block; cur = cur->next)
{
cur->ofs = POOL_BLOCK_SIZE;
- if ((char *) cur + POOL_BLOCK_SIZE == (char *) pool)
+ if ((char *) cur + POOL_BLOCK_SIZE == (char *) pool)
{
cur->ofs += POOL_SIZE;
if (pool->parent != NULL)
- cur->ofs += POOL_GIZMO_SIZE;
+ cur->ofs += POOL_GIZMO_SIZE;
}
}
pool->blocks = mark->block;
@@ -875,7 +958,7 @@ add_gizmo (struct pool *pool, struct pool_gizmo *gizmo)
check_gizmo (pool, gizmo);
}
-
+
/* Removes GIZMO from POOL's gizmo list. */
static void
delete_gizmo (struct pool *pool, struct pool_gizmo *gizmo)
@@ -907,6 +990,9 @@ free_gizmo (struct pool_gizmo *gizmo)
case POOL_GIZMO_FILE:
fclose (gizmo->p.file); /* Ignore errors. */
break;
+ case POOL_GIZMO_TEMP_FILE:
+ close_temp_file (gizmo->p.file); /* Ignore errors. */
+ break;
case POOL_GIZMO_SUBPOOL:
gizmo->p.subpool->parent = NULL;
pool_destroy (gizmo->p.subpool);
@@ -921,7 +1007,7 @@ free_gizmo (struct pool_gizmo *gizmo)
/* Free all the gizmos in POOL. */
static void
-free_all_gizmos (struct pool *pool)
+free_all_gizmos (struct pool *pool)
{
struct pool_gizmo *cur, *next;
@@ -934,7 +1020,7 @@ free_all_gizmos (struct pool *pool)
}
static void
-check_gizmo (struct pool *p, struct pool_gizmo *g)
+check_gizmo (struct pool *p, struct pool_gizmo *g)
{
assert (g->pool == p);
assert (g->next == NULL || g->next->prev == g);