|
|
1.1 root 1: /*
2: * Copyright (c) 1983 Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms are permitted
6: * provided that: (1) source distributions retain this entire copyright
7: * notice and comment, and (2) distributions including binaries display
8: * the following acknowledgement: ``This product includes software
9: * developed by the University of California, Berkeley and its contributors''
10: * in the documentation or other materials provided with the distribution
11: * and in all advertising materials mentioning features or use of this
12: * software. Neither the name of the University nor the names of its
13: * contributors may be used to endorse or promote products derived
14: * from this software without specific prior written permission.
15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
16: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
17: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18: */
19:
20: #if defined(LIBC_SCCS) && !defined(lint)
21: static char sccsid[] = "@(#)malloc.c 5.9 (Berkeley) 6/1/90";
22: #endif /* LIBC_SCCS and not lint */
23:
24: /*
25: * malloc.c (Caltech) 2/21/82
26: * Chris Kingsley, kingsley@cit-20.
27: *
28: * This is a very fast storage allocator. It allocates blocks of a small
29: * number of different sizes, and keeps free lists of each size. Blocks that
30: * don't exactly fit are passed up to the next larger size. In this
31: * implementation, the available sizes are 2^n-4 (or 2^n-10) bytes long.
32: * This is designed for use in a virtual memory environment.
33: */
34:
35: #include <sys/types.h>
36:
37: #define NULL 0
38:
39: /*
40: * The overhead on a block is at least 4 bytes. When free, this space
41: * contains a pointer to the next free block, and the bottom two bits must
42: * be zero. When in use, the first byte is set to MAGIC, and the second
43: * byte is the size index. The remaining bytes are for alignment.
44: * If range checking is enabled then a second word holds the size of the
45: * requested block, less 1, rounded up to a multiple of sizeof(RMAGIC).
46: * The order of elements is critical: ov_magic must overlay the low order
47: * bits of ov_next, and ov_magic can not be a valid ov_next bit pattern.
48: */
49: union overhead {
50: union overhead *ov_next; /* when free */
51: struct {
52: u_char ovu_magic; /* magic number */
53: u_char ovu_index; /* bucket # */
54: #ifdef RCHECK
55: u_short ovu_rmagic; /* range magic number */
56: u_int ovu_size; /* actual block size */
57: #endif
58: } ovu;
59: #define ov_magic ovu.ovu_magic
60: #define ov_index ovu.ovu_index
61: #define ov_rmagic ovu.ovu_rmagic
62: #define ov_size ovu.ovu_size
63: };
64:
65: #define MAGIC 0xef /* magic # on accounting info */
66: #define RMAGIC 0x5555 /* magic # on range info */
67:
68: #ifdef RCHECK
69: #define RSLOP sizeof (u_short)
70: #else
71: #define RSLOP 0
72: #endif
73:
74: /*
75: * nextf[i] is the pointer to the next free block of size 2^(i+3). The
76: * smallest allocatable block is 8 bytes. The overhead information
77: * precedes the data area returned to the user.
78: */
79: #define NBUCKETS 30
80: static union overhead *nextf[NBUCKETS];
81: extern char *sbrk();
82:
83: static int pagesz; /* page size */
84: static int pagebucket; /* page size bucket */
85:
86: #ifdef MSTATS
87: /*
88: * nmalloc[i] is the difference between the number of mallocs and frees
89: * for a given block size.
90: */
91: static u_int nmalloc[NBUCKETS];
92: #include <stdio.h>
93: #endif
94:
95: #if defined(DEBUG) || defined(RCHECK)
96: #define ASSERT(p) if (!(p)) botch("p")
97: #include <stdio.h>
98: static
99: botch(s)
100: char *s;
101: {
102: fprintf(stderr, "\r\nassertion botched: %s\r\n", s);
103: (void) fflush(stderr); /* just in case user buffered it */
104: abort();
105: }
106: #else
107: #define ASSERT(p)
108: #endif
109:
110: char *
111: malloc(nbytes)
112: unsigned nbytes;
113: {
114: register union overhead *op;
115: register int bucket, n;
116: register unsigned amt;
117:
118: /*
119: * First time malloc is called, setup page size and
120: * align break pointer so all data will be page aligned.
121: */
122: if (pagesz == 0) {
123: pagesz = n = getpagesize();
124: op = (union overhead *)sbrk(0);
125: n = n - sizeof (*op) - ((int)op & (n - 1));
126: if (n < 0)
127: n += pagesz;
128: if (n) {
129: if (sbrk(n) == (char *)-1)
130: return (NULL);
131: }
132: bucket = 0;
133: amt = 8;
134: while (pagesz > amt) {
135: amt <<= 1;
136: bucket++;
137: }
138: pagebucket = bucket;
139: }
140: /*
141: * Convert amount of memory requested into closest block size
142: * stored in hash buckets which satisfies request.
143: * Account for space used per block for accounting.
144: */
145: if (nbytes <= (n = pagesz - sizeof (*op) - RSLOP)) {
146: #ifndef RCHECK
147: amt = 8; /* size of first bucket */
148: bucket = 0;
149: #else
150: amt = 16; /* size of first bucket */
151: bucket = 1;
152: #endif
153: n = -(sizeof (*op) + RSLOP);
154: } else {
155: amt = pagesz;
156: bucket = pagebucket;
157: }
158: while (nbytes > amt + n) {
159: amt <<= 1;
160: if (amt == 0)
161: return (NULL);
162: bucket++;
163: }
164: /*
165: * If nothing in hash bucket right now,
166: * request more memory from the system.
167: */
168: if ((op = nextf[bucket]) == NULL) {
169: morecore(bucket);
170: if ((op = nextf[bucket]) == NULL)
171: return (NULL);
172: }
173: /* remove from linked list */
174: nextf[bucket] = op->ov_next;
175: op->ov_magic = MAGIC;
176: op->ov_index = bucket;
177: #ifdef MSTATS
178: nmalloc[bucket]++;
179: #endif
180: #ifdef RCHECK
181: /*
182: * Record allocated size of block and
183: * bound space with magic numbers.
184: */
185: op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1);
186: op->ov_rmagic = RMAGIC;
187: *(u_short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC;
188: #endif
189: return ((char *)(op + 1));
190: }
191:
192: /*
193: * Allocate more memory to the indicated bucket.
194: */
195: morecore(bucket)
196: int bucket;
197: {
198: register union overhead *op;
199: register int sz; /* size of desired block */
200: int amt; /* amount to allocate */
201: int nblks; /* how many blocks we get */
202:
203: /*
204: * sbrk_size <= 0 only for big, FLUFFY, requests (about
205: * 2^30 bytes on a VAX, I think) or for a negative arg.
206: */
207: sz = 1 << (bucket + 3);
208: #ifdef DEBUG
209: ASSERT(sz > 0);
210: #else
211: if (sz <= 0)
212: return;
213: #endif
214: if (sz < pagesz) {
215: amt = pagesz;
216: nblks = amt / sz;
217: } else {
218: amt = sz + pagesz;
219: nblks = 1;
220: }
221: op = (union overhead *)sbrk(amt);
222: /* no more room! */
223: if ((int)op == -1)
224: return;
225: /*
226: * Add new memory allocated to that on
227: * free list for this hash bucket.
228: */
229: nextf[bucket] = op;
230: while (--nblks > 0) {
231: op->ov_next = (union overhead *)((caddr_t)op + sz);
232: op = (union overhead *)((caddr_t)op + sz);
233: }
234: }
235:
236: free(cp)
237: char *cp;
238: {
239: register int size;
240: register union overhead *op;
241:
242: if (cp == NULL)
243: return;
244: op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
245: #ifdef DEBUG
246: ASSERT(op->ov_magic == MAGIC); /* make sure it was in use */
247: #else
248: if (op->ov_magic != MAGIC)
249: return; /* sanity */
250: #endif
251: #ifdef RCHECK
252: ASSERT(op->ov_rmagic == RMAGIC);
253: ASSERT(*(u_short *)((caddr_t)(op + 1) + op->ov_size) == RMAGIC);
254: #endif
255: size = op->ov_index;
256: ASSERT(size < NBUCKETS);
257: op->ov_next = nextf[size]; /* also clobbers ov_magic */
258: nextf[size] = op;
259: #ifdef MSTATS
260: nmalloc[size]--;
261: #endif
262: }
263:
264: /*
265: * When a program attempts "storage compaction" as mentioned in the
266: * old malloc man page, it realloc's an already freed block. Usually
267: * this is the last block it freed; occasionally it might be farther
268: * back. We have to search all the free lists for the block in order
269: * to determine its bucket: 1st we make one pass thru the lists
270: * checking only the first block in each; if that fails we search
271: * ``realloc_srchlen'' blocks in each list for a match (the variable
272: * is extern so the caller can modify it). If that fails we just copy
273: * however many bytes was given to realloc() and hope it's not huge.
274: */
275: int realloc_srchlen = 4; /* 4 should be plenty, -1 =>'s whole list */
276:
277: char *
278: realloc(cp, nbytes)
279: char *cp;
280: unsigned nbytes;
281: {
282: register u_int onb;
283: register int i;
284: union overhead *op;
285: char *res;
286: int was_alloced = 0;
287:
288: if (cp == NULL)
289: return (malloc(nbytes));
290: op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
291: if (op->ov_magic == MAGIC) {
292: was_alloced++;
293: i = op->ov_index;
294: } else {
295: /*
296: * Already free, doing "compaction".
297: *
298: * Search for the old block of memory on the
299: * free list. First, check the most common
300: * case (last element free'd), then (this failing)
301: * the last ``realloc_srchlen'' items free'd.
302: * If all lookups fail, then assume the size of
303: * the memory block being realloc'd is the
304: * largest possible (so that all "nbytes" of new
305: * memory are copied into). Note that this could cause
306: * a memory fault if the old area was tiny, and the moon
307: * is gibbous. However, that is very unlikely.
308: */
309: if ((i = findbucket(op, 1)) < 0 &&
310: (i = findbucket(op, realloc_srchlen)) < 0)
311: i = NBUCKETS;
312: }
313: onb = 1 << (i + 3);
314: if (onb < pagesz)
315: onb -= sizeof (*op) + RSLOP;
316: else
317: onb += pagesz - sizeof (*op) - RSLOP;
318: /* avoid the copy if same size block */
319: if (was_alloced) {
320: if (i) {
321: i = 1 << (i + 2);
322: if (i < pagesz)
323: i -= sizeof (*op) + RSLOP;
324: else
325: i += pagesz - sizeof (*op) - RSLOP;
326: }
327: if (nbytes <= onb && nbytes > i) {
328: #ifdef RCHECK
329: op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1);
330: *(u_short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC;
331: #endif
332: return(cp);
333: } else
334: free(cp);
335: }
336: if ((res = malloc(nbytes)) == NULL)
337: return (NULL);
338: if (cp != res) /* common optimization if "compacting" */
339: bcopy(cp, res, (nbytes < onb) ? nbytes : onb);
340: return (res);
341: }
342:
343: /*
344: * Search ``srchlen'' elements of each free list for a block whose
345: * header starts at ``freep''. If srchlen is -1 search the whole list.
346: * Return bucket number, or -1 if not found.
347: */
348: static
349: findbucket(freep, srchlen)
350: union overhead *freep;
351: int srchlen;
352: {
353: register union overhead *p;
354: register int i, j;
355:
356: for (i = 0; i < NBUCKETS; i++) {
357: j = 0;
358: for (p = nextf[i]; p && j != srchlen; p = p->ov_next) {
359: if (p == freep)
360: return (i);
361: j++;
362: }
363: }
364: return (-1);
365: }
366:
367: #ifdef MSTATS
368: /*
369: * mstats - print out statistics about malloc
370: *
371: * Prints two lines of numbers, one showing the length of the free list
372: * for each size category, the second showing the number of mallocs -
373: * frees for each size category.
374: */
375: mstats(s)
376: char *s;
377: {
378: register int i, j;
379: register union overhead *p;
380: int totfree = 0,
381: totused = 0;
382:
383: fprintf(stderr, "Memory allocation statistics %s\nfree:\t", s);
384: for (i = 0; i < NBUCKETS; i++) {
385: for (j = 0, p = nextf[i]; p; p = p->ov_next, j++)
386: ;
387: fprintf(stderr, " %d", j);
388: totfree += j * (1 << (i + 3));
389: }
390: fprintf(stderr, "\nused:\t");
391: for (i = 0; i < NBUCKETS; i++) {
392: fprintf(stderr, " %d", nmalloc[i]);
393: totused += nmalloc[i] * (1 << (i + 3));
394: }
395: fprintf(stderr, "\n\tTotal in use: %d, total free: %d\n",
396: totused, totfree);
397: }
398: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.