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