1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32: #include <sys/cdefs.h>
33: #if defined(LIBC_SCCS) && !defined(lint)
34: #if 0
35: static char sccsid[] = "@(#)malloc.c 8.1 (Berkeley) 6/4/93";
36: #else
37: __RCSID("$NetBSD: malloc.c,v 1.4 2004/12/14 00:21:01 nathanw Exp $");
38: #endif
39: #endif
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52: #include <sys/types.h>
53: #if defined(DEBUG) || defined(RCHECK)
54: #include <sys/uio.h>
55: #endif
56: #if defined(RCHECK) || defined(MSTATS)
57: #include <stdio.h>
58: #endif
59: #include <stdlib.h>
60: #include <string.h>
61: #include <unistd.h>
62: #include <pthread.h>
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75: union overhead {
76: union overhead *ov_next;
77: struct {
78: u_char ovu_magic;
79: u_char ovu_index;
80: #ifdef RCHECK
81: u_short ovu_rmagic;
82: u_long ovu_size;
83: #endif
84: } ovu;
85: #define ov_magic ovu.ovu_magic
86: #define ov_index ovu.ovu_index
87: #define ov_rmagic ovu.ovu_rmagic
88: #define ov_size ovu.ovu_size
89: };
90:
91: #define MAGIC 0xef
92: #ifdef RCHECK
93: #define RMAGIC 0x5555
94: #endif
95:
96: #ifdef RCHECK
97: #define RSLOP sizeof (u_short)
98: #else
99: #define RSLOP 0
100: #endif
101:
102:
103:
104:
105:
106:
107: #define NBUCKETS 30
108: static union overhead *nextf[NBUCKETS];
109:
110: static long pagesz;
111: static int pagebucket;
112:
113: #ifdef MSTATS
114:
115:
116:
117:
118: static u_int nmalloc[NBUCKETS];
119: #endif
120:
121: static pthread_mutex_t malloc_mutex = PTHREAD_MUTEX_INITIALIZER;
122:
123: static void morecore(int);
124: static int findbucket(union overhead *, int);
125: #ifdef MSTATS
126: void mstats(const char *);
127: #endif
128:
129: #if defined(DEBUG) || defined(RCHECK)
130: #define ASSERT(p) if (!(p)) botch(__STRING(p))
131:
132: static void botch(const char *);
133:
134:
135:
136:
137:
138: static void
139: botch(s)
140: const char *s;
141: {
142: struct iovec iov[3];
143:
144: iov[0].iov_base = "\nassertion botched: ";
145: iov[0].iov_len = 20;
146: iov[1].iov_base = (void *)s;
147: iov[1].iov_len = strlen(s);
148: iov[2].iov_base = "\n";
149: iov[2].iov_len = 1;
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163: (void)writev(STDERR_FILENO, iov, 3);
164: abort();
165: }
166: #else
167: #define ASSERT(p)
168: #endif
169:
170: void *
171: malloc(nbytes)
172: size_t nbytes;
173: {
174: union overhead *op;
175: int bucket;
176: long n;
177: unsigned amt;
178:
179: pthread_mutex_lock(&malloc_mutex);
180:
181:
182:
183:
184:
185: if (pagesz == 0) {
186: pagesz = n = getpagesize();
187: ASSERT(pagesz > 0);
188: op = (union overhead *)(void *)sbrk(0);
189: n = n - sizeof (*op) - ((long)op & (n - 1));
190: if (n < 0)
191: n += pagesz;
192: if (n) {
193: if (sbrk((int)n) == (void *)-1) {
194: pthread_mutex_unlock(&malloc_mutex);
195: return (NULL);
196: }
197: }
198: bucket = 0;
199: amt = 8;
200: while (pagesz > amt) {
201: amt <<= 1;
202: bucket++;
203: }
204: pagebucket = bucket;
205: }
206:
207:
208:
209:
210:
211: if (nbytes <= (n = pagesz - sizeof (*op) - RSLOP)) {
212: #ifndef RCHECK
213: amt = 8;
214: bucket = 0;
215: #else
216: amt = 16;
217: bucket = 1;
218: #endif
219: n = -((long)sizeof (*op) + RSLOP);
220: } else {
221: amt = (unsigned)pagesz;
222: bucket = pagebucket;
223: }
224: while (nbytes > amt + n) {
225: amt <<= 1;
226: if (amt == 0)
227: return (NULL);
228: bucket++;
229: }
230:
231:
232:
233:
234: if ((op = nextf[bucket]) == NULL) {
235: morecore(bucket);
236: if ((op = nextf[bucket]) == NULL) {
237: pthread_mutex_unlock(&malloc_mutex);
238: return (NULL);
239: }
240: }
241:
242: nextf[bucket] = op->ov_next;
243: op->ov_magic = MAGIC;
244: op->ov_index = bucket;
245: #ifdef MSTATS
246: nmalloc[bucket]++;
247: #endif
248: pthread_mutex_unlock(&malloc_mutex);
249: #ifdef RCHECK
250:
251:
252:
253:
254: op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1);
255: op->ov_rmagic = RMAGIC;
256: *(u_short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC;
257: #endif
258: return ((void *)(op + 1));
259: }
260:
261:
262:
263:
264: static void
265: morecore(bucket)
266: int bucket;
267: {
268: union overhead *op;
269: long sz;
270: long amt;
271: long nblks;
272:
273:
274:
275:
276:
277: sz = 1 << (bucket + 3);
278: #ifdef DEBUG
279: ASSERT(sz > 0);
280: #else
281: if (sz <= 0)
282: return;
283: #endif
284: if (sz < pagesz) {
285: amt = pagesz;
286: nblks = amt / sz;
287: } else {
288: amt = sz + pagesz;
289: nblks = 1;
290: }
291: op = (union overhead *)(void *)sbrk((int)amt);
292:
293: if ((long)op == -1)
294: return;
295:
296:
297:
298:
299: nextf[bucket] = op;
300: while (--nblks > 0) {
301: op->ov_next =
302: (union overhead *)(void *)((caddr_t)(void *)op+(size_t)sz);
303: op = op->ov_next;
304: }
305: }
306:
307: void
308: free(cp)
309: void *cp;
310: {
311: long size;
312: union overhead *op;
313:
314: if (cp == NULL)
315: return;
316: op = (union overhead *)(void *)((caddr_t)cp - sizeof (union overhead));
317: #ifdef DEBUG
318: ASSERT(op->ov_magic == MAGIC);
319: #else
320: if (op->ov_magic != MAGIC)
321: return;
322: #endif
323: #ifdef RCHECK
324: ASSERT(op->ov_rmagic == RMAGIC);
325: ASSERT(*(u_short *)((caddr_t)(op + 1) + op->ov_size) == RMAGIC);
326: #endif
327: size = op->ov_index;
328: ASSERT(size < NBUCKETS);
329: pthread_mutex_lock(&malloc_mutex);
330: op->ov_next = nextf[(unsigned int)size];
331: nextf[(unsigned int)size] = op;
332: #ifdef MSTATS
333: nmalloc[(size_t)size]--;
334: #endif
335: pthread_mutex_unlock(&malloc_mutex);
336: }
337:
338:
339:
340:
341:
342:
343:
344:
345:
346:
347:
348:
349: int __realloc_srchlen = 4;
350:
351: void *
352: realloc(cp, nbytes)
353: void *cp;
354: size_t nbytes;
355: {
356: u_long onb;
357: long i;
358: union overhead *op;
359: char *res;
360: int was_alloced = 0;
361:
362: if (cp == NULL)
363: return (malloc(nbytes));
364: if (nbytes == 0) {
365: free (cp);
366: return (NULL);
367: }
368: op = (union overhead *)(void *)((caddr_t)cp - sizeof (union overhead));
369: pthread_mutex_lock(&malloc_mutex);
370: if (op->ov_magic == MAGIC) {
371: was_alloced++;
372: i = op->ov_index;
373: } else {
374:
375:
376:
377:
378:
379:
380:
381:
382:
383:
384:
385:
386:
387:
388: if ((i = findbucket(op, 1)) < 0 &&
389: (i = findbucket(op, __realloc_srchlen)) < 0)
390: i = NBUCKETS;
391: }
392: onb = (u_long)1 << (u_long)(i + 3);
393: if (onb < pagesz)
394: onb -= sizeof (*op) + RSLOP;
395: else
396: onb += pagesz - sizeof (*op) - RSLOP;
397:
398: if (was_alloced) {
399: if (i) {
400: i = (long)1 << (long)(i + 2);
401: if (i < pagesz)
402: i -= sizeof (*op) + RSLOP;
403: else
404: i += pagesz - sizeof (*op) - RSLOP;
405: }
406: if (nbytes <= onb && nbytes > i) {
407: #ifdef RCHECK
408: op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1);
409: *(u_short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC;
410: #endif
411: pthread_mutex_unlock(&malloc_mutex);
412: return (cp);
413:
414: }
415: #ifndef _REENT
416: else
417: free(cp);
418: #endif
419: }
420: pthread_mutex_unlock(&malloc_mutex);
421: if ((res = malloc(nbytes)) == NULL) {
422: #ifdef _REENT
423: free(cp);
424: #endif
425: return (NULL);
426: }
427: #ifndef _REENT
428: if (cp != res)
429: (void)memmove(res, cp, (size_t)((nbytes < onb) ? nbytes : onb));
430: #else
431: (void)memmove(res, cp, (size_t)((nbytes < onb) ? nbytes : onb));
432: free(cp);
433: #endif
434: return (res);
435: }
436:
437:
438:
439:
440:
441:
442: static int
443: findbucket(freep, srchlen)
444: union overhead *freep;
445: int srchlen;
446: {
447: union overhead *p;
448: int i, j;
449:
450: for (i = 0; i < NBUCKETS; i++) {
451: j = 0;
452: for (p = nextf[i]; p && j != srchlen; p = p->ov_next) {
453: if (p == freep)
454: return (i);
455: j++;
456: }
457: }
458: return (-1);
459: }
460:
461: #ifdef MSTATS
462:
463:
464:
465:
466:
467:
468:
469: void
470: mstats(s)
471: char *s;
472: {
473: int i, j;
474: union overhead *p;
475: int totfree = 0,
476: totused = 0;
477:
478: fprintf(stderr, "Memory allocation statistics %s\nfree:\t", s);
479: for (i = 0; i < NBUCKETS; i++) {
480: for (j = 0, p = nextf[i]; p; p = p->ov_next, j++)
481: ;
482: fprintf(stderr, " %d", j);
483: totfree += j * (1 << (i + 3));
484: }
485: fprintf(stderr, "\nused:\t");
486: for (i = 0; i < NBUCKETS; i++) {
487: fprintf(stderr, " %d", nmalloc[i]);
488: totused += nmalloc[i] * (1 << (i + 3));
489: }
490: fprintf(stderr, "\n\tTotal in use: %d, total free: %d\n",
491: totused, totfree);
492: }
493: #endif