/* * mem.c * * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald * 2003 Bastian Blank * * 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 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, see . */ #include #include #include #include #include #include #include #define MEM_ALIGN sizeof (void *) #define MEM_AREA_SIZE sizeof (void *) typedef struct di_mem_area di_mem_area; /** * @addtogroup di_mem_chunk * @{ */ /** * @internal * @brief a mem chunk */ struct di_mem_chunk { int num_mem_areas; /**< the number of memory areas */ int num_marked_areas; /**< the number of areas marked for deletion */ size_t atom_size; /**< the size of an atom */ size_t area_size; /**< the size of a memory area */ size_t rarea_size; /**< the size of a real memory area */ di_mem_area *mem_area; /**< the current memory area */ di_mem_area *mem_areas; /**< a list of all the mem areas owned by this chunk */ }; /** * @internal * @brief a mem area */ struct di_mem_area { di_mem_area *next; /**< the next mem area */ di_mem_area *prev; /**< the previous mem area */ size_t index; /**< the current index into the "mem" array */ size_t free; /**< the number of free bytes in this mem area */ size_t allocated; /**< the number of atoms allocated from this area */ char mem[MEM_AREA_SIZE]; /**< the mem array from which atoms get allocated * the actual size of this array is determined by * the mem chunk "area_size". ANSI says that it * must be declared to be the maximum size it * can possibly be (even though the actual size * may be less). */ }; static size_t internal_di_mem_chunk_compute_size (size_t size, size_t min_size); /** @} */ /** * Makes a new Memory-Chunk Allocer * * @param atom_size size of each piece * @param area_size size of each alloced chunk */ di_mem_chunk* di_mem_chunk_new (di_ksize_t atom_size, di_ksize_t area_size) { di_mem_chunk *mem_chunk; if (area_size < atom_size) return NULL; area_size = (area_size + atom_size - 1) / atom_size; area_size *= atom_size; mem_chunk = di_new (di_mem_chunk, 1); mem_chunk->num_mem_areas = 0; mem_chunk->num_marked_areas = 0; mem_chunk->mem_area = NULL; mem_chunk->mem_areas = NULL; mem_chunk->atom_size = atom_size; if (mem_chunk->atom_size % MEM_ALIGN) mem_chunk->atom_size += MEM_ALIGN - (mem_chunk->atom_size % MEM_ALIGN); mem_chunk->rarea_size = internal_di_mem_chunk_compute_size (area_size + sizeof (di_mem_area) - MEM_AREA_SIZE, atom_size + sizeof (di_mem_area) - MEM_AREA_SIZE); mem_chunk->area_size = mem_chunk->rarea_size - (sizeof (di_mem_area) - MEM_AREA_SIZE); return mem_chunk; } /** * Allocate a piece * * @param mem_chunk a di_mem_chunk * * @return memory */ void *di_mem_chunk_alloc (di_mem_chunk *mem_chunk) { void *mem; if ((!mem_chunk->mem_area) || ((mem_chunk->mem_area->index + mem_chunk->atom_size) > mem_chunk->area_size)) { mem_chunk->mem_area = di_malloc (mem_chunk->rarea_size); mem_chunk->num_mem_areas += 1; mem_chunk->mem_area->next = mem_chunk->mem_areas; mem_chunk->mem_area->prev = NULL; if (mem_chunk->mem_areas) mem_chunk->mem_areas->prev = mem_chunk->mem_area; mem_chunk->mem_areas = mem_chunk->mem_area; mem_chunk->mem_area->index = 0; mem_chunk->mem_area->free = mem_chunk->area_size; mem_chunk->mem_area->allocated = 0; } mem = &mem_chunk->mem_area->mem[mem_chunk->mem_area->index]; mem_chunk->mem_area->index += mem_chunk->atom_size; mem_chunk->mem_area->free -= mem_chunk->atom_size; mem_chunk->mem_area->allocated += 1; return mem; } /** * Allocate a cleared piece * * @param mem_chunk a di_mem_chunk * * @return memory */ void *di_mem_chunk_alloc0 (di_mem_chunk *mem_chunk) { void *mem; mem = di_mem_chunk_alloc (mem_chunk); if (mem) memset (mem, 0, mem_chunk->atom_size); return mem; } void di_mem_chunk_destroy (di_mem_chunk *mem_chunk) { di_mem_area *mem_areas, *temp_area; mem_areas = mem_chunk->mem_areas; while (mem_areas) { temp_area = mem_areas; mem_areas = mem_areas->next; di_free (temp_area); } di_free (mem_chunk); } size_t di_mem_chunk_size (di_mem_chunk *mem_chunk) { di_mem_area *mem_area; size_t size = 0; for (mem_area = mem_chunk->mem_areas; mem_area; mem_area = mem_area->next) { size += mem_chunk->atom_size * mem_area->allocated; } return size; } static size_t internal_di_mem_chunk_compute_size (size_t size, size_t min_size) { size_t power_of_2; size_t lower, upper; power_of_2 = 16; while (power_of_2 < size) power_of_2 <<= 1; lower = power_of_2 >> 1; upper = power_of_2; if (size - lower < upper - size && lower >= min_size) return lower; else return upper; }