Fix an amazing number of typos & malformed sentences reported by Detlef
[python/dscho.git] / Mac / mwerks / malloc / malloc.c
blob7d0fb6c6fe4119a200e5438627050a23b53a58fc
1 /*
2 * Attempt at a memory allocator for the Mac, Jack Jansen, CWI, 1995-1997.
4 * Code adapted from BSD malloc, which is:
6 * Copyright (c) 1983 Regents of the University of California.
7 * All rights reserved.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by the University of
20 * California, Berkeley and its contributors.
21 * 4. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
38 #if defined(LIBC_SCCS) && !defined(lint)
39 /*static char *sccsid = "from: @(#)malloc.c 5.11 (Berkeley) 2/23/91";*/
40 static char *rcsid = "$Id$";
41 #endif /* LIBC_SCCS and not lint */
44 * malloc.c (Caltech) 2/21/82
45 * Chris Kingsley, kingsley@cit-20. Modified by Jack Jansen, CWI.
47 * This is a very fast storage allocator. It allocates blocks of a small
48 * number of different sizes, and keeps free lists of each size. Blocks that
49 * don't exactly fit are passed up to the next larger size.
51 * Blocks over a certain size are directly allocated by calling NewPtr.
55 #ifdef USE_MALLOC_DEBUG
56 /* You may also selectively enable some of these (but some are interdependent) */
57 #define DEBUG
58 #define DEBUG2
59 #define MSTATS
60 #define RCHECK
61 #define VCHECK
62 #endif /* USE_MALLOC_DEBUG */
64 /*
65 * Set the next define if you want to return memory that is aligned to 32-byte
66 * boundaries. This allows 604 (and, to a lesser extent, any PPC) programs to
67 * make better use of the L1 cache.
69 /* #define USE_CACHE_ALIGNED 8 /* The alignment (in 4-byte words) */
71 typedef unsigned char u_char;
72 typedef unsigned long u_long;
73 typedef unsigned int u_int;
74 typedef unsigned short u_short;
75 typedef u_long caddr_t;
77 #include <Memory.h>
78 #include <stdlib.h>
79 #include <string.h>
81 #define NULL 0
83 static void morecore();
86 * The overhead on a block is at least 4 bytes. When free, this space
87 * contains a pointer to the next free block, and the bottom two bits must
88 * be zero. When in use, the first byte is set to MAGIC, and the second
89 * byte is the size index. The remaining bytes are for alignment.
90 * If range checking is enabled then a second word holds the size of the
91 * requested block, less 1, rounded up to a multiple of sizeof(RMAGIC).
92 * The order of elements is critical: ov_magic must overlay the low order
93 * bits of ov_next, and ov_magic can not be a valid ov_next bit pattern.
95 union overhead {
96 union overhead *ov_next; /* when free */
97 struct {
98 u_char ovu_magic0; /* magic number */
99 u_char ovu_index; /* bucket # */
100 u_char ovu_unused; /* unused */
101 u_char ovu_magic1; /* other magic number */
102 #ifdef RCHECK
103 u_short ovu_rmagic; /* range magic number */
104 u_long ovu_size; /* actual block size */
105 #endif
106 } ovu;
107 #define ov_magic0 ovu.ovu_magic0
108 #define ov_magic1 ovu.ovu_magic1
109 #define ov_index ovu.ovu_index
110 #define ov_rmagic ovu.ovu_rmagic
111 #define ov_size ovu.ovu_size
112 #ifdef USE_CACHE_ALIGNED
113 struct cachealigner {
114 u_long ovalign[USE_CACHE_ALIGNED];
115 } ovu_aligner;
116 #endif /* USE_CACHE_ALIGN */
119 #define MAGIC 0xef /* magic # on accounting info */
120 #define RMAGIC 0x5555 /* magic # on range info */
122 #ifdef RCHECK
123 #define RSLOP sizeof (u_short)
124 #else
125 #define RSLOP 0
126 #endif
128 #define OVERHEAD (sizeof(union overhead) + RSLOP)
131 * nextf[i] is the pointer to the next free block of size 2^(i+3). The
132 * smallest allocatable block is 8 bytes. The overhead information
133 * precedes the data area returned to the user.
135 #define NBUCKETS 11
136 #define MAXMALLOC (1<<(NBUCKETS+2))
137 static union overhead *nextf[NBUCKETS];
139 #ifdef MSTATS
141 * nmalloc[i] is the difference between the number of mallocs and frees
142 * for a given block size.
144 static u_int nmalloc[NBUCKETS+1];
145 #include <stdio.h>
146 #endif
148 #if defined(DEBUG) || defined(RCHECK) || defined(DEBUG2)
149 #define ASSERT(p) if (!(p)) botch(# p)
150 #include <stdio.h>
151 static
152 botch(s)
153 char *s;
155 fprintf(stderr, "\r\nmalloc assertion botched: %s\r\n", s);
156 (void) fflush(stderr); /* just in case user buffered it */
157 abort();
159 #else
160 #define ASSERT(p)
161 #endif
163 void *
164 malloc(nbytes)
165 size_t nbytes;
167 register union overhead *op;
168 register long bucket;
169 register unsigned amt;
172 ** First the simple case: we simple allocate big blocks directly
174 if ( nbytes + OVERHEAD >= MAXMALLOC ) {
175 op = (union overhead *)NewPtr(nbytes+OVERHEAD);
176 if ( op == NULL )
177 return NULL;
178 op->ov_magic0 = op->ov_magic1 = MAGIC;
179 op->ov_index = 0xff;
180 #ifdef MSTATS
181 nmalloc[NBUCKETS]++;
182 #endif
183 #ifdef RCHECK
185 * Record allocated size of block and
186 * bound space with magic numbers.
188 op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1);
189 op->ov_rmagic = RMAGIC;
190 *(u_short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC;
191 #endif
192 return (void *)(op+1);
195 * Convert amount of memory requested into closest block size
196 * stored in hash buckets which satisfies request.
197 * Account for space used per block for accounting.
199 #ifndef RCHECK
200 amt = 8; /* size of first bucket */
201 bucket = 0;
202 #else
203 amt = 16; /* size of first bucket */
204 bucket = 1;
205 #endif
206 while (nbytes + OVERHEAD > amt) {
207 amt <<= 1;
208 if (amt == 0)
209 return (NULL);
210 bucket++;
212 #ifdef DEBUG2
213 ASSERT( bucket < NBUCKETS );
214 #endif
216 * If nothing in hash bucket right now,
217 * request more memory from the system.
219 if ((op = nextf[bucket]) == NULL) {
220 morecore(bucket);
221 if ((op = nextf[bucket]) == NULL)
222 return (NULL);
224 /* remove from linked list */
225 nextf[bucket] = op->ov_next;
226 op->ov_magic0 = op->ov_magic1 = MAGIC;
227 op->ov_index = bucket;
228 #ifdef MSTATS
229 nmalloc[bucket]++;
230 #endif
231 #ifdef RCHECK
233 * Record allocated size of block and
234 * bound space with magic numbers.
236 op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1);
237 op->ov_rmagic = RMAGIC;
238 *(u_short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC;
239 #endif
240 #ifdef VCHECK
241 memset((char *)(op+1), 0x41, nbytes);
242 #endif
243 return ((char *)(op + 1));
247 * Allocate more memory to the indicated bucket.
249 static void
250 morecore(bucket)
251 int bucket;
253 register union overhead *op;
254 register long sz; /* size of desired block */
255 long amt; /* amount to allocate */
256 int nblks; /* how many blocks we get */
259 * sbrk_size <= 0 only for big, FLUFFY, requests (about
260 * 2^30 bytes on a VAX, I think) or for a negative arg.
262 sz = 1 << (bucket + 3);
263 #ifdef DEBUG2
264 ASSERT(sz > 0);
265 #endif
266 amt = MAXMALLOC;
267 nblks = amt / sz;
268 #ifdef DEBUG2
269 ASSERT(nblks*sz == amt);
270 #endif
271 #ifdef USE_CACHE_ALIGNED
272 op = (union overhead *)NewPtr(amt+4*USE_CACHE_ALIGNED);
273 #else
274 op = (union overhead *)NewPtr(amt);
275 #endif
276 /* no more room! */
277 if (op == NULL)
278 return;
279 #ifdef USE_CACHE_ALIGNED
280 #define ALIGN_MASK (4*USE_CACHE_ALIGNED-1)
281 while ((long)op & ALIGN_MASK )
282 op = (union overhead *)((long)op+1);
283 #endif /* USE_CACHE_ALIGNED */
285 * Add new memory allocated to that on
286 * free list for this hash bucket.
288 nextf[bucket] = op;
289 while (--nblks > 0) {
290 op->ov_next = (union overhead *)((caddr_t)op + sz);
291 op = (union overhead *)((caddr_t)op + sz);
293 op->ov_next = (union overhead *)NULL;
296 void
297 free(cp)
298 void *cp;
300 register long size;
301 register union overhead *op;
303 if (cp == NULL)
304 return;
305 op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
306 #ifdef DEBUG
307 ASSERT(op->ov_magic0 == MAGIC); /* make sure it was in use */
308 ASSERT(op->ov_magic1 == MAGIC);
309 #else
310 if (op->ov_magic0 != MAGIC || op->ov_magic1 != MAGIC)
311 return; /* sanity */
312 #endif
313 #ifdef RCHECK
314 ASSERT(op->ov_rmagic == RMAGIC);
315 ASSERT(*(u_short *)((caddr_t)(op + 1) + op->ov_size) == RMAGIC);
316 #endif
317 #ifdef VCHECK
318 memset(cp, 43, op->ov_size);
319 #endif
320 size = op->ov_index;
321 if ( size == 0xff ) {
322 #ifdef MSTATS
323 nmalloc[NBUCKETS]--;
324 #endif
325 DisposePtr((Ptr)op);
326 return;
328 ASSERT(size < NBUCKETS);
329 op->ov_next = nextf[size]; /* also clobbers ov_magic */
330 nextf[size] = op;
331 #ifdef MSTATS
332 nmalloc[size]--;
333 #endif
336 void *
337 realloc(cp, nbytes)
338 void *cp;
339 size_t nbytes;
341 int i;
342 union overhead *op;
343 int expensive;
344 u_long maxsize;
346 if (cp == NULL)
347 return (malloc(nbytes));
348 op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
349 #ifdef DEBUG
350 ASSERT(op->ov_magic0 == MAGIC); /* make sure it was in use */
351 ASSERT(op->ov_magic1 == MAGIC);
352 #else
353 if (op->ov_magic0 != MAGIC || op->ov_magic1 != MAGIC)
354 return NULL; /* sanity */
355 #endif
356 #ifdef RCHECK
357 ASSERT(op->ov_rmagic == RMAGIC);
358 ASSERT(*(u_short *)((caddr_t)(op + 1) + op->ov_size) == RMAGIC);
359 #endif
360 i = op->ov_index;
362 ** First the malloc/copy cases
364 expensive = 0;
365 if ( i == 0xff ) {
366 /* Big block. See if it has to stay big */
367 if (nbytes+OVERHEAD > MAXMALLOC) {
368 /* Yup, try to resize it first */
369 SetPtrSize((Ptr)op, nbytes+OVERHEAD);
370 if ( MemError() == 0 ) {
371 #ifdef RCHECK
372 op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1);
373 *(u_short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC;
374 #endif
375 return cp;
377 /* Nope, failed. Take the long way */
379 maxsize = GetPtrSize((Ptr)op);
380 expensive = 1;
381 } else {
382 maxsize = 1 << (i+3);
383 if ( nbytes + OVERHEAD > maxsize )
384 expensive = 1;
385 else if ( i > 0 && nbytes + OVERHEAD < (maxsize/2) )
386 expensive = 1;
388 if ( expensive ) {
389 void *newp;
391 newp = malloc(nbytes);
392 if ( newp == NULL ) {
393 return NULL;
395 maxsize -= OVERHEAD;
396 if ( maxsize < nbytes )
397 nbytes = maxsize;
398 memcpy(newp, cp, nbytes);
399 free(cp);
400 return newp;
403 ** Ok, we don't have to copy, it fits as-is
405 #ifdef RCHECK
406 op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1);
407 *(u_short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC;
408 #endif
409 return(cp);
413 #ifdef MSTATS
415 * mstats - print out statistics about malloc
417 * Prints two lines of numbers, one showing the length of the free list
418 * for each size category, the second showing the number of mallocs -
419 * frees for each size category.
421 mstats(s)
422 char *s;
424 register int i, j;
425 register union overhead *p;
426 int totfree = 0,
427 totused = 0;
429 fprintf(stderr, "Memory allocation statistics %s\nfree:\t", s);
430 for (i = 0; i < NBUCKETS; i++) {
431 for (j = 0, p = nextf[i]; p; p = p->ov_next, j++)
433 fprintf(stderr, " %d", j);
434 totfree += j * (1 << (i + 3));
436 fprintf(stderr, "\nused:\t");
437 for (i = 0; i < NBUCKETS; i++) {
438 fprintf(stderr, " %d", nmalloc[i]);
439 totused += nmalloc[i] * (1 << (i + 3));
441 fprintf(stderr, "\n\tTotal small in use: %d, total free: %d\n",
442 totused, totfree);
443 fprintf(stderr, "\n\tNumber of big (>%d) blocks in use: %d\n", MAXMALLOC, nmalloc[NBUCKETS]);
445 #endif