X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fpool.c;h=b8ca4ad1205afbe6d069d308c0030f64eeb91502;hb=c8e41f19f9af4d4bac023c63192484b970381027;hp=9824b9b7341f68435fd7c6819773edeb56f977cc;hpb=4fdeb2145d081ff1b84e3f6c99f9d1c048c0d64a;p=pspp diff --git a/src/pool.c b/src/pool.c index 9824b9b734..b8ca4ad120 100644 --- a/src/pool.c +++ b/src/pool.c @@ -19,10 +19,11 @@ #include #include "pool.h" -#include "command.h" -#include "error.h" #include #include "alloc.h" +#include "command.h" +#include "error.h" +#include "size_max.h" #include "str.h" /* Fast, low-overhead memory block suballocator. */ @@ -96,11 +97,7 @@ union align /* This should be the alignment size used by malloc(). The size of the union above is correct, if not optimal, in all known cases. */ -#if defined (i386) || defined (__i386__) -#define ALIGN_SIZE 4 /* Save some extra memory. */ -#else #define ALIGN_SIZE sizeof (union align) -#endif /* DISCRETE_BLOCKS may be declared as nonzero to prevent suballocation of blocks. This is useful under memory @@ -166,6 +163,27 @@ pool_create (void) return pool; } +/* Creates a pool, allocates a block STRUCT_SIZE bytes in + length from it, stores the pool's address at offset + POOL_MEMBER_OFFSET within the block, and returns the allocated + block. + + Meant for use indirectly via pool_create_container(). */ +void * +pool_create_at_offset (size_t struct_size, size_t pool_member_offset) +{ + struct pool *pool; + char *struct_; + + assert (struct_size >= sizeof pool); + assert (pool_member_offset <= struct_size - sizeof pool); + + pool = pool_create (); + struct_ = pool_alloc (pool, struct_size); + *(struct pool **) (struct_ + pool_member_offset) = pool; + return struct_; +} + /* Destroy the specified pool, including all subpools. */ void pool_destroy (struct pool *pool) @@ -223,11 +241,15 @@ pool_clear (struct pool *pool) /* Suballocation routines. */ /* Allocates a memory region AMT bytes in size from POOL and returns a - pointer to the region's start. */ + pointer to the region's start. + The region is properly aligned for storing any object. */ void * pool_alloc (struct pool *pool, size_t amt) { assert (pool != NULL); + + if (amt == 0) + return NULL; #ifndef DISCRETE_BLOCKS if (amt <= MAX_SUBALLOC) @@ -273,6 +295,53 @@ pool_alloc (struct pool *pool, size_t amt) return pool_malloc (pool, amt); } +/* Allocates a memory region AMT bytes in size from POOL and + returns a pointer to the region's start. The region is not + necessarily aligned, so it is most suitable for storing + strings. */ +void * +pool_alloc_unaligned (struct pool *pool, size_t amt) +{ + assert (pool != NULL); + +#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 == 0) + return NULL; + else + { + struct pool_block *const b = pool->blocks; + + if (b->ofs + amt <= BLOCK_SIZE) + { + void *p = ((char *) b) + b->ofs; + b->ofs += amt; + return p; + } + } + } +#endif + + return pool_alloc (pool, amt); +} + +/* Allocates a memory region N * S bytes in size from POOL and + returns a pointer to the region's start. + 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_nalloc (struct pool *pool, size_t n, size_t s) +{ + if (xalloc_oversized (n, s)) + xalloc_die (); + return pool_alloc (pool, n * s); +} + /* Allocates SIZE bytes in POOL, copies BUFFER into it, and returns the new copy. */ void * @@ -283,40 +352,14 @@ pool_clone (struct pool *pool, const void *buffer, size_t 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_strndup (struct pool *pool, const char *string, size_t length) +/* Allocates SIZE bytes of unaligned data in POOL, copies BUFFER + into it, and returns the new copy. */ +void * +pool_clone_unaligned (struct pool *pool, const void *buffer, size_t size) { - size_t size; - char *copy; - - assert (pool && string); - size = length + 1; - - /* Note that strings need not be aligned on any boundary. */ -#ifndef DISCRETE_BLOCKS - { - struct pool_block *const b = pool->blocks; - - if (b->ofs + size <= BLOCK_SIZE) - { - copy = ((char *) b) + b->ofs; - b->ofs += size; - } - else - copy = pool_alloc (pool, size); - } -#else - copy = pool_alloc (pool, size); -#endif - - memcpy (copy, string, length); - copy[length] = '\0'; - return copy; + void *block = pool_alloc_unaligned (pool, size); + memcpy (block, buffer, size); + return block; } /* Duplicates null-terminated STRING, within POOL, and returns a @@ -326,7 +369,7 @@ pool_strndup (struct pool *pool, const char *string, size_t length) char * pool_strdup (struct pool *pool, const char *string) { - return pool_strndup (pool, string, strlen (string)); + return pool_clone_unaligned (pool, string, strlen (string) + 1); } /* Standard allocation routines. */ @@ -334,7 +377,7 @@ pool_strdup (struct pool *pool, const char *string) /* Allocates AMT bytes using malloc(), to be managed by POOL, and returns a pointer to the beginning of the block. If POOL is a null pointer, then allocates a normal memory block - with malloc(). */ + with xmalloc(). */ void * pool_malloc (struct pool *pool, size_t amt) { @@ -355,6 +398,21 @@ pool_malloc (struct pool *pool, size_t amt) return xmalloc (amt); } +/* Allocates and returns N elements of S bytes each, to be + managed by POOL. + 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_nmalloc (struct pool *pool, size_t n, size_t s) +{ + if (xalloc_oversized (n, s)) + xalloc_die (); + return pool_malloc (pool, n * s); +} + /* 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. @@ -396,6 +454,116 @@ pool_realloc (struct pool *pool, void *p, size_t amt) return xrealloc (p, amt); } +/* Changes the allocation size of the specified memory block P + managed by POOL to N * S bytes and returns a pointer to the + beginning of the block. + N must be nonnegative, S must be positive. + If POOL is a null pointer, then the block is reallocated in + the usual way with xrealloc(). + Terminates the program if the memory cannot be obtained, + including the case where N * S overflows the range of size_t. */ +void * +pool_nrealloc (struct pool *pool, void *p, size_t n, size_t s) +{ + if (xalloc_oversized (n, s)) + xalloc_die (); + return pool_realloc (pool, p, n * s); +} + +/* If P is null, allocate a block of at least *PN such objects; + otherwise, reallocate P so that it contains more than *PN + objects each of S bytes. *PN must be nonzero unless P is + null, and S must be nonzero. Set *PN to the new number of + objects, and return the pointer to the new block. *PN is + never set to zero, and the returned pointer is never null. + + The block returned is managed by POOL. If POOL is a null + pointer, then the block is reallocated in the usual way with + x2nrealloc(). + + Terminates the program if the memory cannot be obtained, + including the case where the memory required overflows the + range of size_t. + + Repeated reallocations are guaranteed to make progress, either by + allocating an initial block with a nonzero size, or by allocating a + larger block. + + In the following implementation, nonzero sizes are doubled so that + repeated reallocations have O(N log N) overall cost rather than + O(N**2) cost, but the specification for this function does not + guarantee that sizes are doubled. + + Here is an example of use: + + int *p = NULL; + struct pool *pool; + size_t used = 0; + size_t allocated = 0; + + void + append_int (int value) + { + if (used == allocated) + p = pool_2nrealloc (pool, p, &allocated, sizeof *p); + p[used++] = value; + } + + This causes x2nrealloc to allocate a block of some nonzero size the + first time it is called. + + To have finer-grained control over the initial size, set *PN to a + nonzero value before calling this function with P == NULL. For + example: + + int *p = NULL; + struct pool *pool; + size_t used = 0; + size_t allocated = 0; + size_t allocated1 = 1000; + + void + append_int (int value) + { + if (used == allocated) + { + p = pool_2nrealloc (pool, p, &allocated1, sizeof *p); + allocated = allocated1; + } + p[used++] = value; + } + + This function implementation is from gnulib. */ +void * +pool_2nrealloc (struct pool *pool, void *p, size_t *pn, size_t s) +{ + size_t n = *pn; + + if (p == NULL) + { + if (n == 0) + { + /* The approximate size to use for initial small allocation + requests, when the invoking code specifies an old size of + zero. 64 bytes is the largest "small" request for the + GNU C library malloc. */ + enum { DEFAULT_MXFAST = 64 }; + + n = DEFAULT_MXFAST / s; + n += !n; + } + } + else + { + if (SIZE_MAX / 2 / s < n) + xalloc_die (); + n *= 2; + } + + *pn = n; + return pool_realloc (pool, p, n * s); +} + /* Frees block P managed by POOL. If POOL is a null pointer, then the block is freed as usual with free(). */ @@ -439,6 +607,27 @@ pool_create_subpool (struct pool *pool) return subpool; } +/* Makes SUBPOOL a subpool of POOL. + SUBPOOL must not already have a parent 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) +{ + 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; + add_gizmo (pool, g); + + subpool->parent = pool; +} + /* Opens file FILENAME with mode MODE 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