1570af302Sopenharmony_ci/*
2570af302Sopenharmony_ci  tre-mem.c - TRE memory allocator
3570af302Sopenharmony_ci
4570af302Sopenharmony_ci  Copyright (c) 2001-2009 Ville Laurikari <vl@iki.fi>
5570af302Sopenharmony_ci  All rights reserved.
6570af302Sopenharmony_ci
7570af302Sopenharmony_ci  Redistribution and use in source and binary forms, with or without
8570af302Sopenharmony_ci  modification, are permitted provided that the following conditions
9570af302Sopenharmony_ci  are met:
10570af302Sopenharmony_ci
11570af302Sopenharmony_ci    1. Redistributions of source code must retain the above copyright
12570af302Sopenharmony_ci       notice, this list of conditions and the following disclaimer.
13570af302Sopenharmony_ci
14570af302Sopenharmony_ci    2. Redistributions in binary form must reproduce the above copyright
15570af302Sopenharmony_ci       notice, this list of conditions and the following disclaimer in the
16570af302Sopenharmony_ci       documentation and/or other materials provided with the distribution.
17570af302Sopenharmony_ci
18570af302Sopenharmony_ci  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS
19570af302Sopenharmony_ci  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20570af302Sopenharmony_ci  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21570af302Sopenharmony_ci  A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT
22570af302Sopenharmony_ci  HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23570af302Sopenharmony_ci  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24570af302Sopenharmony_ci  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25570af302Sopenharmony_ci  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26570af302Sopenharmony_ci  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27570af302Sopenharmony_ci  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28570af302Sopenharmony_ci  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29570af302Sopenharmony_ci
30570af302Sopenharmony_ci*/
31570af302Sopenharmony_ci
32570af302Sopenharmony_ci/*
33570af302Sopenharmony_ci  This memory allocator is for allocating small memory blocks efficiently
34570af302Sopenharmony_ci  in terms of memory overhead and execution speed.  The allocated blocks
35570af302Sopenharmony_ci  cannot be freed individually, only all at once.  There can be multiple
36570af302Sopenharmony_ci  allocators, though.
37570af302Sopenharmony_ci*/
38570af302Sopenharmony_ci
39570af302Sopenharmony_ci#include <stdlib.h>
40570af302Sopenharmony_ci#include <string.h>
41570af302Sopenharmony_ci
42570af302Sopenharmony_ci#include "tre.h"
43570af302Sopenharmony_ci
44570af302Sopenharmony_ci/*
45570af302Sopenharmony_ci  This memory allocator is for allocating small memory blocks efficiently
46570af302Sopenharmony_ci  in terms of memory overhead and execution speed.  The allocated blocks
47570af302Sopenharmony_ci  cannot be freed individually, only all at once.  There can be multiple
48570af302Sopenharmony_ci  allocators, though.
49570af302Sopenharmony_ci*/
50570af302Sopenharmony_ci
51570af302Sopenharmony_ci/* Returns a new memory allocator or NULL if out of memory. */
52570af302Sopenharmony_citre_mem_t
53570af302Sopenharmony_citre_mem_new_impl(int provided, void *provided_block)
54570af302Sopenharmony_ci{
55570af302Sopenharmony_ci  tre_mem_t mem;
56570af302Sopenharmony_ci  if (provided)
57570af302Sopenharmony_ci    {
58570af302Sopenharmony_ci      mem = provided_block;
59570af302Sopenharmony_ci      memset(mem, 0, sizeof(*mem));
60570af302Sopenharmony_ci    }
61570af302Sopenharmony_ci  else
62570af302Sopenharmony_ci    mem = xcalloc(1, sizeof(*mem));
63570af302Sopenharmony_ci  if (mem == NULL)
64570af302Sopenharmony_ci    return NULL;
65570af302Sopenharmony_ci  return mem;
66570af302Sopenharmony_ci}
67570af302Sopenharmony_ci
68570af302Sopenharmony_ci
69570af302Sopenharmony_ci/* Frees the memory allocator and all memory allocated with it. */
70570af302Sopenharmony_civoid
71570af302Sopenharmony_citre_mem_destroy(tre_mem_t mem)
72570af302Sopenharmony_ci{
73570af302Sopenharmony_ci  tre_list_t *tmp, *l = mem->blocks;
74570af302Sopenharmony_ci
75570af302Sopenharmony_ci  while (l != NULL)
76570af302Sopenharmony_ci    {
77570af302Sopenharmony_ci      xfree(l->data);
78570af302Sopenharmony_ci      tmp = l->next;
79570af302Sopenharmony_ci      xfree(l);
80570af302Sopenharmony_ci      l = tmp;
81570af302Sopenharmony_ci    }
82570af302Sopenharmony_ci  xfree(mem);
83570af302Sopenharmony_ci}
84570af302Sopenharmony_ci
85570af302Sopenharmony_ci
86570af302Sopenharmony_ci/* Allocates a block of `size' bytes from `mem'.  Returns a pointer to the
87570af302Sopenharmony_ci   allocated block or NULL if an underlying malloc() failed. */
88570af302Sopenharmony_civoid *
89570af302Sopenharmony_citre_mem_alloc_impl(tre_mem_t mem, int provided, void *provided_block,
90570af302Sopenharmony_ci		   int zero, size_t size)
91570af302Sopenharmony_ci{
92570af302Sopenharmony_ci  void *ptr;
93570af302Sopenharmony_ci
94570af302Sopenharmony_ci  if (mem->failed)
95570af302Sopenharmony_ci    {
96570af302Sopenharmony_ci      return NULL;
97570af302Sopenharmony_ci    }
98570af302Sopenharmony_ci
99570af302Sopenharmony_ci  if (mem->n < size)
100570af302Sopenharmony_ci    {
101570af302Sopenharmony_ci      /* We need more memory than is available in the current block.
102570af302Sopenharmony_ci	 Allocate a new block. */
103570af302Sopenharmony_ci      tre_list_t *l;
104570af302Sopenharmony_ci      if (provided)
105570af302Sopenharmony_ci	{
106570af302Sopenharmony_ci	  if (provided_block == NULL)
107570af302Sopenharmony_ci	    {
108570af302Sopenharmony_ci	      mem->failed = 1;
109570af302Sopenharmony_ci	      return NULL;
110570af302Sopenharmony_ci	    }
111570af302Sopenharmony_ci	  mem->ptr = provided_block;
112570af302Sopenharmony_ci	  mem->n = TRE_MEM_BLOCK_SIZE;
113570af302Sopenharmony_ci	}
114570af302Sopenharmony_ci      else
115570af302Sopenharmony_ci	{
116570af302Sopenharmony_ci	  int block_size;
117570af302Sopenharmony_ci	  if (size * 8 > TRE_MEM_BLOCK_SIZE)
118570af302Sopenharmony_ci	    block_size = size * 8;
119570af302Sopenharmony_ci	  else
120570af302Sopenharmony_ci	    block_size = TRE_MEM_BLOCK_SIZE;
121570af302Sopenharmony_ci	  l = xmalloc(sizeof(*l));
122570af302Sopenharmony_ci	  if (l == NULL)
123570af302Sopenharmony_ci	    {
124570af302Sopenharmony_ci	      mem->failed = 1;
125570af302Sopenharmony_ci	      return NULL;
126570af302Sopenharmony_ci	    }
127570af302Sopenharmony_ci	  l->data = xmalloc(block_size);
128570af302Sopenharmony_ci	  if (l->data == NULL)
129570af302Sopenharmony_ci	    {
130570af302Sopenharmony_ci	      xfree(l);
131570af302Sopenharmony_ci	      mem->failed = 1;
132570af302Sopenharmony_ci	      return NULL;
133570af302Sopenharmony_ci	    }
134570af302Sopenharmony_ci	  l->next = NULL;
135570af302Sopenharmony_ci	  if (mem->current != NULL)
136570af302Sopenharmony_ci	    mem->current->next = l;
137570af302Sopenharmony_ci	  if (mem->blocks == NULL)
138570af302Sopenharmony_ci	    mem->blocks = l;
139570af302Sopenharmony_ci	  mem->current = l;
140570af302Sopenharmony_ci	  mem->ptr = l->data;
141570af302Sopenharmony_ci	  mem->n = block_size;
142570af302Sopenharmony_ci	}
143570af302Sopenharmony_ci    }
144570af302Sopenharmony_ci
145570af302Sopenharmony_ci  /* Make sure the next pointer will be aligned. */
146570af302Sopenharmony_ci  size += ALIGN(mem->ptr + size, long);
147570af302Sopenharmony_ci
148570af302Sopenharmony_ci  /* Allocate from current block. */
149570af302Sopenharmony_ci  ptr = mem->ptr;
150570af302Sopenharmony_ci  mem->ptr += size;
151570af302Sopenharmony_ci  mem->n -= size;
152570af302Sopenharmony_ci
153570af302Sopenharmony_ci  /* Set to zero if needed. */
154570af302Sopenharmony_ci  if (zero)
155570af302Sopenharmony_ci    memset(ptr, 0, size);
156570af302Sopenharmony_ci
157570af302Sopenharmony_ci  return ptr;
158570af302Sopenharmony_ci}
159