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