alloc.c revision 1.3.6.1 1 1.3.6.1 wrstuden /* $NetBSD: alloc.c,v 1.3.6.1 1999/12/27 18:27:01 wrstuden Exp $ */
2 1.2 tls
3 1.1 jtc /*
4 1.1 jtc * area-based allocation built on malloc/free
5 1.1 jtc */
6 1.1 jtc
7 1.1 jtc #include "sh.h"
8 1.3.6.1 wrstuden
9 1.3.6.1 wrstuden #ifdef TEST_ALLOC
10 1.3.6.1 wrstuden # define shellf printf
11 1.3.6.1 wrstuden # ifndef DEBUG_ALLOC
12 1.3.6.1 wrstuden # define DEBUG_ALLOC
13 1.3.6.1 wrstuden # endif /* DEBUG_ALLOC */
14 1.3.6.1 wrstuden #endif /* TEST_ALLOC */
15 1.3.6.1 wrstuden
16 1.1 jtc #ifdef MEM_DEBUG
17 1.1 jtc
18 1.3.6.1 wrstuden /*
19 1.3.6.1 wrstuden * Special versions of alloc routines if doing mem_debug
20 1.3.6.1 wrstuden */
21 1.3.6.1 wrstuden Area *
22 1.3.6.1 wrstuden _chmem_ainit(ap, file, line)
23 1.3.6.1 wrstuden Area *ap;
24 1.3.6.1 wrstuden const char *file;
25 1.3.6.1 wrstuden int line;
26 1.3.6.1 wrstuden {
27 1.3.6.1 wrstuden ap->freelist = (struct Block *) _chmem_newpool("ainit", (char *) 0, -1,
28 1.3.6.1 wrstuden file, line);
29 1.3.6.1 wrstuden if (!ap->freelist)
30 1.3.6.1 wrstuden aerror(ap, "ainit failed (ie, newpool)");
31 1.3.6.1 wrstuden return ap;
32 1.3.6.1 wrstuden }
33 1.3.6.1 wrstuden
34 1.3.6.1 wrstuden /* free all object in Area */
35 1.3.6.1 wrstuden void
36 1.3.6.1 wrstuden _chmem_afreeall(ap, file, line)
37 1.3.6.1 wrstuden Area *ap;
38 1.3.6.1 wrstuden const char *file;
39 1.3.6.1 wrstuden int line;
40 1.3.6.1 wrstuden {
41 1.3.6.1 wrstuden _chmem_delpool((Chmem_poolp) ap->freelist, 0, file, line);
42 1.3.6.1 wrstuden /* Kind of ugly, but it works */
43 1.3.6.1 wrstuden _chmem_ainit(ap, file, line);
44 1.3.6.1 wrstuden }
45 1.3.6.1 wrstuden
46 1.3.6.1 wrstuden /* allocate object from Area */
47 1.3.6.1 wrstuden void *
48 1.3.6.1 wrstuden _chmem_alloc(size, ap, file, line)
49 1.3.6.1 wrstuden size_t size;
50 1.3.6.1 wrstuden Area *ap;
51 1.3.6.1 wrstuden const char *file;
52 1.3.6.1 wrstuden int line;
53 1.3.6.1 wrstuden {
54 1.3.6.1 wrstuden return _chmem_mallocp((Chmem_poolp) ap->freelist, size, file, line);
55 1.3.6.1 wrstuden }
56 1.3.6.1 wrstuden
57 1.3.6.1 wrstuden /* change size of object -- like realloc */
58 1.3.6.1 wrstuden void *
59 1.3.6.1 wrstuden _chmem_aresize(ptr, size, ap, file, line)
60 1.3.6.1 wrstuden void *ptr;
61 1.3.6.1 wrstuden size_t size;
62 1.3.6.1 wrstuden Area *ap;
63 1.3.6.1 wrstuden const char *file;
64 1.3.6.1 wrstuden int line;
65 1.3.6.1 wrstuden {
66 1.3.6.1 wrstuden if (!ptr)
67 1.3.6.1 wrstuden /* Done as realloc(0, size) is not portable */
68 1.3.6.1 wrstuden return _chmem_mallocp((Chmem_poolp) ap->freelist, size,
69 1.3.6.1 wrstuden file, line);
70 1.3.6.1 wrstuden else
71 1.3.6.1 wrstuden return _chmem_reallocp((Chmem_poolp) ap->freelist, ptr, size,
72 1.3.6.1 wrstuden file, line);
73 1.3.6.1 wrstuden }
74 1.3.6.1 wrstuden
75 1.3.6.1 wrstuden void
76 1.3.6.1 wrstuden _chmem_afree(ptr, ap, file, line)
77 1.3.6.1 wrstuden void *ptr;
78 1.3.6.1 wrstuden Area *ap;
79 1.3.6.1 wrstuden const char *file;
80 1.3.6.1 wrstuden int line;
81 1.3.6.1 wrstuden {
82 1.3.6.1 wrstuden return _chmem_freep((Chmem_poolp) ap->freelist, ptr, file, line);
83 1.3.6.1 wrstuden }
84 1.3.6.1 wrstuden
85 1.3.6.1 wrstuden #else /* MEM_DEBUG */
86 1.3.6.1 wrstuden
87 1.3.6.1 wrstuden # if DEBUG_ALLOC
88 1.3.6.1 wrstuden void acheck ARGS((Area *ap));
89 1.3.6.1 wrstuden # define ACHECK(ap) acheck(ap)
90 1.3.6.1 wrstuden # else /* DEBUG_ALLOC */
91 1.3.6.1 wrstuden # define ACHECK(ap)
92 1.3.6.1 wrstuden # endif /* DEBUG_ALLOC */
93 1.3.6.1 wrstuden
94 1.3.6.1 wrstuden #define ICELLS 200 /* number of Cells in small Block */
95 1.1 jtc
96 1.1 jtc typedef union Cell Cell;
97 1.1 jtc typedef struct Block Block;
98 1.1 jtc
99 1.1 jtc /*
100 1.1 jtc * The Cells in a Block are organized as a set of objects.
101 1.3.6.1 wrstuden * Each object (pointed to by dp) begins with the block it is in
102 1.3.6.1 wrstuden * (dp-2)->block, then has a size in (dp-1)->size, which is
103 1.1 jtc * followed with "size" data Cells. Free objects are
104 1.1 jtc * linked together via dp->next.
105 1.1 jtc */
106 1.1 jtc
107 1.3.6.1 wrstuden #define NOBJECT_FIELDS 2 /* the block and size `fields' */
108 1.3.6.1 wrstuden
109 1.1 jtc union Cell {
110 1.1 jtc size_t size;
111 1.1 jtc Cell *next;
112 1.3.6.1 wrstuden Block *block;
113 1.1 jtc struct {int _;} junk; /* alignment */
114 1.3.6.1 wrstuden double djunk; /* alignment */
115 1.1 jtc };
116 1.1 jtc
117 1.1 jtc struct Block {
118 1.1 jtc Block *next; /* list of Blocks in Area */
119 1.3.6.1 wrstuden Block *prev; /* previous block in list */
120 1.1 jtc Cell *freelist; /* object free list */
121 1.1 jtc Cell *last; /* &b.cell[size] */
122 1.1 jtc Cell cell [1]; /* [size] Cells for allocation */
123 1.1 jtc };
124 1.1 jtc
125 1.3.6.1 wrstuden static Block aempty = {&aempty, &aempty, aempty.cell, aempty.cell};
126 1.3.6.1 wrstuden
127 1.3.6.1 wrstuden static void ablockfree ARGS((Block *bp, Area *ap));
128 1.3.6.1 wrstuden static void *asplit ARGS((Area *ap, Block *bp, Cell *fp, Cell *fpp, int cells));
129 1.1 jtc
130 1.1 jtc /* create empty Area */
131 1.1 jtc Area *
132 1.1 jtc ainit(ap)
133 1.1 jtc register Area *ap;
134 1.1 jtc {
135 1.1 jtc ap->freelist = &aempty;
136 1.3.6.1 wrstuden ACHECK(ap);
137 1.1 jtc return ap;
138 1.1 jtc }
139 1.1 jtc
140 1.1 jtc /* free all object in Area */
141 1.1 jtc void
142 1.1 jtc afreeall(ap)
143 1.1 jtc register Area *ap;
144 1.1 jtc {
145 1.1 jtc register Block *bp;
146 1.1 jtc register Block *tmp;
147 1.1 jtc
148 1.3.6.1 wrstuden ACHECK(ap);
149 1.1 jtc bp = ap->freelist;
150 1.1 jtc if (bp != NULL && bp != &aempty) {
151 1.1 jtc do {
152 1.3.6.1 wrstuden tmp = bp;
153 1.3.6.1 wrstuden bp = bp->next;
154 1.3.6.1 wrstuden free((void*)tmp);
155 1.1 jtc } while (bp != ap->freelist);
156 1.1 jtc ap->freelist = &aempty;
157 1.1 jtc }
158 1.3.6.1 wrstuden ACHECK(ap);
159 1.1 jtc }
160 1.1 jtc
161 1.1 jtc /* allocate object from Area */
162 1.1 jtc void *
163 1.1 jtc alloc(size, ap)
164 1.1 jtc size_t size;
165 1.1 jtc register Area *ap;
166 1.1 jtc {
167 1.3.6.1 wrstuden int cells, acells;
168 1.3.6.1 wrstuden Block *bp = 0;
169 1.3.6.1 wrstuden Cell *fp = 0, *fpp = 0;
170 1.1 jtc
171 1.3.6.1 wrstuden ACHECK(ap);
172 1.3.6.1 wrstuden if (size <= 0)
173 1.1 jtc aerror(ap, "allocate bad size");
174 1.3.6.1 wrstuden cells = (unsigned)(size + sizeof(Cell) - 1) / sizeof(Cell);
175 1.1 jtc
176 1.3.6.1 wrstuden /* allocate at least this many cells */
177 1.3.6.1 wrstuden acells = cells + NOBJECT_FIELDS;
178 1.3.6.1 wrstuden
179 1.3.6.1 wrstuden /*
180 1.3.6.1 wrstuden * Only attempt to track small objects - let malloc deal
181 1.3.6.1 wrstuden * with larger objects. (this way we don't have to deal with
182 1.3.6.1 wrstuden * coalescing memory, or with releasing it to the system)
183 1.3.6.1 wrstuden */
184 1.3.6.1 wrstuden if (cells <= ICELLS) {
185 1.3.6.1 wrstuden /* find free Cell large enough */
186 1.3.6.1 wrstuden for (bp = ap->freelist; ; bp = bp->next) {
187 1.3.6.1 wrstuden for (fpp = NULL, fp = bp->freelist;
188 1.3.6.1 wrstuden fp != bp->last; fpp = fp, fp = fp->next)
189 1.3.6.1 wrstuden {
190 1.3.6.1 wrstuden if ((fp-1)->size >= cells)
191 1.3.6.1 wrstuden goto Found;
192 1.1 jtc }
193 1.3.6.1 wrstuden /* wrapped around Block list, create new Block */
194 1.3.6.1 wrstuden if (bp->next == ap->freelist) {
195 1.3.6.1 wrstuden bp = 0;
196 1.3.6.1 wrstuden break;
197 1.1 jtc }
198 1.1 jtc }
199 1.3.6.1 wrstuden /* Not much free space left? Allocate a big object this time */
200 1.3.6.1 wrstuden acells += ICELLS;
201 1.3.6.1 wrstuden }
202 1.3.6.1 wrstuden if (bp == 0) {
203 1.3.6.1 wrstuden bp = (Block*) malloc(offsetof(Block, cell[acells]));
204 1.3.6.1 wrstuden if (bp == NULL)
205 1.3.6.1 wrstuden aerror(ap, "cannot allocate");
206 1.3.6.1 wrstuden if (ap->freelist == &aempty) {
207 1.3.6.1 wrstuden ap->freelist = bp->next = bp->prev = bp;
208 1.3.6.1 wrstuden } else {
209 1.3.6.1 wrstuden bp->next = ap->freelist->next;
210 1.3.6.1 wrstuden ap->freelist->next->prev = bp;
211 1.3.6.1 wrstuden ap->freelist->next = bp;
212 1.3.6.1 wrstuden bp->prev = ap->freelist;
213 1.3.6.1 wrstuden }
214 1.3.6.1 wrstuden bp->last = bp->cell + acells;
215 1.3.6.1 wrstuden /* initial free list */
216 1.3.6.1 wrstuden fp = bp->freelist = bp->cell + NOBJECT_FIELDS;
217 1.3.6.1 wrstuden (fp-1)->size = acells - NOBJECT_FIELDS;
218 1.3.6.1 wrstuden (fp-2)->block = bp;
219 1.3.6.1 wrstuden fp->next = bp->last;
220 1.3.6.1 wrstuden fpp = NULL;
221 1.1 jtc }
222 1.3.6.1 wrstuden
223 1.1 jtc Found:
224 1.3.6.1 wrstuden return asplit(ap, bp, fp, fpp, cells);
225 1.3.6.1 wrstuden }
226 1.3.6.1 wrstuden
227 1.3.6.1 wrstuden /* Do the work of splitting an object into allocated and (possibly) unallocated
228 1.3.6.1 wrstuden * objects. Returns the `allocated' object.
229 1.3.6.1 wrstuden */
230 1.3.6.1 wrstuden static void *
231 1.3.6.1 wrstuden asplit(ap, bp, fp, fpp, cells)
232 1.3.6.1 wrstuden Area *ap;
233 1.3.6.1 wrstuden Block *bp;
234 1.3.6.1 wrstuden Cell *fp;
235 1.3.6.1 wrstuden Cell *fpp;
236 1.3.6.1 wrstuden int cells;
237 1.3.6.1 wrstuden {
238 1.3.6.1 wrstuden Cell *dp = fp; /* allocated object */
239 1.3.6.1 wrstuden int split = (fp-1)->size - cells;
240 1.3.6.1 wrstuden
241 1.3.6.1 wrstuden ACHECK(ap);
242 1.1 jtc if (split < 0)
243 1.1 jtc aerror(ap, "allocated object too small");
244 1.3.6.1 wrstuden if (split <= NOBJECT_FIELDS) { /* allocate all */
245 1.1 jtc fp = fp->next;
246 1.1 jtc } else { /* allocate head, free tail */
247 1.3.6.1 wrstuden Cell *next = fp->next; /* needed, as cells may be 0 */
248 1.3.6.1 wrstuden ap->freelist = bp; /* next time, start looking for space here */
249 1.1 jtc (fp-1)->size = cells;
250 1.3.6.1 wrstuden fp += cells + NOBJECT_FIELDS;
251 1.3.6.1 wrstuden (fp-1)->size = split - NOBJECT_FIELDS;
252 1.3.6.1 wrstuden (fp-2)->block = bp;
253 1.3.6.1 wrstuden fp->next = next;
254 1.1 jtc }
255 1.1 jtc if (fpp == NULL)
256 1.1 jtc bp->freelist = fp;
257 1.1 jtc else
258 1.1 jtc fpp->next = fp;
259 1.3.6.1 wrstuden ACHECK(ap);
260 1.1 jtc return (void*) dp;
261 1.1 jtc }
262 1.1 jtc
263 1.1 jtc /* change size of object -- like realloc */
264 1.1 jtc void *
265 1.1 jtc aresize(ptr, size, ap)
266 1.1 jtc register void *ptr;
267 1.1 jtc size_t size;
268 1.1 jtc Area *ap;
269 1.1 jtc {
270 1.1 jtc int cells;
271 1.3.6.1 wrstuden Cell *dp = (Cell*) ptr;
272 1.3.6.1 wrstuden int oldcells = dp ? (dp-1)->size : 0;
273 1.1 jtc
274 1.3.6.1 wrstuden ACHECK(ap);
275 1.3.6.1 wrstuden if (size <= 0)
276 1.1 jtc aerror(ap, "allocate bad size");
277 1.3.6.1 wrstuden /* New size (in cells) */
278 1.1 jtc cells = (unsigned)(size - 1) / sizeof(Cell) + 1;
279 1.1 jtc
280 1.3.6.1 wrstuden /* Is this a large object? If so, let malloc deal with it
281 1.3.6.1 wrstuden * directly (unless we are crossing the ICELLS border, in
282 1.3.6.1 wrstuden * which case the alloc/free below handles it - this should
283 1.3.6.1 wrstuden * cut down on fragmentation, and will also keep the code
284 1.3.6.1 wrstuden * working (as it assumes size < ICELLS means it is not
285 1.3.6.1 wrstuden * a `large object').
286 1.3.6.1 wrstuden */
287 1.3.6.1 wrstuden if (oldcells > ICELLS && cells > ICELLS) {
288 1.3.6.1 wrstuden Block *bp = (dp-2)->block;
289 1.3.6.1 wrstuden Block *nbp;
290 1.3.6.1 wrstuden /* Saved in case realloc fails.. */
291 1.3.6.1 wrstuden Block *next = bp->next, *prev = bp->prev;
292 1.3.6.1 wrstuden
293 1.3.6.1 wrstuden if (bp->freelist != bp->last)
294 1.3.6.1 wrstuden aerror(ap, "allocation resizing free pointer");
295 1.3.6.1 wrstuden nbp = realloc((void *) bp,
296 1.3.6.1 wrstuden offsetof(Block, cell[cells + NOBJECT_FIELDS]));
297 1.3.6.1 wrstuden if (!nbp) {
298 1.3.6.1 wrstuden /* Have to clean up... */
299 1.3.6.1 wrstuden /* NOTE: If this code changes, similar changes may be
300 1.3.6.1 wrstuden * needed in ablockfree().
301 1.3.6.1 wrstuden */
302 1.3.6.1 wrstuden if (next == bp) /* only block */
303 1.3.6.1 wrstuden ap->freelist = &aempty;
304 1.3.6.1 wrstuden else {
305 1.3.6.1 wrstuden next->prev = prev;
306 1.3.6.1 wrstuden prev->next = next;
307 1.3.6.1 wrstuden if (ap->freelist == bp)
308 1.3.6.1 wrstuden ap->freelist = next;
309 1.3.6.1 wrstuden }
310 1.3.6.1 wrstuden aerror(ap, "cannot re-allocate");
311 1.3.6.1 wrstuden }
312 1.3.6.1 wrstuden /* If location changed, keep pointers straight... */
313 1.3.6.1 wrstuden if (nbp != bp) {
314 1.3.6.1 wrstuden if (next == bp) /* only one block */
315 1.3.6.1 wrstuden nbp->next = nbp->prev = nbp;
316 1.3.6.1 wrstuden else {
317 1.3.6.1 wrstuden next->prev = nbp;
318 1.3.6.1 wrstuden prev->next = nbp;
319 1.3.6.1 wrstuden }
320 1.3.6.1 wrstuden if (ap->freelist == bp)
321 1.3.6.1 wrstuden ap->freelist = nbp;
322 1.3.6.1 wrstuden dp = nbp->cell + NOBJECT_FIELDS;
323 1.3.6.1 wrstuden (dp-2)->block = nbp;
324 1.1 jtc }
325 1.3.6.1 wrstuden (dp-1)->size = cells;
326 1.3.6.1 wrstuden nbp->last = nbp->cell + cells + NOBJECT_FIELDS;
327 1.3.6.1 wrstuden nbp->freelist = nbp->last;
328 1.3.6.1 wrstuden
329 1.3.6.1 wrstuden ACHECK(ap);
330 1.3.6.1 wrstuden return (void*) dp;
331 1.3.6.1 wrstuden }
332 1.3.6.1 wrstuden
333 1.3.6.1 wrstuden /* Check if we can just grow this cell
334 1.3.6.1 wrstuden * (need to check that cells < ICELLS so we don't make an
335 1.3.6.1 wrstuden * object a `large' - that would mess everything up).
336 1.3.6.1 wrstuden */
337 1.3.6.1 wrstuden if (dp && cells > oldcells && cells <= ICELLS) {
338 1.3.6.1 wrstuden Cell *fp, *fpp;
339 1.3.6.1 wrstuden Block *bp = (dp-2)->block;
340 1.3.6.1 wrstuden int need = cells - oldcells - NOBJECT_FIELDS;
341 1.3.6.1 wrstuden
342 1.3.6.1 wrstuden /* XXX if we had a flag in an object indicating
343 1.3.6.1 wrstuden * if the object was free/allocated, we could
344 1.3.6.1 wrstuden * avoid this loop (perhaps)
345 1.3.6.1 wrstuden */
346 1.3.6.1 wrstuden for (fpp = NULL, fp = bp->freelist;
347 1.3.6.1 wrstuden fp != bp->last
348 1.3.6.1 wrstuden && dp + oldcells + NOBJECT_FIELDS <= fp
349 1.3.6.1 wrstuden ; fpp = fp, fp = fp->next)
350 1.3.6.1 wrstuden {
351 1.3.6.1 wrstuden if (dp + oldcells + NOBJECT_FIELDS == fp
352 1.3.6.1 wrstuden && (fp-1)->size >= need)
353 1.3.6.1 wrstuden {
354 1.3.6.1 wrstuden Cell *np = asplit(ap, bp, fp, fpp, need);
355 1.3.6.1 wrstuden /* May get more than we need here */
356 1.3.6.1 wrstuden (dp-1)->size += (np-1)->size + NOBJECT_FIELDS;
357 1.3.6.1 wrstuden ACHECK(ap);
358 1.3.6.1 wrstuden return ptr;
359 1.3.6.1 wrstuden }
360 1.3.6.1 wrstuden }
361 1.3.6.1 wrstuden }
362 1.3.6.1 wrstuden
363 1.3.6.1 wrstuden /* Check if we can just shrink this cell
364 1.3.6.1 wrstuden * (if oldcells > ICELLS, this is a large object and we leave
365 1.3.6.1 wrstuden * it to malloc...)
366 1.3.6.1 wrstuden * Note: this also handles cells == oldcells (a no-op).
367 1.3.6.1 wrstuden */
368 1.3.6.1 wrstuden if (dp && cells <= oldcells && oldcells <= ICELLS) {
369 1.1 jtc int split;
370 1.1 jtc
371 1.3.6.1 wrstuden split = oldcells - cells;
372 1.3.6.1 wrstuden if (split <= NOBJECT_FIELDS) /* cannot split */
373 1.1 jtc ;
374 1.1 jtc else { /* shrink head, free tail */
375 1.3.6.1 wrstuden Block *bp = (dp-2)->block;
376 1.3.6.1 wrstuden
377 1.1 jtc (dp-1)->size = cells;
378 1.3.6.1 wrstuden dp += cells + NOBJECT_FIELDS;
379 1.3.6.1 wrstuden (dp-1)->size = split - NOBJECT_FIELDS;
380 1.3.6.1 wrstuden (dp-2)->block = bp;
381 1.1 jtc afree((void*)dp, ap);
382 1.1 jtc }
383 1.3.6.1 wrstuden /* ACHECK() done in afree() */
384 1.3.6.1 wrstuden return ptr;
385 1.1 jtc }
386 1.3.6.1 wrstuden
387 1.3.6.1 wrstuden /* Have to do it the hard way... */
388 1.3.6.1 wrstuden ptr = alloc(size, ap);
389 1.3.6.1 wrstuden if (dp != NULL) {
390 1.3.6.1 wrstuden size_t s = (dp-1)->size * sizeof(Cell);
391 1.3.6.1 wrstuden if (s > size)
392 1.3.6.1 wrstuden s = size;
393 1.3.6.1 wrstuden memcpy(ptr, dp, s);
394 1.3.6.1 wrstuden afree((void *) dp, ap);
395 1.3.6.1 wrstuden }
396 1.3.6.1 wrstuden /* ACHECK() done in alloc()/afree() */
397 1.3.6.1 wrstuden return ptr;
398 1.1 jtc }
399 1.1 jtc
400 1.1 jtc void
401 1.1 jtc afree(ptr, ap)
402 1.1 jtc void *ptr;
403 1.1 jtc register Area *ap;
404 1.1 jtc {
405 1.1 jtc register Block *bp;
406 1.1 jtc register Cell *fp, *fpp;
407 1.1 jtc register Cell *dp = (Cell*)ptr;
408 1.1 jtc
409 1.3.6.1 wrstuden ACHECK(ap);
410 1.3.6.1 wrstuden if (ptr == 0)
411 1.3.6.1 wrstuden aerror(ap, "freeing null pointer");
412 1.3.6.1 wrstuden bp = (dp-2)->block;
413 1.3.6.1 wrstuden
414 1.3.6.1 wrstuden /* If this is a large object, just free it up... */
415 1.3.6.1 wrstuden /* Release object... */
416 1.3.6.1 wrstuden if ((dp-1)->size > ICELLS) {
417 1.3.6.1 wrstuden ablockfree(bp, ap);
418 1.3.6.1 wrstuden ACHECK(ap);
419 1.3.6.1 wrstuden return;
420 1.1 jtc }
421 1.1 jtc
422 1.3.6.1 wrstuden if (dp < &bp->cell[NOBJECT_FIELDS] || dp >= bp->last)
423 1.3.6.1 wrstuden aerror(ap, "freeing memory outside of block (corrupted?)");
424 1.3.6.1 wrstuden
425 1.1 jtc /* find position in free list */
426 1.3.6.1 wrstuden /* XXX if we had prev/next pointers for objects, this loop could go */
427 1.3.6.1 wrstuden for (fpp = NULL, fp = bp->freelist; fp < dp; fpp = fp, fp = fp->next)
428 1.1 jtc ;
429 1.1 jtc
430 1.3.6.1 wrstuden if (fp == dp)
431 1.1 jtc aerror(ap, "freeing free object");
432 1.1 jtc
433 1.1 jtc /* join object with next */
434 1.3.6.1 wrstuden if (dp + (dp-1)->size == fp-NOBJECT_FIELDS) { /* adjacent */
435 1.3.6.1 wrstuden (dp-1)->size += (fp-1)->size + NOBJECT_FIELDS;
436 1.1 jtc dp->next = fp->next;
437 1.1 jtc } else /* non-adjacent */
438 1.1 jtc dp->next = fp;
439 1.1 jtc
440 1.1 jtc /* join previous with object */
441 1.1 jtc if (fpp == NULL)
442 1.1 jtc bp->freelist = dp;
443 1.3.6.1 wrstuden else if (fpp + (fpp-1)->size == dp-NOBJECT_FIELDS) { /* adjacent */
444 1.3.6.1 wrstuden (fpp-1)->size += (dp-1)->size + NOBJECT_FIELDS;
445 1.1 jtc fpp->next = dp->next;
446 1.1 jtc } else /* non-adjacent */
447 1.1 jtc fpp->next = dp;
448 1.3.6.1 wrstuden
449 1.3.6.1 wrstuden /* If whole block is free (and we have some other blocks
450 1.3.6.1 wrstuden * around), release this block back to the system...
451 1.3.6.1 wrstuden */
452 1.3.6.1 wrstuden if (bp->next != bp && bp->freelist == bp->cell + NOBJECT_FIELDS
453 1.3.6.1 wrstuden && bp->freelist + (bp->freelist-1)->size == bp->last
454 1.3.6.1 wrstuden /* XXX and the other block has some free memory? */
455 1.3.6.1 wrstuden )
456 1.3.6.1 wrstuden ablockfree(bp, ap);
457 1.3.6.1 wrstuden ACHECK(ap);
458 1.3.6.1 wrstuden }
459 1.3.6.1 wrstuden
460 1.3.6.1 wrstuden static void
461 1.3.6.1 wrstuden ablockfree(bp, ap)
462 1.3.6.1 wrstuden Block *bp;
463 1.3.6.1 wrstuden Area *ap;
464 1.3.6.1 wrstuden {
465 1.3.6.1 wrstuden /* NOTE: If this code changes, similar changes may be
466 1.3.6.1 wrstuden * needed in alloc() (where realloc fails).
467 1.3.6.1 wrstuden */
468 1.3.6.1 wrstuden
469 1.3.6.1 wrstuden if (bp->next == bp) /* only block */
470 1.3.6.1 wrstuden ap->freelist = &aempty;
471 1.3.6.1 wrstuden else {
472 1.3.6.1 wrstuden bp->next->prev = bp->prev;
473 1.3.6.1 wrstuden bp->prev->next = bp->next;
474 1.3.6.1 wrstuden if (ap->freelist == bp)
475 1.3.6.1 wrstuden ap->freelist = bp->next;
476 1.3.6.1 wrstuden }
477 1.3.6.1 wrstuden free((void*) bp);
478 1.3.6.1 wrstuden }
479 1.3.6.1 wrstuden
480 1.3.6.1 wrstuden # if DEBUG_ALLOC
481 1.3.6.1 wrstuden void
482 1.3.6.1 wrstuden acheck(ap)
483 1.3.6.1 wrstuden Area *ap;
484 1.3.6.1 wrstuden {
485 1.3.6.1 wrstuden Block *bp, *bpp;
486 1.3.6.1 wrstuden Cell *dp, *dptmp, *fp;
487 1.3.6.1 wrstuden int ok = 1;
488 1.3.6.1 wrstuden int isfree;
489 1.3.6.1 wrstuden static int disabled;
490 1.3.6.1 wrstuden
491 1.3.6.1 wrstuden if (disabled)
492 1.3.6.1 wrstuden return;
493 1.3.6.1 wrstuden
494 1.3.6.1 wrstuden if (!ap) {
495 1.3.6.1 wrstuden disabled = 1;
496 1.3.6.1 wrstuden aerror(ap, "acheck: null area pointer");
497 1.3.6.1 wrstuden }
498 1.3.6.1 wrstuden
499 1.3.6.1 wrstuden bp = ap->freelist;
500 1.3.6.1 wrstuden if (!bp) {
501 1.3.6.1 wrstuden disabled = 1;
502 1.3.6.1 wrstuden aerror(ap, "acheck: null area freelist");
503 1.3.6.1 wrstuden }
504 1.3.6.1 wrstuden
505 1.3.6.1 wrstuden /* Nothing to check... */
506 1.3.6.1 wrstuden if (bp == &aempty)
507 1.3.6.1 wrstuden return;
508 1.3.6.1 wrstuden
509 1.3.6.1 wrstuden bpp = ap->freelist->prev;
510 1.3.6.1 wrstuden while (1) {
511 1.3.6.1 wrstuden if (bp->prev != bpp) {
512 1.3.6.1 wrstuden shellf("acheck: bp->prev != previous\n");
513 1.3.6.1 wrstuden ok = 0;
514 1.3.6.1 wrstuden }
515 1.3.6.1 wrstuden fp = bp->freelist;
516 1.3.6.1 wrstuden for (dp = &bp->cell[NOBJECT_FIELDS]; dp != bp->last; ) {
517 1.3.6.1 wrstuden if ((dp-2)->block != bp) {
518 1.3.6.1 wrstuden shellf("acheck: fragment's block is wrong\n");
519 1.3.6.1 wrstuden ok = 0;
520 1.3.6.1 wrstuden }
521 1.3.6.1 wrstuden isfree = dp == fp;
522 1.3.6.1 wrstuden if ((dp-1)->size == 0 && isfree) {
523 1.3.6.1 wrstuden shellf("acheck: 0 size frag\n");
524 1.3.6.1 wrstuden ok = 0;
525 1.3.6.1 wrstuden }
526 1.3.6.1 wrstuden if ((dp-1)->size > ICELLS
527 1.3.6.1 wrstuden && !isfree
528 1.3.6.1 wrstuden && (dp != &bp->cell[NOBJECT_FIELDS]
529 1.3.6.1 wrstuden || dp + (dp-1)->size != bp->last))
530 1.3.6.1 wrstuden {
531 1.3.6.1 wrstuden shellf("acheck: big cell doesn't make up whole block\n");
532 1.3.6.1 wrstuden ok = 0;
533 1.3.6.1 wrstuden }
534 1.3.6.1 wrstuden if (isfree) {
535 1.3.6.1 wrstuden if (dp->next <= dp) {
536 1.3.6.1 wrstuden shellf("acheck: free fragment's next <= self\n");
537 1.3.6.1 wrstuden ok = 0;
538 1.3.6.1 wrstuden }
539 1.3.6.1 wrstuden if (dp->next > bp->last) {
540 1.3.6.1 wrstuden shellf("acheck: free fragment's next > last\n");
541 1.3.6.1 wrstuden ok = 0;
542 1.3.6.1 wrstuden }
543 1.3.6.1 wrstuden fp = dp->next;
544 1.3.6.1 wrstuden }
545 1.3.6.1 wrstuden dptmp = dp + (dp-1)->size;
546 1.3.6.1 wrstuden if (dptmp > bp->last) {
547 1.3.6.1 wrstuden shellf("acheck: next frag out of range\n");
548 1.3.6.1 wrstuden ok = 0;
549 1.3.6.1 wrstuden break;
550 1.3.6.1 wrstuden } else if (dptmp != bp->last) {
551 1.3.6.1 wrstuden dptmp += NOBJECT_FIELDS;
552 1.3.6.1 wrstuden if (dptmp > bp->last) {
553 1.3.6.1 wrstuden shellf("acheck: next frag just out of range\n");
554 1.3.6.1 wrstuden ok = 0;
555 1.3.6.1 wrstuden break;
556 1.3.6.1 wrstuden }
557 1.3.6.1 wrstuden }
558 1.3.6.1 wrstuden if (isfree && dptmp == fp && dptmp != bp->last) {
559 1.3.6.1 wrstuden shellf("acheck: adjacent free frags\n");
560 1.3.6.1 wrstuden ok = 0;
561 1.3.6.1 wrstuden } else if (dptmp > fp) {
562 1.3.6.1 wrstuden shellf("acheck: free frag list messed up\n");
563 1.3.6.1 wrstuden ok = 0;
564 1.3.6.1 wrstuden }
565 1.3.6.1 wrstuden dp = dptmp;
566 1.3.6.1 wrstuden }
567 1.3.6.1 wrstuden bpp = bp;
568 1.3.6.1 wrstuden bp = bp->next;
569 1.3.6.1 wrstuden if (bp == ap->freelist)
570 1.3.6.1 wrstuden break;
571 1.3.6.1 wrstuden }
572 1.3.6.1 wrstuden if (!ok) {
573 1.3.6.1 wrstuden disabled = 1;
574 1.3.6.1 wrstuden aerror(ap, "acheck failed");
575 1.3.6.1 wrstuden }
576 1.1 jtc }
577 1.1 jtc
578 1.1 jtc void
579 1.1 jtc aprint(ap, ptr, size)
580 1.1 jtc register Area *ap;
581 1.1 jtc void *ptr;
582 1.1 jtc size_t size;
583 1.1 jtc {
584 1.1 jtc Block *bp;
585 1.1 jtc
586 1.1 jtc if (!ap)
587 1.1 jtc shellf("aprint: null area pointer\n");
588 1.1 jtc else if (!(bp = ap->freelist))
589 1.1 jtc shellf("aprint: null area freelist\n");
590 1.1 jtc else if (bp == &aempty)
591 1.1 jtc shellf("aprint: area is empty\n");
592 1.1 jtc else {
593 1.1 jtc int i;
594 1.3.6.1 wrstuden Cell *dp, *fp;
595 1.3.6.1 wrstuden Block *bpp;
596 1.1 jtc
597 1.3.6.1 wrstuden bpp = ap->freelist->prev;
598 1.3.6.1 wrstuden for (i = 0; ; i++) {
599 1.1 jtc if (ptr) {
600 1.1 jtc void *eptr = (void *) (((char *) ptr) + size);
601 1.1 jtc /* print block only if it overlaps ptr/size */
602 1.1 jtc if (!((ptr >= (void *) bp
603 1.1 jtc && ptr <= (void *) bp->last)
604 1.1 jtc || (eptr >= (void *) bp
605 1.1 jtc && eptr <= (void *) bp->last)))
606 1.1 jtc continue;
607 1.1 jtc shellf("aprint: overlap of 0x%p .. 0x%p\n",
608 1.1 jtc ptr, eptr);
609 1.1 jtc }
610 1.3.6.1 wrstuden if (bp->prev != bpp || bp->next->prev != bp)
611 1.3.6.1 wrstuden shellf(
612 1.3.6.1 wrstuden "aprint: BAD prev pointer: bp %p, bp->prev %p, bp->next %p, bpp=%p\n",
613 1.3.6.1 wrstuden bp, bp->prev, bp->next, bpp);
614 1.3.6.1 wrstuden shellf("aprint: block %2d (p=%p,%p,n=%p): 0x%p .. 0x%p (%ld)\n", i,
615 1.3.6.1 wrstuden bp->prev, bp, bp->next,
616 1.1 jtc bp->cell, bp->last,
617 1.3.6.1 wrstuden (long) ((char *) bp->last - (char *) bp->cell));
618 1.3.6.1 wrstuden fp = bp->freelist;
619 1.3.6.1 wrstuden if (bp->last <= bp->cell + NOBJECT_FIELDS)
620 1.1 jtc shellf(
621 1.3.6.1 wrstuden "aprint: BAD bp->last too small: %p <= %p\n",
622 1.3.6.1 wrstuden bp->last, bp->cell + NOBJECT_FIELDS);
623 1.3.6.1 wrstuden if (bp->freelist < bp->cell + NOBJECT_FIELDS
624 1.3.6.1 wrstuden || bp->freelist > bp->last)
625 1.3.6.1 wrstuden shellf(
626 1.3.6.1 wrstuden "aprint: BAD bp->freelist %p out of range: %p .. %p\n",
627 1.3.6.1 wrstuden bp->freelist,
628 1.3.6.1 wrstuden bp->cell + NOBJECT_FIELDS, bp->last);
629 1.3.6.1 wrstuden for (dp = bp->cell; dp != bp->last ; ) {
630 1.3.6.1 wrstuden dp += NOBJECT_FIELDS;
631 1.3.6.1 wrstuden shellf(
632 1.3.6.1 wrstuden "aprint: 0x%p .. 0x%p (%ld) %s\n",
633 1.3.6.1 wrstuden (dp-NOBJECT_FIELDS),
634 1.3.6.1 wrstuden (dp-NOBJECT_FIELDS) + (dp-1)->size
635 1.3.6.1 wrstuden + NOBJECT_FIELDS,
636 1.3.6.1 wrstuden (long) ((dp-1)->size + NOBJECT_FIELDS)
637 1.3.6.1 wrstuden * sizeof(Cell),
638 1.3.6.1 wrstuden dp == fp ? "free" : "allocated");
639 1.3.6.1 wrstuden if ((dp-2)->block != bp)
640 1.3.6.1 wrstuden shellf(
641 1.3.6.1 wrstuden "aprint: BAD dp->block %p != bp %p\n",
642 1.3.6.1 wrstuden (dp-2)->block, bp);
643 1.3.6.1 wrstuden if (dp > bp->last)
644 1.3.6.1 wrstuden shellf(
645 1.3.6.1 wrstuden "aprint: BAD dp gone past block: %p > %p\n",
646 1.3.6.1 wrstuden dp, bp->last);
647 1.3.6.1 wrstuden if (dp > fp)
648 1.3.6.1 wrstuden shellf(
649 1.3.6.1 wrstuden "aprint: BAD dp gone past free: %p > %p\n",
650 1.3.6.1 wrstuden dp, fp);
651 1.3.6.1 wrstuden if (dp == fp) {
652 1.3.6.1 wrstuden fp = fp->next;
653 1.3.6.1 wrstuden if (fp < dp || fp > bp->last)
654 1.3.6.1 wrstuden shellf(
655 1.3.6.1 wrstuden "aprint: BAD free object %p out of range: %p .. %p\n",
656 1.3.6.1 wrstuden fp,
657 1.3.6.1 wrstuden dp, bp->last);
658 1.3.6.1 wrstuden }
659 1.3.6.1 wrstuden dp += (dp-1)->size;
660 1.3.6.1 wrstuden }
661 1.3.6.1 wrstuden bpp = bp;
662 1.3.6.1 wrstuden bp = bp->next;
663 1.3.6.1 wrstuden if (bp == ap->freelist)
664 1.3.6.1 wrstuden break;
665 1.1 jtc }
666 1.1 jtc }
667 1.1 jtc }
668 1.3.6.1 wrstuden # endif /* DEBUG_ALLOC */
669 1.1 jtc
670 1.3.6.1 wrstuden # ifdef TEST_ALLOC
671 1.1 jtc
672 1.1 jtc Area a;
673 1.3.6.1 wrstuden FILE *myout;
674 1.1 jtc
675 1.3.6.1 wrstuden int
676 1.3.6.1 wrstuden main(int argc, char **argv)
677 1.3.6.1 wrstuden {
678 1.3.6.1 wrstuden char buf[1024];
679 1.3.6.1 wrstuden struct info {
680 1.3.6.1 wrstuden int size;
681 1.3.6.1 wrstuden void *value;
682 1.3.6.1 wrstuden };
683 1.3.6.1 wrstuden struct info info[1024 * 2];
684 1.3.6.1 wrstuden int size, ident;
685 1.3.6.1 wrstuden int lineno = 0;
686 1.1 jtc
687 1.3.6.1 wrstuden myout = stdout;
688 1.1 jtc ainit(&a);
689 1.3.6.1 wrstuden while (fgets(buf, sizeof(buf), stdin)) {
690 1.3.6.1 wrstuden lineno++;
691 1.3.6.1 wrstuden if (buf[0] == '\n' || buf[0] == '#')
692 1.3.6.1 wrstuden continue;
693 1.3.6.1 wrstuden if (sscanf(buf, " alloc %d = i%d", &size, &ident) == 2) {
694 1.3.6.1 wrstuden if (ident < 0 || ident > NELEM(info)) {
695 1.3.6.1 wrstuden fprintf(stderr, "bad ident (%d) on line %d\n",
696 1.3.6.1 wrstuden ident, lineno);
697 1.3.6.1 wrstuden exit(1);
698 1.3.6.1 wrstuden }
699 1.3.6.1 wrstuden info[ident].value = alloc(info[ident].size = size, &a);
700 1.3.6.1 wrstuden printf("%p = alloc(%d) [%d,i%d]\n",
701 1.3.6.1 wrstuden info[ident].value, info[ident].size,
702 1.3.6.1 wrstuden lineno, ident);
703 1.3.6.1 wrstuden memset(info[ident].value, 1, size);
704 1.3.6.1 wrstuden continue;
705 1.3.6.1 wrstuden }
706 1.3.6.1 wrstuden if (sscanf(buf, " afree i%d", &ident) == 1) {
707 1.3.6.1 wrstuden if (ident < 0 || ident > NELEM(info)) {
708 1.3.6.1 wrstuden fprintf(stderr, "bad ident (%d) on line %d\n",
709 1.3.6.1 wrstuden ident, lineno);
710 1.3.6.1 wrstuden exit(1);
711 1.3.6.1 wrstuden }
712 1.3.6.1 wrstuden afree(info[ident].value, &a);
713 1.3.6.1 wrstuden printf("afree(%p) [%d,i%d]\n", info[ident].value,
714 1.3.6.1 wrstuden lineno, ident);
715 1.3.6.1 wrstuden continue;
716 1.3.6.1 wrstuden }
717 1.3.6.1 wrstuden if (sscanf(buf, " aresize i%d , %d", &ident, &size) == 2) {
718 1.3.6.1 wrstuden void *value;
719 1.3.6.1 wrstuden if (ident < 0 || ident > NELEM(info)) {
720 1.3.6.1 wrstuden fprintf(stderr, "bad ident (%d) on line %d\n",
721 1.3.6.1 wrstuden ident, lineno);
722 1.3.6.1 wrstuden exit(1);
723 1.3.6.1 wrstuden }
724 1.3.6.1 wrstuden value = info[ident].value;
725 1.3.6.1 wrstuden info[ident].value = aresize(value,
726 1.3.6.1 wrstuden info[ident].size = size,
727 1.3.6.1 wrstuden &a);
728 1.3.6.1 wrstuden printf("%p = aresize(%p, %d) [%d,i%d]\n",
729 1.3.6.1 wrstuden info[ident].value, value, info[ident].size,
730 1.3.6.1 wrstuden lineno, ident);
731 1.3.6.1 wrstuden memset(info[ident].value, 1, size);
732 1.3.6.1 wrstuden continue;
733 1.3.6.1 wrstuden }
734 1.3.6.1 wrstuden if (sscanf(buf, " aprint i%d , %d", &ident, &size) == 2) {
735 1.3.6.1 wrstuden if (ident < 0 || ident > NELEM(info)) {
736 1.3.6.1 wrstuden fprintf(stderr, "bad ident (%d) on line %d\n",
737 1.3.6.1 wrstuden ident, lineno);
738 1.3.6.1 wrstuden exit(1);
739 1.3.6.1 wrstuden }
740 1.3.6.1 wrstuden printf("aprint(%p, %d) [%d,i%d]\n",
741 1.3.6.1 wrstuden info[ident].value, size, lineno, ident);
742 1.3.6.1 wrstuden aprint(&a, info[ident].value, size);
743 1.3.6.1 wrstuden continue;
744 1.3.6.1 wrstuden }
745 1.3.6.1 wrstuden if (sscanf(buf, " aprint %d", &ident) == 1) {
746 1.3.6.1 wrstuden if (ident < 0 || ident > NELEM(info)) {
747 1.3.6.1 wrstuden fprintf(stderr, "bad ident (%d) on line %d\n",
748 1.3.6.1 wrstuden ident, lineno);
749 1.3.6.1 wrstuden exit(1);
750 1.3.6.1 wrstuden }
751 1.3.6.1 wrstuden printf("aprint(0, 0) [%d]\n", lineno);
752 1.3.6.1 wrstuden aprint(&a, 0, 0);
753 1.3.6.1 wrstuden continue;
754 1.3.6.1 wrstuden }
755 1.3.6.1 wrstuden if (sscanf(buf, " afreeall %d", &ident) == 1) {
756 1.3.6.1 wrstuden printf("afreeall() [%d]\n", lineno);
757 1.3.6.1 wrstuden afreeall(&a);
758 1.3.6.1 wrstuden memset(info, 0, sizeof(info));
759 1.3.6.1 wrstuden continue;
760 1.3.6.1 wrstuden }
761 1.3.6.1 wrstuden fprintf(stderr, "unrecognized line (line %d)\n",
762 1.3.6.1 wrstuden lineno);
763 1.3.6.1 wrstuden exit(1);
764 1.3.6.1 wrstuden }
765 1.1 jtc return 0;
766 1.1 jtc }
767 1.1 jtc
768 1.3.6.1 wrstuden void
769 1.3.6.1 wrstuden aerror(Area *ap, const char *msg)
770 1.3.6.1 wrstuden {
771 1.3.6.1 wrstuden printf("aerror: %s\n", msg);
772 1.3.6.1 wrstuden fflush(stdout);
773 1.1 jtc abort();
774 1.1 jtc }
775 1.1 jtc
776 1.3.6.1 wrstuden # endif /* TEST_ALLOC */
777 1.1 jtc
778 1.3.6.1 wrstuden #endif /* MEM_DEBUG */
779