163d4abf0Sagc /*
263d4abf0Sagc tre-mem.c - TRE memory allocator
363d4abf0Sagc
463d4abf0Sagc This software is released under a BSD-style license.
563d4abf0Sagc See the file LICENSE for details and copyright.
663d4abf0Sagc
763d4abf0Sagc */
863d4abf0Sagc
963d4abf0Sagc /*
1063d4abf0Sagc This memory allocator is for allocating small memory blocks efficiently
1163d4abf0Sagc in terms of memory overhead and execution speed. The allocated blocks
1263d4abf0Sagc cannot be freed individually, only all at once. There can be multiple
1363d4abf0Sagc allocators, though.
1463d4abf0Sagc */
1563d4abf0Sagc
1663d4abf0Sagc #ifdef HAVE_CONFIG_H
1763d4abf0Sagc #include <config.h>
1863d4abf0Sagc #endif /* HAVE_CONFIG_H */
1963d4abf0Sagc #include <stdlib.h>
2063d4abf0Sagc #include <string.h>
2163d4abf0Sagc
2263d4abf0Sagc #include "tre-internal.h"
2363d4abf0Sagc #include "tre-mem.h"
2463d4abf0Sagc #include "xmalloc.h"
2563d4abf0Sagc
2663d4abf0Sagc
2763d4abf0Sagc /* Returns a new memory allocator or NULL if out of memory. */
2863d4abf0Sagc tre_mem_t
tre_mem_new_impl(int provided,void * provided_block)2963d4abf0Sagc tre_mem_new_impl(int provided, void *provided_block)
3063d4abf0Sagc {
3163d4abf0Sagc tre_mem_t mem;
3263d4abf0Sagc if (provided)
3363d4abf0Sagc {
3463d4abf0Sagc mem = provided_block;
3563d4abf0Sagc memset(mem, 0, sizeof(*mem));
3663d4abf0Sagc }
3763d4abf0Sagc else
3863d4abf0Sagc mem = xcalloc(1, sizeof(*mem));
3963d4abf0Sagc if (mem == NULL)
4063d4abf0Sagc return NULL;
4163d4abf0Sagc return mem;
4263d4abf0Sagc }
4363d4abf0Sagc
4463d4abf0Sagc
4563d4abf0Sagc /* Frees the memory allocator and all memory allocated with it. */
4663d4abf0Sagc void
tre_mem_destroy(tre_mem_t mem)4763d4abf0Sagc tre_mem_destroy(tre_mem_t mem)
4863d4abf0Sagc {
4963d4abf0Sagc tre_list_t *tmp, *l = mem->blocks;
5063d4abf0Sagc
5163d4abf0Sagc while (l != NULL)
5263d4abf0Sagc {
5363d4abf0Sagc xfree(l->data);
5463d4abf0Sagc tmp = l->next;
5563d4abf0Sagc xfree(l);
5663d4abf0Sagc l = tmp;
5763d4abf0Sagc }
5863d4abf0Sagc xfree(mem);
5963d4abf0Sagc }
6063d4abf0Sagc
6163d4abf0Sagc
6263d4abf0Sagc /* Allocates a block of `size' bytes from `mem'. Returns a pointer to the
6363d4abf0Sagc allocated block or NULL if an underlying malloc() failed. */
6463d4abf0Sagc void *
tre_mem_alloc_impl(tre_mem_t mem,int provided,void * provided_block,int zero,size_t size)6563d4abf0Sagc tre_mem_alloc_impl(tre_mem_t mem, int provided, void *provided_block,
6663d4abf0Sagc int zero, size_t size)
6763d4abf0Sagc {
6863d4abf0Sagc void *ptr;
6963d4abf0Sagc
7063d4abf0Sagc if (mem->failed)
7163d4abf0Sagc {
7263d4abf0Sagc DPRINT(("tre_mem_alloc: oops, called after failure?!\n"));
7363d4abf0Sagc return NULL;
7463d4abf0Sagc }
7563d4abf0Sagc
7663d4abf0Sagc #ifdef MALLOC_DEBUGGING
7763d4abf0Sagc if (!provided)
7863d4abf0Sagc {
7963d4abf0Sagc ptr = xmalloc(1);
8063d4abf0Sagc if (ptr == NULL)
8163d4abf0Sagc {
8263d4abf0Sagc DPRINT(("tre_mem_alloc: xmalloc forced failure\n"));
8363d4abf0Sagc mem->failed = 1;
8463d4abf0Sagc return NULL;
8563d4abf0Sagc }
8663d4abf0Sagc xfree(ptr);
8763d4abf0Sagc }
8863d4abf0Sagc #endif /* MALLOC_DEBUGGING */
8963d4abf0Sagc
9063d4abf0Sagc if (mem->n < size)
9163d4abf0Sagc {
9263d4abf0Sagc /* We need more memory than is available in the current block.
9363d4abf0Sagc Allocate a new block. */
9463d4abf0Sagc tre_list_t *l;
9563d4abf0Sagc if (provided)
9663d4abf0Sagc {
9763d4abf0Sagc DPRINT(("tre_mem_alloc: using provided block\n"));
9863d4abf0Sagc if (provided_block == NULL)
9963d4abf0Sagc {
10063d4abf0Sagc DPRINT(("tre_mem_alloc: provided block was NULL\n"));
10163d4abf0Sagc mem->failed = 1;
10263d4abf0Sagc return NULL;
10363d4abf0Sagc }
10463d4abf0Sagc mem->ptr = provided_block;
10563d4abf0Sagc mem->n = TRE_MEM_BLOCK_SIZE;
10663d4abf0Sagc }
10763d4abf0Sagc else
10863d4abf0Sagc {
109*f2a3d147Schristos size_t block_size;
11063d4abf0Sagc if (size * 8 > TRE_MEM_BLOCK_SIZE)
11163d4abf0Sagc block_size = size * 8;
11263d4abf0Sagc else
11363d4abf0Sagc block_size = TRE_MEM_BLOCK_SIZE;
11463d4abf0Sagc DPRINT(("tre_mem_alloc: allocating new %d byte block\n",
11563d4abf0Sagc block_size));
11663d4abf0Sagc l = xmalloc(sizeof(*l));
11763d4abf0Sagc if (l == NULL)
11863d4abf0Sagc {
11963d4abf0Sagc mem->failed = 1;
12063d4abf0Sagc return NULL;
12163d4abf0Sagc }
12263d4abf0Sagc l->data = xmalloc(block_size);
12363d4abf0Sagc if (l->data == NULL)
12463d4abf0Sagc {
12563d4abf0Sagc xfree(l);
12663d4abf0Sagc mem->failed = 1;
12763d4abf0Sagc return NULL;
12863d4abf0Sagc }
12963d4abf0Sagc l->next = NULL;
13063d4abf0Sagc if (mem->current != NULL)
13163d4abf0Sagc mem->current->next = l;
13263d4abf0Sagc if (mem->blocks == NULL)
13363d4abf0Sagc mem->blocks = l;
13463d4abf0Sagc mem->current = l;
13563d4abf0Sagc mem->ptr = l->data;
13663d4abf0Sagc mem->n = block_size;
13763d4abf0Sagc }
13863d4abf0Sagc }
13963d4abf0Sagc
14063d4abf0Sagc /* Make sure the next pointer will be aligned. */
14163d4abf0Sagc size += ALIGN(mem->ptr + size, long);
14263d4abf0Sagc
14363d4abf0Sagc /* Allocate from current block. */
14463d4abf0Sagc ptr = mem->ptr;
14563d4abf0Sagc mem->ptr += size;
14663d4abf0Sagc mem->n -= size;
14763d4abf0Sagc
14863d4abf0Sagc /* Set to zero if needed. */
14963d4abf0Sagc if (zero)
15063d4abf0Sagc memset(ptr, 0, size);
15163d4abf0Sagc
15263d4abf0Sagc return ptr;
15363d4abf0Sagc }
15463d4abf0Sagc
15563d4abf0Sagc /* EOF */
156