perl 4.0 patch 19: (combined patch)
[p5sagit/p5-mst-13.2.git] / malloc.c
CommitLineData
45d8adaa 1/* $RCSfile: malloc.c,v $$Revision: 4.0.1.3 $$Date: 91/11/05 17:57:40 $
8d063cd8 2 *
3 * $Log: malloc.c,v $
45d8adaa 4 * Revision 4.0.1.3 91/11/05 17:57:40 lwall
5 * patch11: safe malloc code now integrated into Perl's malloc when possible
6 *
352d5a3a 7 * Revision 4.0.1.2 91/06/07 11:20:45 lwall
8 * patch4: many, many itty-bitty portability fixes
9 *
35c8bce7 10 * Revision 4.0.1.1 91/04/11 17:48:31 lwall
11 * patch1: Configure now figures out malloc ptr type
12 *
fe14fcc3 13 * Revision 4.0 91/03/20 01:28:52 lwall
14 * 4.0 baseline.
8d063cd8 15 *
16 */
17
18#ifndef lint
45d8adaa 19/*SUPPRESS 592*/
8d063cd8 20static char sccsid[] = "@(#)malloc.c 4.3 (Berkeley) 9/16/83";
8d063cd8 21
a687059c 22#ifdef DEBUGGING
8d063cd8 23#define RCHECK
a687059c 24#endif
8d063cd8 25/*
26 * malloc.c (Caltech) 2/21/82
27 * Chris Kingsley, kingsley@cit-20.
28 *
29 * This is a very fast storage allocator. It allocates blocks of a small
30 * number of different sizes, and keeps free lists of each size. Blocks that
31 * don't exactly fit are passed up to the next larger size. In this
32 * implementation, the available sizes are 2^n-4 (or 2^n-12) bytes long.
33 * This is designed for use in a program that uses vast quantities of memory,
34 * but bombs when it runs out.
35 */
36
135863df 37#include "EXTERN.h"
135863df 38#include "perl.h"
39
03a14243 40static findbucket(), morecore();
41
135863df 42/* I don't much care whether these are defined in sys/types.h--LAW */
43
44#define u_char unsigned char
45#define u_int unsigned int
46#define u_short unsigned short
8d063cd8 47
8d063cd8 48/*
49 * The overhead on a block is at least 4 bytes. When free, this space
50 * contains a pointer to the next free block, and the bottom two bits must
51 * be zero. When in use, the first byte is set to MAGIC, and the second
52 * byte is the size index. The remaining bytes are for alignment.
53 * If range checking is enabled and the size of the block fits
54 * in two bytes, then the top two bytes hold the size of the requested block
55 * plus the range checking words, and the header word MINUS ONE.
56 */
57union overhead {
58 union overhead *ov_next; /* when free */
c623bd54 59#if ALIGNBYTES > 4
60 double strut; /* alignment problems */
a687059c 61#endif
8d063cd8 62 struct {
63 u_char ovu_magic; /* magic number */
64 u_char ovu_index; /* bucket # */
65#ifdef RCHECK
66 u_short ovu_size; /* actual block size */
67 u_int ovu_rmagic; /* range magic number */
68#endif
69 } ovu;
70#define ov_magic ovu.ovu_magic
71#define ov_index ovu.ovu_index
72#define ov_size ovu.ovu_size
73#define ov_rmagic ovu.ovu_rmagic
74};
75
76#define MAGIC 0xff /* magic # on accounting info */
378cc40b 77#define OLDMAGIC 0x7f /* same after a free() */
8d063cd8 78#define RMAGIC 0x55555555 /* magic # on range info */
79#ifdef RCHECK
80#define RSLOP sizeof (u_int)
81#else
82#define RSLOP 0
83#endif
84
85/*
86 * nextf[i] is the pointer to the next free block of size 2^(i+3). The
87 * smallest allocatable block is 8 bytes. The overhead information
88 * precedes the data area returned to the user.
89 */
90#define NBUCKETS 30
91static union overhead *nextf[NBUCKETS];
92extern char *sbrk();
93
94#ifdef MSTATS
95/*
96 * nmalloc[i] is the difference between the number of mallocs and frees
97 * for a given block size.
98 */
99static u_int nmalloc[NBUCKETS];
100#include <stdio.h>
101#endif
102
103#ifdef debug
104#define ASSERT(p) if (!(p)) botch("p"); else
105static
106botch(s)
107 char *s;
108{
109
110 printf("assertion botched: %s\n", s);
111 abort();
112}
113#else
114#define ASSERT(p)
115#endif
116
45d8adaa 117#ifdef safemalloc
118static int an = 0;
119#endif
120
35c8bce7 121MALLOCPTRTYPE *
8d063cd8 122malloc(nbytes)
123 register unsigned nbytes;
124{
125 register union overhead *p;
126 register int bucket = 0;
127 register unsigned shiftr;
128
45d8adaa 129#ifdef safemalloc
130#ifdef DEBUGGING
131 int size = nbytes;
132#endif
133
134#ifdef MSDOS
135 if (nbytes > 0xffff) {
136 fprintf(stderr, "Allocation too large: %lx\n", nbytes);
137 exit(1);
138 }
139#endif /* MSDOS */
140#ifdef DEBUGGING
141 if ((long)nbytes < 0)
142 fatal("panic: malloc");
143#endif
144#endif /* safemalloc */
145
8d063cd8 146 /*
147 * Convert amount of memory requested into
148 * closest block size stored in hash buckets
149 * which satisfies request. Account for
150 * space used per block for accounting.
151 */
152 nbytes += sizeof (union overhead) + RSLOP;
153 nbytes = (nbytes + 3) &~ 3;
154 shiftr = (nbytes - 1) >> 2;
155 /* apart from this loop, this is O(1) */
156 while (shiftr >>= 1)
157 bucket++;
158 /*
159 * If nothing in hash bucket right now,
160 * request more memory from the system.
161 */
162 if (nextf[bucket] == NULL)
163 morecore(bucket);
45d8adaa 164 if ((p = (union overhead *)nextf[bucket]) == NULL) {
165#ifdef safemalloc
166 fputs("Out of memory!\n", stderr);
167 exit(1);
168#else
8d063cd8 169 return (NULL);
45d8adaa 170#endif
171 }
172
173#ifdef safemalloc
174#ifdef DEBUGGING
175# ifndef I286
176 if (debug & 128)
177 fprintf(stderr,"0x%x: (%05d) malloc %d bytes\n",p+1,an++,size);
178# else
179 if (debug & 128)
180 fprintf(stderr,"0x%lx: (%05d) malloc %d bytes\n",p+1,an++,size);
181# endif
182#endif
183#endif /* safemalloc */
184
8d063cd8 185 /* remove from linked list */
bf38876a 186#ifdef RCHECK
187 if (*((int*)p) & (sizeof(union overhead) - 1))
a687059c 188#ifndef I286
8d063cd8 189 fprintf(stderr,"Corrupt malloc ptr 0x%x at 0x%x\n",*((int*)p),p);
a687059c 190#else
191 fprintf(stderr,"Corrupt malloc ptr 0x%lx at 0x%lx\n",*((int*)p),p);
192#endif
bf38876a 193#endif
194 nextf[bucket] = p->ov_next;
8d063cd8 195 p->ov_magic = MAGIC;
196 p->ov_index= bucket;
197#ifdef MSTATS
198 nmalloc[bucket]++;
199#endif
200#ifdef RCHECK
201 /*
202 * Record allocated size of block and
203 * bound space with magic numbers.
204 */
205 if (nbytes <= 0x10000)
206 p->ov_size = nbytes - 1;
207 p->ov_rmagic = RMAGIC;
208 *((u_int *)((caddr_t)p + nbytes - RSLOP)) = RMAGIC;
209#endif
352d5a3a 210 return ((MALLOCPTRTYPE *)(p + 1));
8d063cd8 211}
212
213/*
214 * Allocate more memory to the indicated bucket.
215 */
216static
217morecore(bucket)
a687059c 218 register int bucket;
8d063cd8 219{
220 register union overhead *op;
221 register int rnu; /* 2^rnu bytes will be requested */
222 register int nblks; /* become nblks blocks of the desired size */
223 register int siz;
224
225 if (nextf[bucket])
226 return;
227 /*
228 * Insure memory is allocated
229 * on a page boundary. Should
230 * make getpageize call?
231 */
232 op = (union overhead *)sbrk(0);
a687059c 233#ifndef I286
8d063cd8 234 if ((int)op & 0x3ff)
a687059c 235 (void)sbrk(1024 - ((int)op & 0x3ff));
236#else
237 /* The sbrk(0) call on the I286 always returns the next segment */
238#endif
239
240#ifndef I286
8d063cd8 241 /* take 2k unless the block is bigger than that */
242 rnu = (bucket <= 8) ? 11 : bucket + 3;
a687059c 243#else
244 /* take 16k unless the block is bigger than that
245 (80286s like large segments!) */
246 rnu = (bucket <= 11) ? 14 : bucket + 3;
247#endif
8d063cd8 248 nblks = 1 << (rnu - (bucket + 3)); /* how many blocks to get */
249 if (rnu < bucket)
250 rnu = bucket;
251 op = (union overhead *)sbrk(1 << rnu);
252 /* no more room! */
253 if ((int)op == -1)
254 return;
255 /*
256 * Round up to minimum allocation size boundary
257 * and deduct from block count to reflect.
258 */
a687059c 259#ifndef I286
8d063cd8 260 if ((int)op & 7) {
261 op = (union overhead *)(((int)op + 8) &~ 7);
262 nblks--;
263 }
a687059c 264#else
265 /* Again, this should always be ok on an 80286 */
266#endif
8d063cd8 267 /*
268 * Add new memory allocated to that on
269 * free list for this hash bucket.
270 */
271 nextf[bucket] = op;
272 siz = 1 << (bucket + 3);
273 while (--nblks > 0) {
274 op->ov_next = (union overhead *)((caddr_t)op + siz);
275 op = (union overhead *)((caddr_t)op + siz);
276 }
277}
278
fe14fcc3 279void
352d5a3a 280free(mp)
281 MALLOCPTRTYPE *mp;
8d063cd8 282{
283 register int size;
284 register union overhead *op;
352d5a3a 285 char *cp = (char*)mp;
8d063cd8 286
45d8adaa 287#ifdef safemalloc
288#ifdef DEBUGGING
289# ifndef I286
290 if (debug & 128)
291 fprintf(stderr,"0x%x: (%05d) free\n",cp,an++);
292# else
293 if (debug & 128)
294 fprintf(stderr,"0x%lx: (%05d) free\n",cp,an++);
295# endif
296#endif
297#endif /* safemalloc */
298
8d063cd8 299 if (cp == NULL)
300 return;
301 op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
302#ifdef debug
303 ASSERT(op->ov_magic == MAGIC); /* make sure it was in use */
304#else
378cc40b 305 if (op->ov_magic != MAGIC) {
a687059c 306 warn("%s free() ignored",
378cc40b 307 op->ov_magic == OLDMAGIC ? "Duplicate" : "Bad");
8d063cd8 308 return; /* sanity */
378cc40b 309 }
310 op->ov_magic = OLDMAGIC;
8d063cd8 311#endif
312#ifdef RCHECK
313 ASSERT(op->ov_rmagic == RMAGIC);
314 if (op->ov_index <= 13)
315 ASSERT(*(u_int *)((caddr_t)op + op->ov_size + 1 - RSLOP) == RMAGIC);
316#endif
317 ASSERT(op->ov_index < NBUCKETS);
318 size = op->ov_index;
319 op->ov_next = nextf[size];
320 nextf[size] = op;
321#ifdef MSTATS
322 nmalloc[size]--;
323#endif
324}
325
326/*
327 * When a program attempts "storage compaction" as mentioned in the
328 * old malloc man page, it realloc's an already freed block. Usually
329 * this is the last block it freed; occasionally it might be farther
330 * back. We have to search all the free lists for the block in order
331 * to determine its bucket: 1st we make one pass thru the lists
332 * checking only the first block in each; if that fails we search
378cc40b 333 * ``reall_srchlen'' blocks in each list for a match (the variable
8d063cd8 334 * is extern so the caller can modify it). If that fails we just copy
335 * however many bytes was given to realloc() and hope it's not huge.
336 */
378cc40b 337int reall_srchlen = 4; /* 4 should be plenty, -1 =>'s whole list */
8d063cd8 338
35c8bce7 339MALLOCPTRTYPE *
352d5a3a 340realloc(mp, nbytes)
341 MALLOCPTRTYPE *mp;
8d063cd8 342 unsigned nbytes;
343{
344 register u_int onb;
345 union overhead *op;
346 char *res;
347 register int i;
348 int was_alloced = 0;
352d5a3a 349 char *cp = (char*)mp;
8d063cd8 350
45d8adaa 351#ifdef safemalloc
352#ifdef DEBUGGING
353 int size = nbytes;
354#endif
355
356#ifdef MSDOS
357 if (nbytes > 0xffff) {
358 fprintf(stderr, "Reallocation too large: %lx\n", size);
359 exit(1);
360 }
361#endif /* MSDOS */
362 if (!cp)
363 fatal("Null realloc");
364#ifdef DEBUGGING
365 if ((long)nbytes < 0)
366 fatal("panic: realloc");
367#endif
368#endif /* safemalloc */
369
8d063cd8 370 if (cp == NULL)
371 return (malloc(nbytes));
372 op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
373 if (op->ov_magic == MAGIC) {
374 was_alloced++;
375 i = op->ov_index;
376 } else {
377 /*
378 * Already free, doing "compaction".
379 *
380 * Search for the old block of memory on the
381 * free list. First, check the most common
382 * case (last element free'd), then (this failing)
378cc40b 383 * the last ``reall_srchlen'' items free'd.
8d063cd8 384 * If all lookups fail, then assume the size of
385 * the memory block being realloc'd is the
386 * smallest possible.
387 */
388 if ((i = findbucket(op, 1)) < 0 &&
378cc40b 389 (i = findbucket(op, reall_srchlen)) < 0)
8d063cd8 390 i = 0;
391 }
392 onb = (1 << (i + 3)) - sizeof (*op) - RSLOP;
393 /* avoid the copy if same size block */
394 if (was_alloced &&
a687059c 395 nbytes <= onb && nbytes > (onb >> 1) - sizeof(*op) - RSLOP) {
396#ifdef RCHECK
397 /*
398 * Record new allocated size of block and
399 * bound space with magic numbers.
400 */
401 if (op->ov_index <= 13) {
402 /*
403 * Convert amount of memory requested into
404 * closest block size stored in hash buckets
405 * which satisfies request. Account for
406 * space used per block for accounting.
407 */
408 nbytes += sizeof (union overhead) + RSLOP;
409 nbytes = (nbytes + 3) &~ 3;
410 op->ov_size = nbytes - 1;
411 *((u_int *)((caddr_t)op + nbytes - RSLOP)) = RMAGIC;
412 }
413#endif
45d8adaa 414 res = cp;
a687059c 415 }
45d8adaa 416 else {
417 if ((res = (char*)malloc(nbytes)) == NULL)
418 return (NULL);
419 if (cp != res) /* common optimization */
420 bcopy(cp, res, (int)(nbytes < onb ? nbytes : onb));
421 if (was_alloced)
422 free(cp);
423 }
424
425#ifdef safemalloc
426#ifdef DEBUGGING
427# ifndef I286
428 if (debug & 128) {
429 fprintf(stderr,"0x%x: (%05d) rfree\n",res,an++);
430 fprintf(stderr,"0x%x: (%05d) realloc %d bytes\n",res,an++,size);
431 }
432# else
433 if (debug & 128) {
434 fprintf(stderr,"0x%lx: (%05d) rfree\n",res,an++);
435 fprintf(stderr,"0x%lx: (%05d) realloc %d bytes\n",res,an++,size);
436 }
437# endif
438#endif
439#endif /* safemalloc */
352d5a3a 440 return ((MALLOCPTRTYPE*)res);
8d063cd8 441}
442
443/*
444 * Search ``srchlen'' elements of each free list for a block whose
445 * header starts at ``freep''. If srchlen is -1 search the whole list.
446 * Return bucket number, or -1 if not found.
447 */
448static
449findbucket(freep, srchlen)
450 union overhead *freep;
451 int srchlen;
452{
453 register union overhead *p;
454 register int i, j;
455
456 for (i = 0; i < NBUCKETS; i++) {
457 j = 0;
458 for (p = nextf[i]; p && j != srchlen; p = p->ov_next) {
459 if (p == freep)
460 return (i);
461 j++;
462 }
463 }
464 return (-1);
465}
466
467#ifdef MSTATS
468/*
469 * mstats - print out statistics about malloc
470 *
471 * Prints two lines of numbers, one showing the length of the free list
472 * for each size category, the second showing the number of mallocs -
473 * frees for each size category.
474 */
475mstats(s)
476 char *s;
477{
478 register int i, j;
479 register union overhead *p;
480 int totfree = 0,
481 totused = 0;
482
483 fprintf(stderr, "Memory allocation statistics %s\nfree:\t", s);
484 for (i = 0; i < NBUCKETS; i++) {
485 for (j = 0, p = nextf[i]; p; p = p->ov_next, j++)
486 ;
487 fprintf(stderr, " %d", j);
488 totfree += j * (1 << (i + 3));
489 }
490 fprintf(stderr, "\nused:\t");
491 for (i = 0; i < NBUCKETS; i++) {
492 fprintf(stderr, " %d", nmalloc[i]);
493 totused += nmalloc[i] * (1 << (i + 3));
494 }
495 fprintf(stderr, "\n\tTotal in use: %d, total free: %d\n",
496 totused, totfree);
497}
498#endif
a687059c 499#endif /* lint */