Annotation of src/usr.bin/patch/malloc.c, Revision 1.3
1.3 ! mpech 1: /* * $OpenBSD: malloc.c,v 1.2 1996/06/10 11:21:29 niklas Exp $*/
1.1 deraadt 2: /*
3: * from: @(#)nmalloc.c 1 (Caltech) 2/21/82
4: *
5: * U of M Modified: 20 Jun 1983 ACT: strange hacks for Emacs
6: *
7: * Nov 1983, Mike@BRL, Added support for 4.1C/4.2 BSD.
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
11: * that don't exactly fit are passed up to the next larger size. In this
12: * implementation, the available sizes are (2^n)-4 (or -16) bytes long.
13: * This is designed for use in a program that uses vast quantities of
14: * memory, but bombs when it runs out. To make it a little better, it
15: * warns the user when he starts to get near the end.
16: *
17: * June 84, ACT: modified rcheck code to check the range given to malloc,
18: * rather than the range determined by the 2-power used.
19: *
20: * Jan 85, RMS: calls malloc_warning to issue warning on nearly full.
21: * No longer Emacs-specific; can serve as all-purpose malloc for GNU.
22: * You should call malloc_init to reinitialize after loading dumped Emacs.
23: * Call malloc_stats to get info on memory stats if MSTATS turned on.
24: * realloc knows how to return same block given, just changing its size,
25: * if the power of 2 is correct.
26: */
27:
28: /*
29: * nextf[i] is the pointer to the next free block of size 2^(i+3). The
30: * smallest allocatable block is 8 bytes. The overhead information will
31: * go in the first int of the block, and the returned pointer will point
32: * to the second.
33: *
34: #ifdef MSTATS
35: * nmalloc[i] is the difference between the number of mallocs and frees
36: * for a given block size.
37: #endif /* MSTATS */
38: */
39:
40: #define ISALLOC ((char) 0xf7) /* magic byte that implies allocation */
41: #define ISFREE ((char) 0x54) /* magic byte that implies free block */
42: /* this is for error checking only */
43:
44: extern char etext;
45:
46: /* end of the program; can be changed by calling init_malloc */
47: static char *endofpure = &etext;
48:
49: #ifdef MSTATS
50: static int nmalloc[30];
51: static int nmal, nfre;
52: #endif /* MSTATS */
53:
54: /* If range checking is not turned on, all we have is a flag indicating
55: whether memory is allocated, an index in nextf[], and a size field; to
56: realloc() memory we copy either size bytes or 1<<(index+3) bytes depending
57: on whether the former can hold the exact size (given the value of
58: 'index'). If range checking is on, we always need to know how much space
59: is allocated, so the 'size' field is never used. */
60:
61: struct mhead {
62: char mh_alloc; /* ISALLOC or ISFREE */
63: char mh_index; /* index in nextf[] */
64: /* Remainder are valid only when block is allocated */
65: unsigned short mh_size; /* size, if < 0x10000 */
66: #ifdef rcheck
67: unsigned mh_nbytes; /* number of bytes allocated */
68: int mh_magic4; /* should be == MAGIC4 */
69: #endif /* rcheck */
70: };
71:
72: /* Access free-list pointer of a block.
73: It is stored at block + 4.
74: This is not a field in the mhead structure
75: because we want sizeof (struct mhead)
76: to describe the overhead for when the block is in use,
77: and we do not want the free-list pointer to count in that. */
78:
79: #define CHAIN(a) \
80: (*(struct mhead **) (sizeof (char *) + (char *) (a)))
81:
82: #ifdef rcheck
83:
84: /* To implement range checking, we write magic values in at the beginning and
85: end of each allocated block, and make sure they are undisturbed whenever a
86: free or a realloc occurs. */
87: /* Written in each of the 4 bytes following the block's real space */
88: #define MAGIC1 0x55
89: /* Written in the 4 bytes before the block's real space */
90: #define MAGIC4 0x55555555
91: #define ASSERT(p) if (!(p)) botch("p"); else
92: static
93: botch(s)
94: char *s;
95: {
96:
97: printf("assertion botched: %s\n", s);
98: abort();
99: }
100: #define EXTRA 4 /* 4 bytes extra for MAGIC1s */
101: #else
102: #define ASSERT(p)
103: #define EXTRA 0
104: #endif /* rcheck */
105:
106: /* nextf[i] is free list of blocks of size 2**(i + 3) */
107:
108: static struct mhead *nextf[30];
109:
110: #ifdef M_WARN
111: /* Number of bytes of writable memory we can expect to be able to get */
112: static int lim_data;
113: /* Level number of warnings already issued.
114: 0 -- no warnings issued.
115: 1 -- 75% warning already issued.
116: 2 -- 85% warning already issued.
117: */
118: static int warnlevel;
119: #endif /* M_WARN */
120:
121: /* nonzero once initial bunch of free blocks made */
122: static int gotpool;
123:
124: /* Cause reinitialization based on job parameters;
125: also declare where the end of pure storage is. */
126: malloc_init (end)
127: char *end; {
128: endofpure = end;
129: #ifdef M_WARN
130: lim_data = 0;
131: warnlevel = 0;
132: #endif /* M_WARN */
133: }
134:
135: static
136: morecore (nu) /* ask system for more memory */
1.3 ! mpech 137: int nu; { /* size index to get more of */
1.1 deraadt 138: char *sbrk ();
1.3 ! mpech 139: char *cp;
! 140: int nblks;
! 141: int siz;
1.1 deraadt 142:
143: #ifdef M_WARN
144: #ifndef BSD42
145: #ifdef USG
146: extern long ulimit ();
147: if (lim_data == 0) /* find out how much we can get */
148: lim_data = ulimit (3, 0) - TEXT_START;
149: #else /*HMS: was endif */
150: if (lim_data == 0) /* find out how much we can get */
151: lim_data = vlimit (LIM_DATA, -1);
152: #endif /* USG */ /HMS:* was not here */
153: #else
154: if (lim_data == 0) {
155: struct rlimit XXrlimit;
156:
157: getrlimit (RLIMIT_DATA, &XXrlimit);
158: lim_data = XXrlimit.rlim_cur;} /* soft limit */
159: #endif /* BSD42 */
160: #endif /* M_WARN */
161:
162: /* On initial startup, get two blocks of each size up to 1k bytes */
163: if (!gotpool)
164: getpool (), getpool (), gotpool = 1;
165:
166: /* Find current end of memory and issue warning if getting near max */
167:
168: cp = sbrk (0);
169: siz = cp - endofpure;
170: #ifdef M_WARN
171: switch (warnlevel) {
172: case 0:
173: if (siz > (lim_data / 4) * 3) {
174: warnlevel++;
175: malloc_warning ("Warning: past 75% of memory limit");}
176: break;
177: case 1:
178: if (siz > (lim_data / 20) * 17) {
179: warnlevel++;
180: malloc_warning ("Warning: past 85% of memory limit");}
181: break;
182: case 2:
183: if (siz > (lim_data / 20) * 19) {
184: warnlevel++;
185: malloc_warning ("Warning: past 95% of memory limit");}
186: break;}
187: #endif /* M_WARN */
188:
189: if ((int) cp & 0x3ff) /* land on 1K boundaries */
190: sbrk (1024 - ((int) cp & 0x3ff));
191:
192: /* Take at least 2k, and figure out how many blocks of the desired size we're about to get */
193: nblks = 1;
194: if ((siz = nu) < 8)
195: nblks = 1 << ((siz = 8) - nu);
196:
197: if ((cp = sbrk (1 << (siz + 3))) == (char *) -1)
198: return; /* no more room! */
199: if ((int) cp & 7) { /* shouldn't happen, but just in case */
200: cp = (char *) (((int) cp + 8) & ~7);
201: nblks--;}
202:
203: /* save new header and link the nblks blocks together */
204: nextf[nu] = (struct mhead *) cp;
205: siz = 1 << (nu + 3);
206: while (1) {
207: ((struct mhead *) cp) -> mh_alloc = ISFREE;
208: ((struct mhead *) cp) -> mh_index = nu;
209: if (--nblks <= 0) break;
210: CHAIN ((struct mhead *) cp) = (struct mhead *) (cp + siz);
211: cp += siz;}
212: /* CHAIN ((struct mhead *) cp) = 0; /* since sbrk() returns cleared core, this is already set */
213: }
214:
215: static
216: getpool () {
1.3 ! mpech 217: int nu;
! 218: char *cp = sbrk (0);
1.1 deraadt 219:
220: if ((int) cp & 0x3ff) /* land on 1K boundaries */
221: sbrk (1024 - ((int) cp & 0x3ff));
222:
223: /* Get 2k of storage */
224:
225: cp = sbrk (04000);
226: if (cp == (char *) -1)
227: return;
228:
229: /* Divide it into an initial 8-word block
230: plus one block of size 2**nu for nu = 3 ... 10. */
231:
232: CHAIN (cp) = nextf[0];
233: nextf[0] = (struct mhead *) cp;
234: ((struct mhead *) cp) -> mh_alloc = ISFREE;
235: ((struct mhead *) cp) -> mh_index = 0;
236: cp += 8;
237:
238: for (nu = 0; nu < 7; nu++) {
239: CHAIN (cp) = nextf[nu];
240: nextf[nu] = (struct mhead *) cp;
241: ((struct mhead *) cp) -> mh_alloc = ISFREE;
242: ((struct mhead *) cp) -> mh_index = nu;
243: cp += 8 << nu;}}
244:
245: char *
246: malloc (n) /* get a block */
247: unsigned n; {
1.3 ! mpech 248: struct mhead *p;
! 249: unsigned int nbytes;
! 250: int nunits = 0;
1.1 deraadt 251:
252: /* Figure out how many bytes are required, rounding up to the nearest
253: multiple of 4, then figure out which nextf[] area to use */
254: nbytes = (n + sizeof *p + EXTRA + 3) & ~3;
255: {
1.3 ! mpech 256: unsigned int shiftr = (nbytes - 1) >> 2;
1.1 deraadt 257:
258: while (shiftr >>= 1)
259: nunits++;
260: }
261:
262: /* If there are no blocks of the appropriate size, go get some */
263: /* COULD SPLIT UP A LARGER BLOCK HERE ... ACT */
264: if (nextf[nunits] == 0)
265: morecore (nunits);
266:
267: /* Get one block off the list, and set the new list head */
268: if ((p = nextf[nunits]) == 0)
269: return 0;
270: nextf[nunits] = CHAIN (p);
271:
272: /* Check for free block clobbered */
273: /* If not for this check, we would gobble a clobbered free chain ptr */
274: /* and bomb out on the NEXT allocate of this size block */
275: if (p -> mh_alloc != ISFREE || p -> mh_index != nunits)
276: #ifdef rcheck
277: botch ("block on free list clobbered");
278: #else
279: abort ();
280: #endif /* rcheck */
281:
282: /* Fill in the info, and if range checking, set up the magic numbers */
283: p -> mh_alloc = ISALLOC;
284: #ifdef rcheck
285: p -> mh_nbytes = n;
286: p -> mh_magic4 = MAGIC4;
287: {
1.3 ! mpech 288: char *m = (char *) (p + 1) + n;
1.1 deraadt 289:
290: *m++ = MAGIC1, *m++ = MAGIC1, *m++ = MAGIC1, *m = MAGIC1;
291: }
292: #else
293: p -> mh_size = n;
294: #endif /* rcheck */
295: #ifdef MSTATS
296: nmalloc[nunits]++;
297: nmal++;
298: #endif /* MSTATS */
299: return (char *) (p + 1);}
300:
301: free (mem)
302: char *mem; {
1.3 ! mpech 303: struct mhead *p;
1.1 deraadt 304: {
1.3 ! mpech 305: char *ap = mem;
1.1 deraadt 306:
307: ASSERT (ap != 0);
308: p = (struct mhead *) ap - 1;
309: ASSERT (p -> mh_alloc == ISALLOC);
310: #ifdef rcheck
311: ASSERT (p -> mh_magic4 == MAGIC4);
312: ap += p -> mh_nbytes;
313: ASSERT (*ap++ == MAGIC1); ASSERT (*ap++ == MAGIC1);
314: ASSERT (*ap++ == MAGIC1); ASSERT (*ap == MAGIC1);
315: #endif /* rcheck */
316: }
317: {
1.3 ! mpech 318: int nunits = p -> mh_index;
1.1 deraadt 319:
320: ASSERT (nunits <= 29);
321: p -> mh_alloc = ISFREE;
322: CHAIN (p) = nextf[nunits];
323: nextf[nunits] = p;
324: #ifdef MSTATS
325: nmalloc[nunits]--;
326: nfre++;
327: #endif /* MSTATS */
328: }
329: }
330:
331: char *
332: realloc (mem, n)
333: char *mem;
1.3 ! mpech 334: unsigned n; {
! 335: struct mhead *p;
! 336: unsigned int tocopy;
! 337: int nbytes;
! 338: int nunits;
1.1 deraadt 339:
340: if ((p = (struct mhead *) mem) == 0)
341: return malloc (n);
342: p--;
343: nunits = p -> mh_index;
344: ASSERT (p -> mh_alloc == ISALLOC);
345: #ifdef rcheck
346: ASSERT (p -> mh_magic4 == MAGIC4);
347: {
1.3 ! mpech 348: char *m = mem + (tocopy = p -> mh_nbytes);
1.1 deraadt 349: ASSERT (*m++ == MAGIC1); ASSERT (*m++ == MAGIC1);
350: ASSERT (*m++ == MAGIC1); ASSERT (*m == MAGIC1);
351: }
352: #else
353: if (p -> mh_index >= 13)
354: tocopy = (1 << (p -> mh_index + 3)) - sizeof *p;
355: else
356: tocopy = p -> mh_size;
357: #endif /* rcheck */
358:
359: /* See if desired size rounds to same power of 2 as actual size. */
360: nbytes = (n + sizeof *p + EXTRA + 7) & ~7;
361:
362: /* If ok, use the same block, just marking its size as changed. */
363: if (nbytes > (4 << nunits) && nbytes <= (8 << nunits)) {
364: #ifdef rcheck
1.3 ! mpech 365: char *m = mem + tocopy;
1.1 deraadt 366: *m++ = 0; *m++ = 0; *m++ = 0; *m++ = 0;
367: p-> mh_nbytes = n;
368: m = mem + n;
369: *m++ = MAGIC1; *m++ = MAGIC1; *m++ = MAGIC1; *m++ = MAGIC1;
370: #else
371: p -> mh_size = n;
372: #endif /* rcheck */
373: return mem;}
374:
375: if (n < tocopy)
376: tocopy = n;
377: {
1.3 ! mpech 378: char *new;
1.1 deraadt 379: void bcopy(); /*HMS: here? */
380:
381: if ((new = malloc (n)) == 0)
382: return 0;
383: bcopy (mem, new, tocopy);
384: free (mem);
385: return new;
386: }
387: }
388:
389: #ifdef MSTATS
390: /* Return statistics describing allocation of blocks of size 2**n. */
391:
392: struct mstats_value {
393: int blocksize;
394: int nfree;
395: int nused;
396: };
397:
398: struct mstats_value
399: malloc_stats (size)
400: int size; {
401: struct mstats_value v;
1.3 ! mpech 402: int i;
! 403: struct mhead *p;
1.1 deraadt 404:
405: v.nfree = 0;
406:
407: if (size < 0 || size >= 30) {
408: v.blocksize = 0;
409: v.nused = 0;
410: return v;}
411:
412: v.blocksize = 1 << (size + 3);
413: v.nused = nmalloc[size];
414:
415: for (p = nextf[size]; p; p = CHAIN (p))
416: v.nfree++;
417:
418: return v;}
419: #endif
420:
421: /* how much space is available? */
422:
423: unsigned freespace() {
1.3 ! mpech 424: int i, j;
! 425: struct mhead *p;
! 426: unsigned space = 0;
1.1 deraadt 427: int local; /* address only is used */
428:
429: space = (char *)&local - sbrk(0); /* stack space */
430:
431: for (i = 0; i < 30; i++) {
432: for (j = 0, p = nextf[i]; p; p = CHAIN (p), j++) ;
433: space += j * (1 << (i + 3));}
434:
435: return(space);}
436:
437: /* How big is this cell? */
438:
439: unsigned mc_size(cp)
440: char *cp;{
1.3 ! mpech 441: struct mhead *p;
1.1 deraadt 442:
443: if ((p = (struct mhead *) cp) == 0) {
444: /*HMS? */
445: }
446: p--;
447: #ifdef rcheck
448: return p -> mh_nbytes;
449: #else
450: return (1 << (p -> mh_index + 3)) - sizeof *p;
451: /**/
452: /* if (p -> mh_index >= 13)
453: /* return (1 << (p -> mh_index + 3)) - sizeof *p;
454: /* else
455: /* return p -> mh_size;
456: /**/
457: #endif /* rcheck */
458: }
459:
460: /*HMS: Really should use memcpy, if available... */
461:
462: void bcopy(source, dest, len)
1.3 ! mpech 463: char *source, *dest;
! 464: len; {
! 465: i;
1.1 deraadt 466:
467: for (i = 0; i < len; i++)
468: *dest++ = *source++;}