/* Functions to support a pool of allocatable objects. Copyright (C) 1987, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. Contributed by Daniel Berlin This file is part of GCC. GCC 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, or (at your option) any later version. GCC 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 GCC; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "config.h" #include "system.h" #include "alloc-pool.h" #define align_four(x) (((x+3) >> 2) << 2) #define align_eight(x) (((x+7) >> 3) << 3) /* Create a pool of things of size SIZE, with NUM in each block we allocate. */ alloc_pool create_alloc_pool (name, size, num) const char *name; size_t size; size_t num; { alloc_pool pool; size_t pool_size, header_size; if (!name) abort (); /* Make size large enough to store the list header. */ if (size < sizeof (alloc_pool_list)) size = sizeof (alloc_pool_list); /* Now align the size to a multiple of 4. */ size = align_four (size); /* Um, we can't really allocate 0 elements per block. */ if (num == 0) abort (); /* Find the size of the pool structure, and the name. */ pool_size = sizeof (struct alloc_pool_def); /* and allocate that much memory. */ pool = (alloc_pool) xmalloc (pool_size); /* Now init the various pieces of our pool structure. */ pool->name = xstrdup (name); pool->elt_size = size; pool->elts_per_block = num; /* List header size should be a multiple of 8 */ header_size = align_eight (sizeof (struct alloc_pool_list_def)); pool->block_size = (size * num) + header_size; pool->free_list = NULL; pool->elts_allocated = 0; pool->elts_free = 0; pool->blocks_allocated = 0; pool->block_list = NULL; return (pool); } /* Free all memory allocated for the given memory pool. */ void free_alloc_pool (pool) alloc_pool pool; { alloc_pool_list block, next_block; if (!pool) abort (); /* Free each block allocated to the pool. */ for (block = pool->block_list; block != NULL; block = next_block) { next_block = block->next; free (block); } /* Lastly, free the pool and the name. */ free (pool->name); free (pool); } /* Allocates one element from the pool specified. */ void * pool_alloc (pool) alloc_pool pool; { alloc_pool_list header; char *block; if (!pool) abort (); /* If there are no more free elements, make some more!. */ if (!pool->free_list) { size_t i; alloc_pool_list block_header; /* Make the block */ block = (char *) xmalloc (pool->block_size); block_header = (alloc_pool_list) block; block += align_eight (sizeof (struct alloc_pool_list_def)); /* Throw it on the block list */ block_header->next = pool->block_list; pool->block_list = block_header; /* Now put the actual block pieces onto the free list. */ for (i = 0; i < pool->elts_per_block; i++, block += pool->elt_size) { header = (alloc_pool_list) block; header->next = pool->free_list; pool->free_list = header; } /* Also update the number of elements we have free/allocated, and increment the allocated block count. */ pool->elts_allocated += pool->elts_per_block; pool->elts_free += pool->elts_per_block; pool->blocks_allocated += 1; } /* Pull the first free element from the free list, and return it. */ header = pool->free_list; pool->free_list = header->next; pool->elts_free--; return ((void *) header); } /* Puts PTR back on POOL's free list. */ void pool_free (pool, ptr) alloc_pool pool; void *ptr; { alloc_pool_list header; if (!ptr) abort (); /* Check if we free more than we allocated, which is Bad (TM). */ if (pool->elts_free + 1 > pool->elts_allocated) abort (); header = (alloc_pool_list) ptr; header->next = pool->free_list; pool->free_list = header; pool->elts_free++; }