|
|
1.1 root 1: #ifndef lint
2: static char sccsid[] = "@(#)malloc.c 4.3 (Berkeley) 9/16/83";
3: #endif
4:
5: /*
6: * malloc.c (Caltech) 2/21/82
7: * Chris Kingsley, kingsley@cit-20.
8: *
9: * This is a very fast storage allocator. It allocates blocks of a small
10: * number of different sizes, and keeps free lists of each size. Blocks that
11: * don't exactly fit are passed up to the next larger size. In this
12: * implementation, the available sizes are 2^n-4 (or 2^n-12) bytes long.
13: * This is designed for use in a program that uses vast quantities of memory,
14: * but bombs when it runs out.
15: */
16:
17: #include <sys/types.h>
18:
19: #define NULL 0
20:
21: /*
22: * The overhead on a block is at least 4 bytes. When free, this space
23: * contains a pointer to the next free block, and the bottom two bits must
24: * be zero. When in use, the first byte is set to MAGIC, and the second
25: * byte is the size index. The remaining bytes are for alignment.
26: * If range checking is enabled and the size of the block fits
27: * in two bytes, then the top two bytes hold the size of the requested block
28: * plus the range checking words, and the header word MINUS ONE.
29: */
30: union overhead {
31: union overhead *ov_next; /* when free */
32: struct {
33: u_char ovu_magic; /* magic number */
34: u_char ovu_index; /* bucket # */
35: #ifdef RCHECK
36: u_short ovu_size; /* actual block size */
37: u_int ovu_rmagic; /* range magic number */
38: #endif
39: } ovu;
40: #define ov_magic ovu.ovu_magic
41: #define ov_index ovu.ovu_index
42: #define ov_size ovu.ovu_size
43: #define ov_rmagic ovu.ovu_rmagic
44: };
45:
46: #define MAGIC 0xff /* magic # on accounting info */
47: #define RMAGIC 0x55555555 /* magic # on range info */
48: #ifdef RCHECK
49: #define RSLOP sizeof (u_int)
50: #else
51: #define RSLOP 0
52: #endif
53:
54: /*
55: * nextf[i] is the pointer to the next free block of size 2^(i+3). The
56: * smallest allocatable block is 8 bytes. The overhead information
57: * precedes the data area returned to the user.
58: */
59: #define NBUCKETS 30
60: static union overhead *nextf[NBUCKETS];
61: extern char *sbrk();
62:
63: #ifdef MSTATS
64: /*
65: * nmalloc[i] is the difference between the number of mallocs and frees
66: * for a given block size.
67: */
68: static u_int nmalloc[NBUCKETS];
69: #include <stdio.h>
70: #endif
71:
72: #ifdef debug
73: #define ASSERT(p) if (!(p)) botch("p"); else
74: static
75: botch(s)
76: char *s;
77: {
78:
79: printf("assertion botched: %s\n", s);
80: abort();
81: }
82: #else
83: #define ASSERT(p)
84: #endif
85:
86: char *
87: malloc(nbytes)
88: register unsigned nbytes;
89: {
90: register union overhead *p;
91: register int bucket = 0;
92: register unsigned shiftr;
93:
94: /*
95: * Convert amount of memory requested into
96: * closest block size stored in hash buckets
97: * which satisfies request. Account for
98: * space used per block for accounting.
99: */
100: nbytes += sizeof (union overhead) + RSLOP;
101: nbytes = (nbytes + 3) &~ 3;
102: shiftr = (nbytes - 1) >> 2;
103: /* apart from this loop, this is O(1) */
104: while (shiftr >>= 1)
105: bucket++;
106: /*
107: * If nothing in hash bucket right now,
108: * request more memory from the system.
109: */
110: if (nextf[bucket] == NULL)
111: morecore(bucket);
112: if ((p = (union overhead *)nextf[bucket]) == NULL)
113: return (NULL);
114: /* remove from linked list */
115: nextf[bucket] = nextf[bucket]->ov_next;
116: p->ov_magic = MAGIC;
117: p->ov_index= bucket;
118: #ifdef MSTATS
119: nmalloc[bucket]++;
120: #endif
121: #ifdef RCHECK
122: /*
123: * Record allocated size of block and
124: * bound space with magic numbers.
125: */
126: if (nbytes <= 0x10000)
127: p->ov_size = nbytes - 1;
128: p->ov_rmagic = RMAGIC;
129: *((u_int *)((caddr_t)p + nbytes - RSLOP)) = RMAGIC;
130: #endif
131: return ((char *)(p + 1));
132: }
133:
134: /*
135: * Allocate more memory to the indicated bucket.
136: */
137: static
138: morecore(bucket)
139: register bucket;
140: {
141: register union overhead *op;
142: register int rnu; /* 2^rnu bytes will be requested */
143: register int nblks; /* become nblks blocks of the desired size */
144: register int siz;
145:
146: if (nextf[bucket])
147: return;
148: /*
149: * Insure memory is allocated
150: * on a page boundary. Should
151: * make getpageize call?
152: */
153: op = (union overhead *)sbrk(0);
154: if ((int)op & 0x3ff)
155: sbrk(1024 - ((int)op & 0x3ff));
156: /* take 2k unless the block is bigger than that */
157: rnu = (bucket <= 8) ? 11 : bucket + 3;
158: nblks = 1 << (rnu - (bucket + 3)); /* how many blocks to get */
159: if (rnu < bucket)
160: rnu = bucket;
161: op = (union overhead *)sbrk(1 << rnu);
162: /* no more room! */
163: if ((int)op == -1)
164: return;
165: /*
166: * Round up to minimum allocation size boundary
167: * and deduct from block count to reflect.
168: */
169: if ((int)op & 7) {
170: op = (union overhead *)(((int)op + 8) &~ 7);
171: nblks--;
172: }
173: /*
174: * Add new memory allocated to that on
175: * free list for this hash bucket.
176: */
177: nextf[bucket] = op;
178: siz = 1 << (bucket + 3);
179: while (--nblks > 0) {
180: op->ov_next = (union overhead *)((caddr_t)op + siz);
181: op = (union overhead *)((caddr_t)op + siz);
182: }
183: }
184:
185: free(cp)
186: char *cp;
187: {
188: register int size;
189: register union overhead *op;
190:
191: if (cp == NULL)
192: return;
193: op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
194: #ifdef debug
195: ASSERT(op->ov_magic == MAGIC); /* make sure it was in use */
196: #else
197: if (op->ov_magic != MAGIC)
198: return; /* sanity */
199: #endif
200: #ifdef RCHECK
201: ASSERT(op->ov_rmagic == RMAGIC);
202: if (op->ov_index <= 13)
203: ASSERT(*(u_int *)((caddr_t)op + op->ov_size + 1 - RSLOP) == RMAGIC);
204: #endif
205: ASSERT(op->ov_index < NBUCKETS);
206: size = op->ov_index;
207: op->ov_next = nextf[size];
208: nextf[size] = op;
209: #ifdef MSTATS
210: nmalloc[size]--;
211: #endif
212: }
213:
214: /*
215: * When a program attempts "storage compaction" as mentioned in the
216: * old malloc man page, it realloc's an already freed block. Usually
217: * this is the last block it freed; occasionally it might be farther
218: * back. We have to search all the free lists for the block in order
219: * to determine its bucket: 1st we make one pass thru the lists
220: * checking only the first block in each; if that fails we search
221: * ``realloc_srchlen'' blocks in each list for a match (the variable
222: * is extern so the caller can modify it). If that fails we just copy
223: * however many bytes was given to realloc() and hope it's not huge.
224: */
225: int realloc_srchlen = 4; /* 4 should be plenty, -1 =>'s whole list */
226:
227: char *
228: realloc(cp, nbytes)
229: char *cp;
230: unsigned nbytes;
231: {
232: register u_int onb;
233: union overhead *op;
234: char *res;
235: register int i;
236: int was_alloced = 0;
237:
238: if (cp == NULL)
239: return (malloc(nbytes));
240: op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
241: if (op->ov_magic == MAGIC) {
242: was_alloced++;
243: i = op->ov_index;
244: } else {
245: /*
246: * Already free, doing "compaction".
247: *
248: * Search for the old block of memory on the
249: * free list. First, check the most common
250: * case (last element free'd), then (this failing)
251: * the last ``realloc_srchlen'' items free'd.
252: * If all lookups fail, then assume the size of
253: * the memory block being realloc'd is the
254: * smallest possible.
255: */
256: if ((i = findbucket(op, 1)) < 0 &&
257: (i = findbucket(op, realloc_srchlen)) < 0)
258: i = 0;
259: }
260: onb = (1 << (i + 3)) - sizeof (*op) - RSLOP;
261: /* avoid the copy if same size block */
262: if (was_alloced &&
263: nbytes <= onb && nbytes > (onb >> 1) - sizeof(*op) - RSLOP)
264: return(cp);
265: if ((res = malloc(nbytes)) == NULL)
266: return (NULL);
267: if (cp != res) /* common optimization */
268: bcopy(cp, res, (nbytes < onb) ? nbytes : onb);
269: if (was_alloced)
270: free(cp);
271: return (res);
272: }
273:
274: /*
275: * Search ``srchlen'' elements of each free list for a block whose
276: * header starts at ``freep''. If srchlen is -1 search the whole list.
277: * Return bucket number, or -1 if not found.
278: */
279: static
280: findbucket(freep, srchlen)
281: union overhead *freep;
282: int srchlen;
283: {
284: register union overhead *p;
285: register int i, j;
286:
287: for (i = 0; i < NBUCKETS; i++) {
288: j = 0;
289: for (p = nextf[i]; p && j != srchlen; p = p->ov_next) {
290: if (p == freep)
291: return (i);
292: j++;
293: }
294: }
295: return (-1);
296: }
297:
298: #ifdef MSTATS
299: /*
300: * mstats - print out statistics about malloc
301: *
302: * Prints two lines of numbers, one showing the length of the free list
303: * for each size category, the second showing the number of mallocs -
304: * frees for each size category.
305: */
306: mstats(s)
307: char *s;
308: {
309: register int i, j;
310: register union overhead *p;
311: int totfree = 0,
312: totused = 0;
313:
314: fprintf(stderr, "Memory allocation statistics %s\nfree:\t", s);
315: for (i = 0; i < NBUCKETS; i++) {
316: for (j = 0, p = nextf[i]; p; p = p->ov_next, j++)
317: ;
318: fprintf(stderr, " %d", j);
319: totfree += j * (1 << (i + 3));
320: }
321: fprintf(stderr, "\nused:\t");
322: for (i = 0; i < NBUCKETS; i++) {
323: fprintf(stderr, " %d", nmalloc[i]);
324: totused += nmalloc[i] * (1 << (i + 3));
325: }
326: fprintf(stderr, "\n\tTotal in use: %d, total free: %d\n",
327: totused, totfree);
328: }
329: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.