objalloc.c revision 1.1 1 1.1 skrll /* objalloc.c -- routines to allocate memory for objects
2 1.1 skrll Copyright 1997 Free Software Foundation, Inc.
3 1.1 skrll Written by Ian Lance Taylor, Cygnus Solutions.
4 1.1 skrll
5 1.1 skrll This program is free software; you can redistribute it and/or modify it
6 1.1 skrll under the terms of the GNU General Public License as published by the
7 1.1 skrll Free Software Foundation; either version 2, or (at your option) any
8 1.1 skrll later version.
9 1.1 skrll
10 1.1 skrll This program is distributed in the hope that it will be useful,
11 1.1 skrll but WITHOUT ANY WARRANTY; without even the implied warranty of
12 1.1 skrll MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 1.1 skrll GNU General Public License for more details.
14 1.1 skrll
15 1.1 skrll You should have received a copy of the GNU General Public License
16 1.1 skrll along with this program; if not, write to the Free Software
17 1.1 skrll Foundation, 51 Franklin Street - Fifth Floor,
18 1.1 skrll Boston, MA 02110-1301, USA. */
19 1.1 skrll
20 1.1 skrll #include "config.h"
21 1.1 skrll #include "ansidecl.h"
22 1.1 skrll
23 1.1 skrll #include "objalloc.h"
24 1.1 skrll
25 1.1 skrll /* Get a definition for NULL. */
26 1.1 skrll #include <stdio.h>
27 1.1 skrll
28 1.1 skrll #if VMS
29 1.1 skrll #include <stdlib.h>
30 1.1 skrll #include <unixlib.h>
31 1.1 skrll #else
32 1.1 skrll
33 1.1 skrll /* Get a definition for size_t. */
34 1.1 skrll #include <stddef.h>
35 1.1 skrll
36 1.1 skrll #ifdef HAVE_STDLIB_H
37 1.1 skrll #include <stdlib.h>
38 1.1 skrll #else
39 1.1 skrll /* For systems with larger pointers than ints, this must be declared. */
40 1.1 skrll extern PTR malloc (size_t);
41 1.1 skrll extern void free (PTR);
42 1.1 skrll #endif
43 1.1 skrll
44 1.1 skrll #endif
45 1.1 skrll
46 1.1 skrll /* These routines allocate space for an object. Freeing allocated
47 1.1 skrll space may or may not free all more recently allocated space.
48 1.1 skrll
49 1.1 skrll We handle large and small allocation requests differently. If we
50 1.1 skrll don't have enough space in the current block, and the allocation
51 1.1 skrll request is for more than 512 bytes, we simply pass it through to
52 1.1 skrll malloc. */
53 1.1 skrll
54 1.1 skrll /* The objalloc structure is defined in objalloc.h. */
55 1.1 skrll
56 1.1 skrll /* This structure appears at the start of each chunk. */
57 1.1 skrll
58 1.1 skrll struct objalloc_chunk
59 1.1 skrll {
60 1.1 skrll /* Next chunk. */
61 1.1 skrll struct objalloc_chunk *next;
62 1.1 skrll /* If this chunk contains large objects, this is the value of
63 1.1 skrll current_ptr when this chunk was allocated. If this chunk
64 1.1 skrll contains small objects, this is NULL. */
65 1.1 skrll char *current_ptr;
66 1.1 skrll };
67 1.1 skrll
68 1.1 skrll /* The aligned size of objalloc_chunk. */
69 1.1 skrll
70 1.1 skrll #define CHUNK_HEADER_SIZE \
71 1.1 skrll ((sizeof (struct objalloc_chunk) + OBJALLOC_ALIGN - 1) \
72 1.1 skrll &~ (OBJALLOC_ALIGN - 1))
73 1.1 skrll
74 1.1 skrll /* We ask for this much memory each time we create a chunk which is to
75 1.1 skrll hold small objects. */
76 1.1 skrll
77 1.1 skrll #define CHUNK_SIZE (4096 - 32)
78 1.1 skrll
79 1.1 skrll /* A request for this amount or more is just passed through to malloc. */
80 1.1 skrll
81 1.1 skrll #define BIG_REQUEST (512)
82 1.1 skrll
83 1.1 skrll /* Create an objalloc structure. */
84 1.1 skrll
85 1.1 skrll struct objalloc *
86 1.1 skrll objalloc_create (void)
87 1.1 skrll {
88 1.1 skrll struct objalloc *ret;
89 1.1 skrll struct objalloc_chunk *chunk;
90 1.1 skrll
91 1.1 skrll ret = (struct objalloc *) malloc (sizeof *ret);
92 1.1 skrll if (ret == NULL)
93 1.1 skrll return NULL;
94 1.1 skrll
95 1.1 skrll ret->chunks = (PTR) malloc (CHUNK_SIZE);
96 1.1 skrll if (ret->chunks == NULL)
97 1.1 skrll {
98 1.1 skrll free (ret);
99 1.1 skrll return NULL;
100 1.1 skrll }
101 1.1 skrll
102 1.1 skrll chunk = (struct objalloc_chunk *) ret->chunks;
103 1.1 skrll chunk->next = NULL;
104 1.1 skrll chunk->current_ptr = NULL;
105 1.1 skrll
106 1.1 skrll ret->current_ptr = (char *) chunk + CHUNK_HEADER_SIZE;
107 1.1 skrll ret->current_space = CHUNK_SIZE - CHUNK_HEADER_SIZE;
108 1.1 skrll
109 1.1 skrll return ret;
110 1.1 skrll }
111 1.1 skrll
112 1.1 skrll /* Allocate space from an objalloc structure. */
113 1.1 skrll
114 1.1 skrll PTR
115 1.1 skrll _objalloc_alloc (struct objalloc *o, unsigned long len)
116 1.1 skrll {
117 1.1 skrll /* We avoid confusion from zero sized objects by always allocating
118 1.1 skrll at least 1 byte. */
119 1.1 skrll if (len == 0)
120 1.1 skrll len = 1;
121 1.1 skrll
122 1.1 skrll len = (len + OBJALLOC_ALIGN - 1) &~ (OBJALLOC_ALIGN - 1);
123 1.1 skrll
124 1.1 skrll if (len <= o->current_space)
125 1.1 skrll {
126 1.1 skrll o->current_ptr += len;
127 1.1 skrll o->current_space -= len;
128 1.1 skrll return (PTR) (o->current_ptr - len);
129 1.1 skrll }
130 1.1 skrll
131 1.1 skrll if (len >= BIG_REQUEST)
132 1.1 skrll {
133 1.1 skrll char *ret;
134 1.1 skrll struct objalloc_chunk *chunk;
135 1.1 skrll
136 1.1 skrll ret = (char *) malloc (CHUNK_HEADER_SIZE + len);
137 1.1 skrll if (ret == NULL)
138 1.1 skrll return NULL;
139 1.1 skrll
140 1.1 skrll chunk = (struct objalloc_chunk *) ret;
141 1.1 skrll chunk->next = (struct objalloc_chunk *) o->chunks;
142 1.1 skrll chunk->current_ptr = o->current_ptr;
143 1.1 skrll
144 1.1 skrll o->chunks = (PTR) chunk;
145 1.1 skrll
146 1.1 skrll return (PTR) (ret + CHUNK_HEADER_SIZE);
147 1.1 skrll }
148 1.1 skrll else
149 1.1 skrll {
150 1.1 skrll struct objalloc_chunk *chunk;
151 1.1 skrll
152 1.1 skrll chunk = (struct objalloc_chunk *) malloc (CHUNK_SIZE);
153 1.1 skrll if (chunk == NULL)
154 1.1 skrll return NULL;
155 1.1 skrll chunk->next = (struct objalloc_chunk *) o->chunks;
156 1.1 skrll chunk->current_ptr = NULL;
157 1.1 skrll
158 1.1 skrll o->current_ptr = (char *) chunk + CHUNK_HEADER_SIZE;
159 1.1 skrll o->current_space = CHUNK_SIZE - CHUNK_HEADER_SIZE;
160 1.1 skrll
161 1.1 skrll o->chunks = (PTR) chunk;
162 1.1 skrll
163 1.1 skrll return objalloc_alloc (o, len);
164 1.1 skrll }
165 1.1 skrll }
166 1.1 skrll
167 1.1 skrll /* Free an entire objalloc structure. */
168 1.1 skrll
169 1.1 skrll void
170 1.1 skrll objalloc_free (struct objalloc *o)
171 1.1 skrll {
172 1.1 skrll struct objalloc_chunk *l;
173 1.1 skrll
174 1.1 skrll l = (struct objalloc_chunk *) o->chunks;
175 1.1 skrll while (l != NULL)
176 1.1 skrll {
177 1.1 skrll struct objalloc_chunk *next;
178 1.1 skrll
179 1.1 skrll next = l->next;
180 1.1 skrll free (l);
181 1.1 skrll l = next;
182 1.1 skrll }
183 1.1 skrll
184 1.1 skrll free (o);
185 1.1 skrll }
186 1.1 skrll
187 1.1 skrll /* Free a block from an objalloc structure. This also frees all more
188 1.1 skrll recently allocated blocks. */
189 1.1 skrll
190 1.1 skrll void
191 1.1 skrll objalloc_free_block (struct objalloc *o, PTR block)
192 1.1 skrll {
193 1.1 skrll struct objalloc_chunk *p, *small;
194 1.1 skrll char *b = (char *) block;
195 1.1 skrll
196 1.1 skrll /* First set P to the chunk which contains the block we are freeing,
197 1.1 skrll and set Q to the last small object chunk we see before P. */
198 1.1 skrll small = NULL;
199 1.1 skrll for (p = (struct objalloc_chunk *) o->chunks; p != NULL; p = p->next)
200 1.1 skrll {
201 1.1 skrll if (p->current_ptr == NULL)
202 1.1 skrll {
203 1.1 skrll if (b > (char *) p && b < (char *) p + CHUNK_SIZE)
204 1.1 skrll break;
205 1.1 skrll small = p;
206 1.1 skrll }
207 1.1 skrll else
208 1.1 skrll {
209 1.1 skrll if (b == (char *) p + CHUNK_HEADER_SIZE)
210 1.1 skrll break;
211 1.1 skrll }
212 1.1 skrll }
213 1.1 skrll
214 1.1 skrll /* If we can't find the chunk, the caller has made a mistake. */
215 1.1 skrll if (p == NULL)
216 1.1 skrll abort ();
217 1.1 skrll
218 1.1 skrll if (p->current_ptr == NULL)
219 1.1 skrll {
220 1.1 skrll struct objalloc_chunk *q;
221 1.1 skrll struct objalloc_chunk *first;
222 1.1 skrll
223 1.1 skrll /* The block is in a chunk containing small objects. We can
224 1.1 skrll free every chunk through SMALL, because they have certainly
225 1.1 skrll been allocated more recently. After SMALL, we will not see
226 1.1 skrll any chunks containing small objects; we can free any big
227 1.1 skrll chunk if the current_ptr is greater than or equal to B. We
228 1.1 skrll can then reset the new current_ptr to B. */
229 1.1 skrll
230 1.1 skrll first = NULL;
231 1.1 skrll q = (struct objalloc_chunk *) o->chunks;
232 1.1 skrll while (q != p)
233 1.1 skrll {
234 1.1 skrll struct objalloc_chunk *next;
235 1.1 skrll
236 1.1 skrll next = q->next;
237 1.1 skrll if (small != NULL)
238 1.1 skrll {
239 1.1 skrll if (small == q)
240 1.1 skrll small = NULL;
241 1.1 skrll free (q);
242 1.1 skrll }
243 1.1 skrll else if (q->current_ptr > b)
244 1.1 skrll free (q);
245 1.1 skrll else if (first == NULL)
246 1.1 skrll first = q;
247 1.1 skrll
248 1.1 skrll q = next;
249 1.1 skrll }
250 1.1 skrll
251 1.1 skrll if (first == NULL)
252 1.1 skrll first = p;
253 1.1 skrll o->chunks = (PTR) first;
254 1.1 skrll
255 1.1 skrll /* Now start allocating from this small block again. */
256 1.1 skrll o->current_ptr = b;
257 1.1 skrll o->current_space = ((char *) p + CHUNK_SIZE) - b;
258 1.1 skrll }
259 1.1 skrll else
260 1.1 skrll {
261 1.1 skrll struct objalloc_chunk *q;
262 1.1 skrll char *current_ptr;
263 1.1 skrll
264 1.1 skrll /* This block is in a large chunk by itself. We can free
265 1.1 skrll everything on the list up to and including this block. We
266 1.1 skrll then start allocating from the next chunk containing small
267 1.1 skrll objects, setting current_ptr from the value stored with the
268 1.1 skrll large chunk we are freeing. */
269 1.1 skrll
270 1.1 skrll current_ptr = p->current_ptr;
271 1.1 skrll p = p->next;
272 1.1 skrll
273 1.1 skrll q = (struct objalloc_chunk *) o->chunks;
274 1.1 skrll while (q != p)
275 1.1 skrll {
276 1.1 skrll struct objalloc_chunk *next;
277 1.1 skrll
278 1.1 skrll next = q->next;
279 1.1 skrll free (q);
280 1.1 skrll q = next;
281 1.1 skrll }
282 1.1 skrll
283 1.1 skrll o->chunks = (PTR) p;
284 1.1 skrll
285 1.1 skrll while (p->current_ptr != NULL)
286 1.1 skrll p = p->next;
287 1.1 skrll
288 1.1 skrll o->current_ptr = current_ptr;
289 1.1 skrll o->current_space = ((char *) p + CHUNK_SIZE) - current_ptr;
290 1.1 skrll }
291 1.1 skrll }
292