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