ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/cms/source/ihost/libukcprog/alloc.c
Revision: 1.1
Committed: Fri Mar 8 14:37:29 2002 UTC (22 years, 8 months ago) by tdb
Content type: text/plain
Branch: MAIN
CVS Tags: IHOST_1_5_3, IHOST_1_5_2, IHOST_1_5_1, IHOST_1_5, IHOST_1_0_RC1
Log Message:
I'm not usually up for putting third party sources in here, but in this
case I'll make an exception. This is ukcprog, a set of useful C functions
which the ihost plugins Pete's writing uses. It's got a pretty free license
too. I've munged the Makefile around, as all it needs to do now is make the
library, not install anything. The idea is to statically compile the other
programs against this library, making the final binary independent of this
code etc.

File Contents

# Content
1 /* alloc_pool.c - routines for allocating memory from tagged pools */
2
3 /* Copyright 1991 Mark Russell, University of Kent at Canterbury.
4 *
5 * You can do what you like with this source code as long as
6 * you don't try to make money out of it and you include an
7 * unaltered copy of this message (including the copyright).
8 */
9
10 char ukcprog_alloc_sccsid[] = "$Id: alloc.c,v 1.10 1993/10/25 11:44:23 mtr Exp $ UKC";
11
12 #include <stdio.h> /* for NULL - grrr */
13 #include <stdlib.h>
14 #include <string.h>
15 #ifndef __STDC__
16 #include <memory.h>
17 #endif
18
19 #include "ukcprog.h"
20
21 /* This is a conservative guess at the per-request malloc overhead in
22 * bytes. Nothing breaks if this is wrong.
23 */
24 #define MALLOC_OVERHEAD 24
25
26 /* When we run out a space in an alloc pool we add another block.
27 * We add small blocks (SBLOCKSIZE bytes each) for the first NSMALLBLOCKS
28 * requests, then switch switch to large (BLOCKSIZE) ones.
29 *
30 * The intention is that we don't gobble large amounts of memory for
31 * a small alloc pool, but that we are reasonablty efficient for
32 * one that's continually growing.
33 *
34 * Currently, we go slowly (256 bytes a go) for the first 8K, then
35 * fast (4K a go).
36 */
37 #define NSMALLBLOCKS 32
38
39 /* Size of the first block for an alloc pool (requested when the alloc
40 * pool is created) and for the subsequent NSMALLBLOCKS blocks.
41 */
42 #define SBLOCKSIZE (256 - sizeof(alloc_pool_t) - MALLOC_OVERHEAD)
43
44 /* Size of the requested for an alloc pool after the first NSMALLBLOCKS
45 * block additions.
46 *
47 * Try to make the malloc request size a bit less than a power of two
48 * to compensate for brain-damaged mallocs that add overhead then round
49 * up to a power of two.
50 */
51 #define BLOCKSIZE (4096 - sizeof(ablock_t) - MALLOC_OVERHEAD)
52
53 /* Maximum alignment requirements for all types *including* float and double.
54 */
55 #define ALIGN sizeof(double)
56
57 typedef struct ablockst {
58 union {
59 double align;
60 struct ablock {
61 char *abu_buf;
62 char *abu_pos;
63 char *abu_end;
64 size_t abu_size;
65 struct ablockst *abu_next;
66 } a;
67 } u;
68 } ablock_t;
69
70 #define ab_buf u.a.abu_buf
71 #define ab_pos u.a.abu_pos
72 #define ab_end u.a.abu_end
73 #define ab_size u.a.abu_size
74 #define ab_next u.a.abu_next
75
76 struct alloc_pool_s {
77 ablock_t *ap_ablock;
78 ablock_t *ap_freelist;
79 int ap_nblocks;
80 bool ap_debug;
81 ablock_t ap_first_ablock;
82 };
83
84 struct alloc_mark_s {
85 alloc_pool_t *am_apool;
86 ablock_t *am_ablock;
87 char *am_pos;
88 char *am_end;
89 };
90
91 static ablock_t *push_ablock PROTO((alloc_pool_t *ap, ablock_t *ab, unsigned size));
92 static ablock_t *find_ab PROTO((alloc_pool_t *ap, unsigned size));
93 static void reset_ablocks PROTO((alloc_pool_t *ap, ablock_t *limab));
94
95 /* The default debug flag for a new alloc_pool. When the debug flag
96 * is TRUE, we initialise memory to garbage, and set it to (different)
97 * garbage when free_alloc_pool is called.
98 */
99 static bool Default_debug_flag = TRUE;
100
101 bool
102 alloc_set_default_debug_flag(val)
103 bool val;
104 {
105 bool oldval;
106
107 oldval = Default_debug_flag;
108 Default_debug_flag = val;
109 return oldval;
110 }
111
112 bool
113 alloc_set_debug_flag(ap, val)
114 alloc_pool_t *ap;
115 bool val;
116 {
117 bool oldval;
118
119 oldval = ap->ap_debug;
120 ap->ap_debug = val;
121 return oldval;
122 }
123
124 /* Make a new alloc_pool(). We make an initial allocation of a small
125 * amount of memory, to make small alloc pool creation cheap (one malloc).
126 */
127 alloc_pool_t *
128 alloc_create_pool()
129 {
130 alloc_pool_t *ap;
131
132 ap = (alloc_pool_t *)e_malloc(sizeof(alloc_pool_t) + SBLOCKSIZE);
133 ap->ap_ablock = NULL;
134 ap->ap_freelist = NULL;
135 ap->ap_nblocks = 0;
136 ap->ap_debug = Default_debug_flag;
137 push_ablock(ap, &ap->ap_first_ablock, SBLOCKSIZE);
138
139 return ap;
140 }
141
142 static void
143 reset_ablocks(ap, limab)
144 alloc_pool_t *ap;
145 ablock_t *limab;
146 {
147 ablock_t *ab, *next;
148 bool debug;
149
150 debug = ap->ap_debug;
151 for (ab = ap->ap_ablock; ab != limab; ab = next) {
152 next = ab->ab_next;
153 if (debug)
154 memset(ab->ab_buf, 0x42, ab->ab_size);
155 ab->ab_pos = ab->ab_buf;
156 ab->ab_end = ab->ab_pos + ab->ab_size;
157 ab->ab_next = ap->ap_freelist;
158 ap->ap_freelist = ab;
159 }
160 }
161
162 void
163 alloc_reset_pool(ap)
164 alloc_pool_t *ap;
165 {
166 ablock_t *ab;
167
168 ab = &ap->ap_first_ablock;
169
170 reset_ablocks(ap, ab);
171
172 if (ap->ap_debug)
173 memset(ab->ab_buf, 0x42, ab->ab_size);
174 ab->ab_pos = ab->ab_buf;
175 ab->ab_end = ab->ab_pos + ab->ab_size;
176
177 ap->ap_ablock = ab;
178 }
179
180 void
181 alloc_free_pool(ap)
182 alloc_pool_t *ap;
183 {
184 ablock_t *ab, *next;
185 bool debug;
186
187 debug = ap->ap_debug;
188
189 /* The odd form of the loop here is because we want to overwrite
190 * all blocks with garbage (if debug is set), but we don't want
191 * to free the last block in the chain, which is allocated as part
192 * of the header block.
193 */
194 ab = ap->ap_ablock;
195 for (;;) {
196 next = ab->ab_next;
197 if (debug)
198 memset(ab->ab_buf, 0x42, ab->ab_size);
199 if (next == NULL)
200 break;
201 free((char *)ab);
202 ab = next;
203 }
204
205 free((char *)ap);
206 }
207
208 static ablock_t *
209 push_ablock(ap, ab, size)
210 alloc_pool_t *ap;
211 ablock_t *ab;
212 unsigned size;
213 {
214 ab->ab_buf = ab->ab_pos = (char *)&ab[1];
215 ab->ab_end = ab->ab_buf + size;
216 ab->ab_size = size;
217 ab->ab_next = ap->ap_ablock;
218 ap->ap_ablock = ab;
219
220 if (ap->ap_debug)
221 memset(ab->ab_buf, 0x53, (size_t)size);
222
223 return ab;
224 }
225
226 /* Find an ablock with at least nbytes free. If the block at the
227 * head of the free list is big enough, use that. Otherwise malloc
228 * a new ablock and push it on the chain.
229 */
230 static ablock_t *
231 find_ab(ap, size)
232 alloc_pool_t *ap;
233 unsigned size;
234 {
235 ablock_t *ab;
236
237 if (ap->ap_freelist != NULL && ap->ap_freelist->ab_size >= size) {
238 ab = ap->ap_freelist;
239 ap->ap_freelist = ap->ap_freelist->ab_next;
240 ab->ab_next = ap->ap_ablock;
241 ap->ap_ablock = ab;
242 }
243 else {
244 voidptr buf;
245 unsigned blocksize;
246
247 blocksize = (ap->ap_nblocks < NSMALLBLOCKS) ? SBLOCKSIZE : BLOCKSIZE;
248 if (size < blocksize)
249 size = blocksize;
250 if ((buf = malloc((size_t)(sizeof(ablock_t) + size))) == NULL)
251 return NULL;
252 ab = push_ablock(ap, (ablock_t *)buf, size);
253 ++ap->ap_nblocks;
254 }
255 return ab;
256 }
257
258 /* Allocate nbytes from alloc pool ap. This interface never
259 * returns NULL - if memory runs out we panic.
260 */
261 voidptr
262 alloc(ap, nbytes)
263 alloc_pool_t *ap;
264 size_t nbytes;
265 {
266 ablock_t *ab;
267 int over;
268 char *ptr;
269
270 over = nbytes % ALIGN;
271 if (over != 0)
272 nbytes += ALIGN - over;
273
274 ab = ap->ap_ablock;
275
276 if (nbytes > ab->ab_end - ab->ab_pos) {
277 ab = find_ab(ap, (unsigned)nbytes);
278 if (ab == NULL)
279 panic("out of memory in alloc");
280 }
281
282 ptr = ab->ab_pos;
283 ab->ab_pos += nbytes;
284
285 return ptr;
286 }
287
288 /* Like alloc, but return NULL if we can't satisfy the request.
289 */
290 voidptr
291 alloc_ck(ap, nbytes)
292 alloc_pool_t *ap;
293 size_t nbytes;
294 {
295 ablock_t *ab;
296 int over;
297 char *ptr;
298
299 over = nbytes % ALIGN;
300 if (over != 0)
301 nbytes += ALIGN - over;
302
303 ab = ap->ap_ablock;
304
305 if (nbytes > ab->ab_end - ab->ab_pos) {
306 ab = find_ab(ap, nbytes);
307 if (ab == NULL)
308 return NULL;
309 }
310
311 ptr = ab->ab_pos;
312 ab->ab_pos += nbytes;
313
314 return ptr;
315 }
316
317 alloc_mark_t *
318 alloc_mark(ap)
319 alloc_pool_t *ap;
320 {
321 alloc_mark_t *am;
322 ablock_t *save_ab;
323 char *save_pos, *save_end;
324
325 save_ab = ap->ap_ablock;
326 save_pos = save_ab->ab_pos;
327 save_end = save_ab->ab_end;
328
329 am = (alloc_mark_t *)alloc(ap, sizeof(alloc_mark_t));
330 am->am_apool = ap;
331 am->am_ablock = save_ab;
332 am->am_pos = save_pos;
333 am->am_end = save_end;
334
335 return am;
336 }
337
338 void
339 alloc_release(ap, am)
340 alloc_pool_t *ap;
341 alloc_mark_t *am;
342 {
343 ablock_t *ab;
344 alloc_mark_t mark;
345
346 if (am->am_apool != ap)
347 panic("id botch in ar");
348
349 /* If debug is set, we are about to step on the store that
350 * the mark was allocated from, so save it.
351 */
352 mark = *am;
353 ab = mark.am_ablock;
354
355 reset_ablocks(ap, ab);
356
357 if (ap->ap_debug) {
358 memset(mark.am_pos, 0x42, (size_t)(ab->ab_pos - mark.am_pos));
359 memset(ab->ab_end, 0x42, (size_t)(mark.am_end - ab->ab_end));
360 }
361 else {
362 /* Make sure the application can't use this mark again.
363 */
364 am->am_apool = NULL;
365 }
366
367 ab->ab_pos = mark.am_pos;
368 ab->ab_end = mark.am_end;
369 ap->ap_ablock = ab;
370 }
371
372 /* Like alloc(), except that the result is assumed not to need alignment.
373 * We work from the other end of the pool than alloc so hopefully all the
374 * string requests will be packed together with no alignment holes.
375 *
376 * We never return NULL - if we can't fulfill the request we panic.
377 */
378 char *
379 allocstr(ap, nbytes)
380 alloc_pool_t *ap;
381 size_t nbytes;
382 {
383 ablock_t *ab;
384
385 ab = ap->ap_ablock;
386
387 if (nbytes > ab->ab_end - ab->ab_pos) {
388 ab = find_ab(ap, (unsigned)nbytes);
389 if (ab == NULL)
390 panic("out of memory in allocstr");
391 }
392
393 return ab->ab_end -= nbytes;
394 }
395
396 char *
397 allocstr_ck(ap, nbytes)
398 alloc_pool_t *ap;
399 size_t nbytes;
400 {
401 ablock_t *ab;
402
403 ab = ap->ap_ablock;
404
405 /* We cast nbytes to unsigned to catch negative values: they
406 * turn into huge positive values which get caught by e_malloc().
407 */
408 if ((unsigned)nbytes > ab->ab_end - ab->ab_pos) {
409 ab = find_ab(ap, (unsigned)nbytes);
410 if (ab == NULL)
411 return NULL;
412 }
413
414 return ab->ab_end -= nbytes;
415 }
416
417 char *
418 alloc_strdup(ap, s)
419 alloc_pool_t *ap;
420 const char *s;
421 {
422 size_t nbytes;
423
424 nbytes = strlen(s) + 1;
425 return memcpy(allocstr(ap, nbytes), s, nbytes);
426 }