X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Flibpspp%2Fpool.c;h=7f3175d477bde1d758f5f358378fa448b30a60ab;hb=20751c90d1d6131fede84358ea2581d9ed443ae3;hp=31a57e9fbeffcff245924efb8c6abc253d6a2276;hpb=5f7f751a47c68946a0fcbc9898f43f5499c5c6c5;p=pspp-builds.git diff --git a/src/libpspp/pool.c b/src/libpspp/pool.c index 31a57e9f..7f3175d4 100644 --- a/src/libpspp/pool.c +++ b/src/libpspp/pool.c @@ -1,30 +1,32 @@ -/* PSPP - computes sample statistics. - Copyright (C) 2000 Free Software Foundation, Inc. - Written by Ben Pfaff . +/* 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 @@ -35,7 +37,7 @@ struct pool }; /* Pool block. */ -struct pool_block +struct pool_block { struct pool_block *prev; struct pool_block *next; @@ -47,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 { @@ -66,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. */ @@ -101,8 +104,8 @@ union align /* DISCRETE_BLOCKS may be declared as nonzero to prevent suballocation of blocks. This is useful under memory - debuggers like Checker or valgrind because it allows the - source location of bugs to be more accurately pinpointed. + debuggers like valgrind because it allows the source location + of bugs to be more accurately pinpointed. On the other hand, if we're testing the library, then we want to test the library's real functionality, not its crippled, slow, @@ -148,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; @@ -164,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_; @@ -186,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. */ @@ -206,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; } @@ -244,7 +247,7 @@ pool_alloc (struct pool *pool, size_t amt) if (amt == 0) return NULL; - + #ifndef DISCRETE_BLOCKS if (amt <= MAX_SUBALLOC) { @@ -260,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; @@ -268,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); @@ -296,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; @@ -329,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 (); @@ -361,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 * @@ -383,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; @@ -401,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 @@ -424,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); @@ -466,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. @@ -658,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; @@ -672,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; @@ -716,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; @@ -782,7 +864,7 @@ bool pool_unregister (struct pool *pool, void *p) { assert (pool && p); - + { struct pool_gizmo *g; @@ -793,7 +875,7 @@ pool_unregister (struct pool *pool, void *p) return true; } } - + return false; } @@ -815,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; @@ -838,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; @@ -876,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) @@ -908,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); @@ -922,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; @@ -935,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);