summaryrefslogtreecommitdiff
path: root/src/lib/libc/stdlib/malloc.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/lib/libc/stdlib/malloc.c491
1 files changed, 271 insertions, 220 deletions
diff --git a/src/lib/libc/stdlib/malloc.c b/src/lib/libc/stdlib/malloc.c
index bff70c7b54..a6f60b3fe3 100644
--- a/src/lib/libc/stdlib/malloc.c
+++ b/src/lib/libc/stdlib/malloc.c
@@ -8,12 +8,15 @@
8 */ 8 */
9 9
10#if defined(LIBC_SCCS) && !defined(lint) 10#if defined(LIBC_SCCS) && !defined(lint)
11static char rcsid[] = "$OpenBSD: malloc.c,v 1.13 1996/09/19 20:38:48 tholo Exp $"; 11static char rcsid[] = "$OpenBSD: malloc.c,v 1.14 1996/09/26 04:19:42 tholo Exp $";
12#endif /* LIBC_SCCS and not lint */ 12#endif /* LIBC_SCCS and not lint */
13 13
14/* 14/*
15 * Defining EXTRA_SANITY will enable some checks which are related 15 * Defining EXTRA_SANITY will enable extra checks which are related
16 * to internal conditions and consistency in malloc.c 16 * to internal conditions and consistency in malloc.c. This has a
17 * noticeable runtime performance hit, and generally will not do you
18 * any good unless you fiddle with the internals of malloc or want
19 * to catch random pointer corruption as early as possible.
17 */ 20 */
18#undef EXTRA_SANITY 21#undef EXTRA_SANITY
19 22
@@ -29,23 +32,23 @@ static char rcsid[] = "$OpenBSD: malloc.c,v 1.13 1996/09/19 20:38:48 tholo Exp $
29#endif 32#endif
30 33
31/* 34/*
32 * What to use for Junk 35 * What to use for Junk. This is the byte value we use to fill with
36 * when the 'J' option is enabled.
33 */ 37 */
34#define SOME_JUNK 0xd0 /* as in "Duh" :-) */ 38#define SOME_JUNK 0xd0 /* as in "Duh" :-) */
35 39
40/*
41 * No user serviceable parts behind this point.
42 */
43
36#include <stdio.h> 44#include <stdio.h>
37#include <stdlib.h> 45#include <stdlib.h>
46#include <string.h>
38#include <unistd.h> 47#include <unistd.h>
39#include <memory.h>
40#include <errno.h> 48#include <errno.h>
41#include <err.h>
42#include <sys/types.h> 49#include <sys/types.h>
43#include <sys/param.h> 50#include <sys/param.h>
44#include <sys/mman.h> 51#include <sys/mman.h>
45#ifdef _THREAD_SAFE
46#include <pthread.h>
47#include "pthread_private.h"
48#endif
49 52
50/* 53/*
51 * If these weren't defined here, they would be calculated on the fly, 54 * If these weren't defined here, they would be calculated on the fly,
@@ -108,14 +111,14 @@ struct pgfree {
108 * We might as well use them. There are C-language backups, but 111 * We might as well use them. There are C-language backups, but
109 * they are considerably slower. 112 * they are considerably slower.
110 */ 113 */
111#ifdef __i386__ 114#if defined(__i386__) && defined(__GNUC__)
112#define ffs _ffs 115#define ffs _ffs
113static __inline int 116static __inline int
114_ffs(input) 117_ffs(input)
115 unsigned input; 118 unsigned input;
116{ 119{
117 int result; 120 int result;
118 __asm("bsfl %1,%0" : "=r" (result) : "r" (input)); 121 __asm("bsfl %1, %0" : "=r" (result) : "r" (input));
119 return result+1; 122 return result+1;
120} 123}
121 124
@@ -125,7 +128,7 @@ _fls(input)
125 unsigned input; 128 unsigned input;
126{ 129{
127 int result; 130 int result;
128 __asm("bsrl %1,%0" : "=r" (result) : "r" (input)); 131 __asm("bsrl %1, %0" : "=r" (result) : "r" (input));
129 return result+1; 132 return result+1;
130} 133}
131 134
@@ -135,7 +138,7 @@ _set_bit(pi, bit)
135 struct pginfo *pi; 138 struct pginfo *pi;
136 int bit; 139 int bit;
137{ 140{
138 __asm("btsl %0,(%1)" : 141 __asm("btsl %0, (%1)" :
139 : "r" (bit & (MALLOC_BITS-1)), "r" (pi->bits+(bit/MALLOC_BITS))); 142 : "r" (bit & (MALLOC_BITS-1)), "r" (pi->bits+(bit/MALLOC_BITS)));
140} 143}
141 144
@@ -145,11 +148,11 @@ _clr_bit(pi, bit)
145 struct pginfo *pi; 148 struct pginfo *pi;
146 int bit; 149 int bit;
147{ 150{
148 __asm("btcl %0,(%1)" : 151 __asm("btcl %0, (%1)" :
149 : "r" (bit & (MALLOC_BITS-1)), "r" (pi->bits+(bit/MALLOC_BITS))); 152 : "r" (bit & (MALLOC_BITS-1)), "r" (pi->bits+(bit/MALLOC_BITS)));
150} 153}
151 154
152#endif /* __i386__ */ 155#endif /* __i386__ && __GNUC__ */
153 156
154/* 157/*
155 * Set to one when malloc_init has been called 158 * Set to one when malloc_init has been called
@@ -165,17 +168,13 @@ static unsigned initialized;
165static unsigned malloc_pagesize; 168static unsigned malloc_pagesize;
166#endif /* malloc_pagesize */ 169#endif /* malloc_pagesize */
167 170
168/* 171/* A mask for the offset inside a page. */
169 * A mask for the offset inside a page.
170 */
171#define malloc_pagemask ((malloc_pagesize)-1) 172#define malloc_pagemask ((malloc_pagesize)-1)
172 173
173#define pageround(foo) (((foo) + (malloc_pagemask))&(~(malloc_pagemask))) 174#define pageround(foo) (((foo) + (malloc_pagemask))&(~(malloc_pagemask)))
174#define ptr2index(foo) (((u_long)(foo) >> malloc_pageshift)-malloc_origo) 175#define ptr2index(foo) (((u_long)(foo) >> malloc_pageshift)-malloc_origo)
175 176
176/* 177/* malloc_pagesize == 1 << malloc_pageshift */
177 * malloc_pagesize == 1 << malloc_pageshift
178 */
179#ifndef malloc_pageshift 178#ifndef malloc_pageshift
180static unsigned malloc_pageshift; 179static unsigned malloc_pageshift;
181#endif /* malloc_pageshift */ 180#endif /* malloc_pageshift */
@@ -197,85 +196,78 @@ static unsigned malloc_minsize;
197static unsigned malloc_maxsize; 196static unsigned malloc_maxsize;
198#endif /* malloc_maxsize */ 197#endif /* malloc_maxsize */
199 198
200/* 199/* The minimum size (in pages) of the free page cache. */
201 * The minimum size (in bytes) of the free page cache. 200static unsigned malloc_cache = 16;
202 */
203#ifndef malloc_cache
204static unsigned malloc_cache;
205#endif /* malloc_cache */
206 201
207/* 202/* The offset from pagenumber to index into the page directory */
208 * The offset from pagenumber to index into the page directory
209 */
210static u_long malloc_origo; 203static u_long malloc_origo;
211 204
212/* 205/* The last index in the page directory we care about */
213 * The last index in the page directory we care about
214 */
215static u_long last_index; 206static u_long last_index;
216 207
217/* 208/* Pointer to page directory. Allocated "as if with" malloc */
218 * Pointer to page directory.
219 * Allocated "as if with" malloc
220 */
221static struct pginfo **page_dir; 209static struct pginfo **page_dir;
222 210
223/* 211/* How many slots in the page directory */
224 * How many slots in the page directory
225 */
226static unsigned malloc_ninfo; 212static unsigned malloc_ninfo;
227 213
228/* 214/* Free pages line up here */
229 * Free pages line up here
230 */
231static struct pgfree free_list; 215static struct pgfree free_list;
232 216
233/* 217/* Abort(), user doesn't handle problems. */
234 * Abort() if we fail to get VM ?
235 */
236static int malloc_abort; 218static int malloc_abort;
237 219
238/* 220/* Are we trying to die ? */
239 * Are we trying to die ?
240 */
241static int suicide; 221static int suicide;
242 222
243#ifdef MALLOC_STATS 223#ifdef MALLOC_STATS
244/* 224/* dump statistics */
245 * dump statistics
246 */
247static int malloc_stats; 225static int malloc_stats;
248#endif /* MALLOC_STATS */ 226#endif /* MALLOC_STATS */
249 227
250/* 228/* always realloc ? */
251 * always realloc ?
252 */
253static int malloc_realloc; 229static int malloc_realloc;
254 230
255/* 231#ifdef __FreeBSD__
256 * zero fill ? 232/* pass the kernel a hint on free pages ? */
257 */ 233static int malloc_hint;
234#endif
235
236/* zero fill ? */
258static int malloc_zero; 237static int malloc_zero;
259 238
260/* 239/* junk fill ? */
261 * junk fill ?
262 */
263static int malloc_junk; 240static int malloc_junk;
264 241
265/* 242#ifdef __FreeBSD__
266 * my last break. 243/* utrace ? */
267 */ 244static int malloc_utrace;
245
246struct ut { void *p; size_t s; void *r; };
247
248#define UTRACE(a, b, c) \
249 if (malloc_utrace) \
250 {struct ut u; u.p=a; u.s = b; u.r=c; utrace(&u, sizeof u);}
251#else /* !__FreeBSD__ */
252#define UTRACE(a,b,c)
253#endif
254
255/* my last break. */
268static void *malloc_brk; 256static void *malloc_brk;
269 257
270/* 258/* one location cache for free-list holders */
271 * one location cache for free-list holders
272 */
273static struct pgfree *px; 259static struct pgfree *px;
274 260
261/* compile-time options */
262char *malloc_options;
263
275/* 264/*
276 * Necessary function declarations 265 * Necessary function declarations
277 */ 266 */
278static int extend_pgdir(u_long index); 267static int extend_pgdir(u_long index);
268static void *imalloc(size_t size);
269static void ifree(void *ptr);
270static void *irealloc(void *ptr, size_t size);
279 271
280#ifdef MALLOC_STATS 272#ifdef MALLOC_STATS
281void 273void
@@ -290,60 +282,63 @@ malloc_dump(fd)
290 282
291 /* print out all the pages */ 283 /* print out all the pages */
292 for(j=0;j<=last_index;j++) { 284 for(j=0;j<=last_index;j++) {
293 fprintf(fd,"%08lx %5d ",(j+malloc_origo) << malloc_pageshift,j); 285 fprintf(fd, "%08lx %5d ", (j+malloc_origo) << malloc_pageshift, j);
294 if (pd[j] == MALLOC_NOT_MINE) { 286 if (pd[j] == MALLOC_NOT_MINE) {
295 for(j++;j<=last_index && pd[j] == MALLOC_NOT_MINE;j++) 287 for(j++;j<=last_index && pd[j] == MALLOC_NOT_MINE;j++)
296 ; 288 ;
297 j--; 289 j--;
298 fprintf(fd,".. %5d not mine\n", j); 290 fprintf(fd, ".. %5d not mine\n", j);
299 } else if (pd[j] == MALLOC_FREE) { 291 } else if (pd[j] == MALLOC_FREE) {
300 for(j++;j<=last_index && pd[j] == MALLOC_FREE;j++) 292 for(j++;j<=last_index && pd[j] == MALLOC_FREE;j++)
301 ; 293 ;
302 j--; 294 j--;
303 fprintf(fd,".. %5d free\n", j); 295 fprintf(fd, ".. %5d free\n", j);
304 } else if (pd[j] == MALLOC_FIRST) { 296 } else if (pd[j] == MALLOC_FIRST) {
305 for(j++;j<=last_index && pd[j] == MALLOC_FOLLOW;j++) 297 for(j++;j<=last_index && pd[j] == MALLOC_FOLLOW;j++)
306 ; 298 ;
307 j--; 299 j--;
308 fprintf(fd,".. %5d in use\n", j); 300 fprintf(fd, ".. %5d in use\n", j);
309 } else if (pd[j] < MALLOC_MAGIC) { 301 } else if (pd[j] < MALLOC_MAGIC) {
310 fprintf(fd,"(%p)\n", pd[j]); 302 fprintf(fd, "(%p)\n", pd[j]);
311 } else { 303 } else {
312 fprintf(fd,"%p %d (of %d) x %d @ %p --> %p\n", 304 fprintf(fd, "%p %d (of %d) x %d @ %p --> %p\n",
313 pd[j],pd[j]->free, pd[j]->total, 305 pd[j], pd[j]->free, pd[j]->total,
314 pd[j]->size, pd[j]->page, pd[j]->next); 306 pd[j]->size, pd[j]->page, pd[j]->next);
315 } 307 }
316 } 308 }
317 309
318 for(pf=free_list.next; pf; pf=pf->next) { 310 for(pf=free_list.next; pf; pf=pf->next) {
319 fprintf(fd,"Free: @%p [%p...%p[ %ld ->%p <-%p\n", 311 fprintf(fd, "Free: @%p [%p...%p[ %ld ->%p <-%p\n",
320 pf,pf->page,pf->end,pf->size,pf->prev,pf->next); 312 pf, pf->page, pf->end, pf->size, pf->prev, pf->next);
321 if (pf == pf->next) { 313 if (pf == pf->next) {
322 fprintf(fd,"Free_list loops.\n"); 314+ fprintf(fd, "Free_list loops.\n");
323 break; 315 break;
324 } 316 }
325 } 317 }
326 318
327 /* print out various info */ 319 /* print out various info */
328 fprintf(fd,"Minsize\t%d\n",malloc_minsize); 320 fprintf(fd, "Minsize\t%d\n", malloc_minsize);
329 fprintf(fd,"Maxsize\t%d\n",malloc_maxsize); 321 fprintf(fd, "Maxsize\t%d\n", malloc_maxsize);
330 fprintf(fd,"Pagesize\t%d\n",malloc_pagesize); 322 fprintf(fd, "Pagesize\t%d\n", malloc_pagesize);
331 fprintf(fd,"Pageshift\t%d\n",malloc_pageshift); 323 fprintf(fd, "Pageshift\t%d\n", malloc_pageshift);
332 fprintf(fd,"FirstPage\t%ld\n",malloc_origo); 324 fprintf(fd, "FirstPage\t%ld\n", malloc_origo);
333 fprintf(fd,"LastPage\t%ld %lx\n",last_index+malloc_pageshift, 325 fprintf(fd, "LastPage\t%ld %lx\n", last_index+malloc_pageshift,
334 (last_index + malloc_pageshift) << malloc_pageshift); 326 (last_index + malloc_pageshift) << malloc_pageshift);
335 fprintf(fd,"Break\t%ld\n",(u_long)sbrk(0) >> malloc_pageshift); 327 fprintf(fd, "Break\t%ld\n", (u_long)sbrk(0) >> malloc_pageshift);
336} 328}
337#endif /* MALLOC_STATS */ 329#endif /* MALLOC_STATS */
338 330
331static char *malloc_func;
332
339static void 333static void
340wrterror(p) 334wrterror(p)
341 char *p; 335 char *p;
342{ 336{
343 char *q = "Malloc error: "; 337 char *q = "Malloc error: ";
344 suicide = 1; 338 suicide = 1;
345 write(2,q,strlen(q)); 339 write(2, q, strlen(q));
346 write(2,p,strlen(p)); 340 write(2, malloc_func, strlen(malloc_func));
341 write(2, p, strlen(p));
347#ifdef MALLOC_STATS 342#ifdef MALLOC_STATS
348 if (malloc_stats) 343 if (malloc_stats)
349 malloc_dump(stderr); 344 malloc_dump(stderr);
@@ -358,21 +353,22 @@ wrtwarning(p)
358 char *q = "Malloc warning: "; 353 char *q = "Malloc warning: ";
359 if (malloc_abort) 354 if (malloc_abort)
360 wrterror(p); 355 wrterror(p);
361 write(2,q,strlen(q)); 356 write(2, q, strlen(q));
362 write(2,p,strlen(p)); 357 write(2, malloc_func, strlen(malloc_func));
358 write(2, p, strlen(p));
363} 359}
364 360
365#ifdef EXTRA_SANITY 361#ifdef EXTRA_SANITY
366static void 362static void
367malloc_exit() 363malloc_exit()
368{ 364{
369 FILE *fd = fopen("malloc.out","a"); 365 FILE *fd = fopen("malloc.out", "a");
370 char *q = "malloc() warning: Couldn't dump stats.\n"; 366 char *q = "malloc() warning: Couldn't dump stats.\n";
371 if (fd) { 367 if (fd) {
372 malloc_dump(fd); 368 malloc_dump(fd);
373 fclose(fd); 369 fclose(fd);
374 } else 370 } else
375 write(2,q,strlen(q)); 371 write(2, q, strlen(q));
376} 372}
377#endif /* EXTRA_SANITY */ 373#endif /* EXTRA_SANITY */
378 374
@@ -384,14 +380,14 @@ static caddr_t
384map_pages(pages) 380map_pages(pages)
385 int pages; 381 int pages;
386{ 382{
387 caddr_t result,tail; 383 caddr_t result, tail;
388 384
389 result = (caddr_t)pageround((u_long)sbrk(0)); 385 result = (caddr_t)pageround((u_long)sbrk(0));
390 tail = result + (pages << malloc_pageshift); 386 tail = result + (pages << malloc_pageshift);
391 387
392 if (brk(tail)) { 388 if (brk(tail)) {
393#ifdef EXTRA_SANITY 389#ifdef EXTRA_SANITY
394 wrterror("(internal): map_pages fails\n"); 390 wrterror("(ES): map_pages fails\n");
395#endif /* EXTRA_SANITY */ 391#endif /* EXTRA_SANITY */
396 return 0; 392 return 0;
397 } 393 }
@@ -466,7 +462,7 @@ static int
466extend_pgdir(index) 462extend_pgdir(index)
467 u_long index; 463 u_long index;
468{ 464{
469 struct pginfo **new,**old; 465 struct pginfo **new, **old;
470 int i, oldlen; 466 int i, oldlen;
471 467
472 /* Make it this many pages */ 468 /* Make it this many pages */
@@ -520,35 +516,61 @@ extend_pgdir(index)
520static void 516static void
521malloc_init () 517malloc_init ()
522{ 518{
523 char *p; 519 char *p, b[64];
520 int i, j;
524 521
525#ifdef EXTRA_SANITY 522#ifdef EXTRA_SANITY
526 malloc_junk = 1; 523 malloc_junk = 1;
527#endif /* EXTRA_SANITY */ 524#endif /* EXTRA_SANITY */
528 525
529 if (issetugid() == 0) { 526 for (i = 0; i < 3; i++) {
530 for (p=getenv("MALLOC_OPTIONS"); p && *p; p++) { 527 if (i == 0) {
528 j = readlink("/etc/malloc.conf", b, sizeof b - 1);
529 if (j <= 0)
530 continue;
531 b[j] = '\0';
532 p = b;
533 } else if (i == 1) {
534 p = getenv("MALLOC_OPTIONS");
535 } else if (i == 2) {
536 p = malloc_options;
537 }
538 for (; p && *p; p++) {
531 switch (*p) { 539 switch (*p) {
532 case 'a': malloc_abort = 0; break; 540 case '>': malloc_cache <<= 1; break;
533 case 'A': malloc_abort = 1; break; 541 case '<': malloc_cache >>= 1; break;
542 case 'a': malloc_abort = 0; break;
543 case 'A': malloc_abort = 1; break;
534#ifdef MALLOC_STATS 544#ifdef MALLOC_STATS
535 case 'd': malloc_stats = 0; break; 545 case 'd': malloc_stats = 0; break;
536 case 'D': malloc_stats = 1; break; 546 case 'D': malloc_stats = 1; break;
537#endif /* MALLOC_STATS */ 547#endif /* MALLOC_STATS */
538 case 'r': malloc_realloc = 0; break; 548#ifdef __FreeBSD__
539 case 'R': malloc_realloc = 1; break; 549 case 'h': malloc_hint = 0; break;
540 case 'j': malloc_junk = 0; break; 550 case 'H': malloc_hint = 1; break;
541 case 'J': malloc_junk = 1; break; 551#endif /* __FreeBSD__ */
542 case 'z': malloc_zero = 0; break; 552 case 'r': malloc_realloc = 0; break;
543 case 'Z': malloc_zero = 1; break; 553 case 'R': malloc_realloc = 1; break;
544 default: 554 case 'j': malloc_junk = 0; break;
545 wrtwarning("(Init): Unknown char in MALLOC_OPTIONS\n"); 555 case 'J': malloc_junk = 1; break;
546 p = 0; 556#ifdef __FreeBSD__
547 break; 557 case 'u': malloc_utrace = 0; break;
558 case 'U': malloc_utrace = 1; break;
559#endif /* __FreeBSD__ */
560 case 'z': malloc_zero = 0; break;
561 case 'Z': malloc_zero = 1; break;
562 default:
563 j = malloc_abort;
564 malloc_abort = 0;
565 wrtwarning("unknown char in MALLOC_OPTIONS\n");
566 malloc_abort = j;
567 break;
548 } 568 }
549 } 569 }
550 } 570 }
551 571
572 UTRACE(0, 0, 0);
573
552 /* 574 /*
553 * We want junk in the entire allocation, and zero only in the part 575 * We want junk in the entire allocation, and zero only in the part
554 * the user asked for. 576 * the user asked for.
@@ -579,10 +601,6 @@ malloc_init ()
579 } 601 }
580#endif /* malloc_pageshift */ 602#endif /* malloc_pageshift */
581 603
582#ifndef malloc_cache
583 malloc_cache = 100 << malloc_pageshift;
584#endif /* malloc_cache */
585
586#ifndef malloc_minsize 604#ifndef malloc_minsize
587 { 605 {
588 int i; 606 int i;
@@ -612,7 +630,7 @@ malloc_init ()
612 page_dir = (struct pginfo **) mmap(0, malloc_pagesize, PROT_READ|PROT_WRITE, 630 page_dir = (struct pginfo **) mmap(0, malloc_pagesize, PROT_READ|PROT_WRITE,
613 MAP_ANON|MAP_PRIVATE, -1, (off_t)0); 631 MAP_ANON|MAP_PRIVATE, -1, (off_t)0);
614 if (page_dir == (struct pginfo **) -1) 632 if (page_dir == (struct pginfo **) -1)
615 wrterror("(Init) my first mmap failed. (check limits ?)\n"); 633 wrterror("mmap(2) failed, check limits.\n");
616 634
617 /* 635 /*
618 * We need a maximum of malloc_pageshift buckets, steal these from the 636 * We need a maximum of malloc_pageshift buckets, steal these from the
@@ -630,7 +648,12 @@ malloc_init ()
630 * This is a nice hack from Kaleb Keithly (kaleb@x.org). 648 * This is a nice hack from Kaleb Keithly (kaleb@x.org).
631 * We can sbrk(2) further back when we keep this on a low address. 649 * We can sbrk(2) further back when we keep this on a low address.
632 */ 650 */
633 px = (struct pgfree *) malloc (sizeof *px); 651 px = (struct pgfree *) imalloc (sizeof *px);
652
653 if (!malloc_cache)
654 malloc_cache++;
655
656 malloc_cache <<= malloc_pageshift;
634} 657}
635 658
636/* 659/*
@@ -640,7 +663,7 @@ void *
640malloc_pages(size) 663malloc_pages(size)
641 size_t size; 664 size_t size;
642{ 665{
643 void *p,*delay_free = 0; 666 void *p, *delay_free = 0;
644 int i; 667 int i;
645 struct pgfree *pf; 668 struct pgfree *pf;
646 u_long index; 669 u_long index;
@@ -705,14 +728,14 @@ malloc_pages(size)
705 page_dir[index+i] = MALLOC_FOLLOW; 728 page_dir[index+i] = MALLOC_FOLLOW;
706 729
707 if (malloc_junk) 730 if (malloc_junk)
708 memset(p, SOME_JUNK,size << malloc_pageshift); 731 memset(p, SOME_JUNK, size << malloc_pageshift);
709 } 732 }
710 733
711 if (delay_free) { 734 if (delay_free) {
712 if (!px) 735 if (!px)
713 px = delay_free; 736 px = delay_free;
714 else 737 else
715 free(delay_free); 738 ifree(delay_free);
716 } 739 }
717 740
718 return p; 741 return p;
@@ -728,7 +751,7 @@ malloc_make_chunks(bits)
728{ 751{
729 struct pginfo *bp; 752 struct pginfo *bp;
730 void *pp; 753 void *pp;
731 int i,k,l; 754 int i, k, l;
732 755
733 /* Allocate a new bucket */ 756 /* Allocate a new bucket */
734 pp = malloc_pages(malloc_pagesize); 757 pp = malloc_pages(malloc_pagesize);
@@ -744,7 +767,7 @@ malloc_make_chunks(bits)
744 if ((1<<(bits)) <= l+l) { 767 if ((1<<(bits)) <= l+l) {
745 bp = (struct pginfo *)pp; 768 bp = (struct pginfo *)pp;
746 } else { 769 } else {
747 bp = (struct pginfo *)malloc(l); 770 bp = (struct pginfo *)imalloc(l);
748 if (!bp) 771 if (!bp)
749 return 0; 772 return 0;
750 } 773 }
@@ -768,12 +791,12 @@ malloc_make_chunks(bits)
768 bp->bits[i / MALLOC_BITS] = (u_long)~0; 791 bp->bits[i / MALLOC_BITS] = (u_long)~0;
769 792
770 for(; i < k; i++) 793 for(; i < k; i++)
771 set_bit(bp,i); 794 set_bit(bp, i);
772 795
773 if (bp == bp->page) { 796 if (bp == bp->page) {
774 /* Mark the ones we stole for ourselves */ 797 /* Mark the ones we stole for ourselves */
775 for(i=0;l > 0;i++) { 798 for(i=0;l > 0;i++) {
776 clr_bit(bp,i); 799 clr_bit(bp, i);
777 bp->free--; 800 bp->free--;
778 bp->total--; 801 bp->total--;
779 l -= (1 << bits); 802 l -= (1 << bits);
@@ -835,8 +858,8 @@ malloc_bytes(size)
835/* 858/*
836 * Allocate a piece of memory 859 * Allocate a piece of memory
837 */ 860 */
838void * 861static void *
839malloc(size) 862imalloc(size)
840 size_t size; 863 size_t size;
841{ 864{
842 void *result; 865 void *result;
@@ -850,36 +873,30 @@ malloc(size)
850 if (suicide) 873 if (suicide)
851 abort(); 874 abort();
852 875
853#ifdef _THREAD_SAFE
854 _thread_kern_sig_block(&status);
855#endif
856 if (size <= malloc_maxsize) 876 if (size <= malloc_maxsize)
857 result = malloc_bytes(size); 877 result = malloc_bytes(size);
858 else 878 else
859 result = malloc_pages(size); 879 result = malloc_pages(size);
860 880
861 if (malloc_abort && !result) 881 if (malloc_abort && !result)
862 wrterror("malloc(): returns NULL\n"); 882 wrterror("allocation failed.\n");
863 883
864 if (malloc_zero) 884 if (malloc_zero)
865 memset(result,0,size); 885 memset(result, 0, size);
866 886
867#ifdef _THREAD_SAFE
868 _thread_kern_sig_unblock(status);
869#endif
870 return result; 887 return result;
871} 888}
872 889
873/* 890/*
874 * Change the size of an allocation. 891 * Change the size of an allocation.
875 */ 892 */
876void * 893static void *
877realloc(ptr, size) 894irealloc(ptr, size)
878 void *ptr; 895 void *ptr;
879 size_t size; 896 size_t size;
880{ 897{
881 void *p; 898 void *p;
882 u_long osize,index; 899 u_long osize, index;
883 struct pginfo **mp; 900 struct pginfo **mp;
884 int i; 901 int i;
885#ifdef _THREAD_SAFE 902#ifdef _THREAD_SAFE
@@ -889,37 +906,20 @@ realloc(ptr, size)
889 if (suicide) 906 if (suicide)
890 return 0; 907 return 0;
891 908
892 if (!ptr) /* Bounce to malloc() */
893 return malloc(size);
894
895 if (!initialized) { 909 if (!initialized) {
896 wrtwarning("realloc(): malloc() never got called.\n"); 910 wrtwarning("malloc() has never been called.\n");
897 return 0;
898 }
899
900 if (ptr && !size) { /* Bounce to free() */
901 free(ptr);
902 return 0; 911 return 0;
903 } 912 }
904 913
905#ifdef _THREAD_SAFE
906 _thread_kern_sig_block(&status);
907#endif
908 index = ptr2index(ptr); 914 index = ptr2index(ptr);
909 915
910 if (index < malloc_pageshift) { 916 if (index < malloc_pageshift) {
911 wrtwarning("realloc(): junk pointer (too low)\n"); 917 wrtwarning("junk pointer, too low to make sense.\n");
912#ifdef _THREAD_SAFE
913 _thread_kern_sig_unblock(status);
914#endif
915 return 0; 918 return 0;
916 } 919 }
917 920
918 if (index > last_index) { 921 if (index > last_index) {
919 wrtwarning("realloc(): junk pointer (too high)\n"); 922 wrtwarning("junk pointer, too high to make sense.\n");
920#ifdef _THREAD_SAFE
921 _thread_kern_sig_unblock(status);
922#endif
923 return 0; 923 return 0;
924 } 924 }
925 925
@@ -929,10 +929,7 @@ realloc(ptr, size)
929 929
930 /* Check the pointer */ 930 /* Check the pointer */
931 if ((u_long)ptr & malloc_pagemask) { 931 if ((u_long)ptr & malloc_pagemask) {
932 wrtwarning("realloc(): modified page pointer.\n"); 932 wrtwarning("modified (page-) pointer.\n");
933#ifdef _THREAD_SAFE
934 _thread_kern_sig_unblock(status);
935#endif
936 return 0; 933 return 0;
937 } 934 }
938 935
@@ -943,9 +940,6 @@ realloc(ptr, size)
943 if (!malloc_realloc && /* unless we have to, */ 940 if (!malloc_realloc && /* unless we have to, */
944 size <= osize && /* .. or are too small, */ 941 size <= osize && /* .. or are too small, */
945 size > (osize - malloc_pagesize)) { /* .. or can free a page, */ 942 size > (osize - malloc_pagesize)) { /* .. or can free a page, */
946#ifdef _THREAD_SAFE
947 _thread_kern_sig_unblock(status);
948#endif
949 return ptr; /* don't do anything. */ 943 return ptr; /* don't do anything. */
950 } 944 }
951 945
@@ -953,10 +947,7 @@ realloc(ptr, size)
953 947
954 /* Check the pointer for sane values */ 948 /* Check the pointer for sane values */
955 if (((u_long)ptr & ((*mp)->size-1))) { 949 if (((u_long)ptr & ((*mp)->size-1))) {
956 wrtwarning("realloc(): modified chunk pointer.\n"); 950 wrtwarning("modified (chunk-) pointer.\n");
957#ifdef _THREAD_SAFE
958 _thread_kern_sig_unblock(status);
959#endif
960 return 0; 951 return 0;
961 } 952 }
962 953
@@ -964,11 +955,8 @@ realloc(ptr, size)
964 i = ((u_long)ptr & malloc_pagemask) >> (*mp)->shift; 955 i = ((u_long)ptr & malloc_pagemask) >> (*mp)->shift;
965 956
966 /* Verify that it isn't a free chunk already */ 957 /* Verify that it isn't a free chunk already */
967 if (tst_bit(*mp,i)) { 958 if (tst_bit(*mp, i)) {
968 wrtwarning("realloc(): already free chunk.\n"); 959 wrtwarning("chunk is already free.\n");
969#ifdef _THREAD_SAFE
970 _thread_kern_sig_unblock(status);
971#endif
972 return 0; 960 return 0;
973 } 961 }
974 962
@@ -978,33 +966,24 @@ realloc(ptr, size)
978 size < osize && /* ..or are too small, */ 966 size < osize && /* ..or are too small, */
979 (size > osize/2 || /* ..or could use a smaller size, */ 967 (size > osize/2 || /* ..or could use a smaller size, */
980 osize == malloc_minsize)) { /* ..(if there is one) */ 968 osize == malloc_minsize)) { /* ..(if there is one) */
981#ifdef _THREAD_SAFE
982 _thread_kern_sig_unblock(status);
983#endif
984 return ptr; /* ..Don't do anything */ 969 return ptr; /* ..Don't do anything */
985 } 970 }
986 971
987 } else { 972 } else {
988 wrtwarning("realloc(): wrong page pointer.\n"); 973 wrtwarning("pointer to wrong page.\n");
989#ifdef _THREAD_SAFE
990 _thread_kern_sig_unblock(status);
991#endif
992 return 0; 974 return 0;
993 } 975 }
994 976
995 p = malloc(size); 977 p = imalloc(size);
996 978
997 if (p) { 979 if (p) {
998 /* copy the lesser of the two sizes, and free the old one */ 980 /* copy the lesser of the two sizes, and free the old one */
999 if (osize < size) 981 if (osize < size)
1000 memcpy(p,ptr,osize); 982 memcpy(p, ptr, osize);
1001 else 983 else
1002 memcpy(p,ptr,size); 984 memcpy(p, ptr, size);
1003 free(ptr); 985 ifree(ptr);
1004 } 986 }
1005#ifdef _THREAD_SAFE
1006 _thread_kern_sig_unblock(status);
1007#endif
1008 return p; 987 return p;
1009} 988}
1010 989
@@ -1019,22 +998,22 @@ free_pages(ptr, index, info)
1019 struct pginfo *info; 998 struct pginfo *info;
1020{ 999{
1021 int i; 1000 int i;
1022 struct pgfree *pf,*pt=0; 1001 struct pgfree *pf, *pt=0;
1023 u_long l; 1002 u_long l;
1024 void *tail; 1003 void *tail;
1025 1004
1026 if (info == MALLOC_FREE) { 1005 if (info == MALLOC_FREE) {
1027 wrtwarning("free(): already free page.\n"); 1006 wrtwarning("page is already free.\n");
1028 return; 1007 return;
1029 } 1008 }
1030 1009
1031 if (info != MALLOC_FIRST) { 1010 if (info != MALLOC_FIRST) {
1032 wrtwarning("free(): freeing wrong page.\n"); 1011 wrtwarning("pointer to wrong page.\n");
1033 return; 1012 return;
1034 } 1013 }
1035 1014
1036 if ((u_long)ptr & malloc_pagemask) { 1015 if ((u_long)ptr & malloc_pagemask) {
1037 wrtwarning("free(): modified page pointer.\n"); 1016 wrtwarning("modified (page-) pointer.\n");
1038 return; 1017 return;
1039 } 1018 }
1040 1019
@@ -1045,11 +1024,16 @@ free_pages(ptr, index, info)
1045 1024
1046 l = i << malloc_pageshift; 1025 l = i << malloc_pageshift;
1047 1026
1048 tail = (char *)ptr + l; 1027#ifdef __FreeBSD__
1028 if (malloc_hint)
1029 madvise(ptr, l, MADV_FREE);
1030#endif
1031
1032 tail = (char *)ptr+l;
1049 1033
1050 /* add to free-list */ 1034 /* add to free-list */
1051 if (!px) 1035 if (!px)
1052 px = malloc(sizeof *pt); /* This cannot fail... */ 1036 px = imalloc(sizeof *pt); /* This cannot fail... */
1053 px->page = ptr; 1037 px->page = ptr;
1054 px->end = tail; 1038 px->end = tail;
1055 px->size = l; 1039 px->size = l;
@@ -1065,7 +1049,7 @@ free_pages(ptr, index, info)
1065 } else { 1049 } else {
1066 1050
1067 /* Find the right spot, leave pf pointing to the modified entry. */ 1051 /* Find the right spot, leave pf pointing to the modified entry. */
1068 tail = (char *)ptr + l; 1052 tail = (char *)ptr+l;
1069 1053
1070 for(pf = free_list.next; pf->end < ptr && pf->next; pf = pf->next) 1054 for(pf = free_list.next; pf->end < ptr && pf->next; pf = pf->next)
1071 ; /* Race ahead here */ 1055 ; /* Race ahead here */
@@ -1103,7 +1087,7 @@ free_pages(ptr, index, info)
1103 pf = px; 1087 pf = px;
1104 px = 0; 1088 px = 0;
1105 } else { 1089 } else {
1106 wrterror("messed up free list"); 1090 wrterror("freelist is destroyed.\n");
1107 } 1091 }
1108 } 1092 }
1109 1093
@@ -1132,7 +1116,7 @@ free_pages(ptr, index, info)
1132 /* XXX: We could realloc/shrink the pagedir here I guess. */ 1116 /* XXX: We could realloc/shrink the pagedir here I guess. */
1133 } 1117 }
1134 if (pt) 1118 if (pt)
1135 free(pt); 1119 ifree(pt);
1136} 1120}
1137 1121
1138/* 1122/*
@@ -1154,16 +1138,16 @@ free_bytes(ptr, index, info)
1154 i = ((u_long)ptr & malloc_pagemask) >> info->shift; 1138 i = ((u_long)ptr & malloc_pagemask) >> info->shift;
1155 1139
1156 if (((u_long)ptr & (info->size-1))) { 1140 if (((u_long)ptr & (info->size-1))) {
1157 wrtwarning("free(): modified pointer.\n"); 1141 wrtwarning("modified (chunk-) pointer.\n");
1158 return; 1142 return;
1159 } 1143 }
1160 1144
1161 if (tst_bit(info,i)) { 1145 if (tst_bit(info, i)) {
1162 wrtwarning("free(): already free chunk.\n"); 1146 wrtwarning("chunk is already free.\n");
1163 return; 1147 return;
1164 } 1148 }
1165 1149
1166 set_bit(info,i); 1150 set_bit(info, i);
1167 info->free++; 1151 info->free++;
1168 1152
1169 mp = page_dir + info->shift; 1153 mp = page_dir + info->shift;
@@ -1198,12 +1182,12 @@ free_bytes(ptr, index, info)
1198 page_dir[ptr2index(info->page)] = MALLOC_FIRST; 1182 page_dir[ptr2index(info->page)] = MALLOC_FIRST;
1199 vp = info->page; /* Order is important ! */ 1183 vp = info->page; /* Order is important ! */
1200 if(vp != (void*)info) 1184 if(vp != (void*)info)
1201 free(info); 1185 ifree(info);
1202 free(vp); 1186 ifree(vp);
1203} 1187}
1204 1188
1205void 1189static void
1206free(ptr) 1190ifree(ptr)
1207 void *ptr; 1191 void *ptr;
1208{ 1192{
1209 struct pginfo *info; 1193 struct pginfo *info;
@@ -1217,7 +1201,7 @@ free(ptr)
1217 return; 1201 return;
1218 1202
1219 if (!initialized) { 1203 if (!initialized) {
1220 wrtwarning("free(): malloc() never got called.\n"); 1204 wrtwarning("malloc() has never been called.\n");
1221 return; 1205 return;
1222 } 1206 }
1223 1207
@@ -1225,35 +1209,102 @@ free(ptr)
1225 if (suicide) 1209 if (suicide)
1226 return; 1210 return;
1227 1211
1228#ifdef _THREAD_SAFE
1229 _thread_kern_sig_block(&status);
1230#endif
1231 index = ptr2index(ptr); 1212 index = ptr2index(ptr);
1232 1213
1233 if (index < malloc_pageshift) { 1214 if (index < malloc_pageshift) {
1234 wrtwarning("free(): junk pointer (too low)\n"); 1215 wrtwarning("junk pointer, too low to make sense.\n");
1235#ifdef _THREAD_SAFE
1236 _thread_kern_sig_unblock(status);
1237#endif
1238 return; 1216 return;
1239 } 1217 }
1240 1218
1241 if (index > last_index) { 1219 if (index > last_index) {
1242 wrtwarning("free(): junk pointer (too high)\n"); 1220 wrtwarning("junk pointer, too high to make sense.\n");
1243#ifdef _THREAD_SAFE
1244 _thread_kern_sig_unblock(status);
1245#endif
1246 return; 1221 return;
1247 } 1222 }
1248 1223
1249 info = page_dir[index]; 1224 info = page_dir[index];
1250 1225
1251 if (info < MALLOC_MAGIC) 1226 if (info < MALLOC_MAGIC)
1252 free_pages(ptr,index,info); 1227 free_pages(ptr, index, info);
1253 else 1228 else
1254 free_bytes(ptr,index,info); 1229 free_bytes(ptr, index, info);
1255#ifdef _THREAD_SAFE 1230 return;
1256 _thread_kern_sig_unblock(status); 1231}
1232
1233/*
1234 * These are the public exported interface routines.
1235 */
1236
1237#ifdef _THREAD_SAFE
1238#include <pthread.h>
1239#include "pthread_private.h"
1240static int malloc_lock;
1241#define THREAD_LOCK() _thread_kern_sig_block(&malloc_lock);
1242#define THREAD_UNLOCK() _thread_kern_sig_unblock(&malloc_lock);
1243#else
1244#define THREAD_LOCK()
1245#define THREAD_UNLOCK()
1257#endif 1246#endif
1247
1248static int malloc_active;
1249
1250void *
1251malloc(size_t size)
1252{
1253 register void *r;
1254
1255 malloc_func = "malloc():";
1256 THREAD_LOCK();
1257 if (malloc_active++) {
1258 wrtwarning("recursive call.\n");
1259 malloc_active--;
1260 return (0);
1261 }
1262 r = imalloc(size);
1263 UTRACE(0, size, r);
1264 malloc_active--;
1265 THREAD_UNLOCK();
1266 return (r);
1267}
1268
1269void
1270free(void *ptr)
1271{
1272 malloc_func = "free():";
1273 THREAD_LOCK();
1274 if (malloc_active++) {
1275 wrtwarning("recursive call.\n");
1276 malloc_active--;
1277 return;
1278 }
1279 ifree(ptr);
1280 UTRACE(ptr, 0, 0);
1281 malloc_active--;
1282 THREAD_UNLOCK();
1258 return; 1283 return;
1259} 1284}
1285
1286void *
1287realloc(void *ptr, size_t size)
1288{
1289 register void *r;
1290
1291 malloc_func = "realloc():";
1292 THREAD_LOCK();
1293 if (malloc_active++) {
1294 wrtwarning("recursive call.\n");
1295 malloc_active--;
1296 return (0);
1297 }
1298 if (!ptr) {
1299 r = imalloc(size);
1300 } else if (ptr && !size) {
1301 ifree(ptr);
1302 r = 0;
1303 } else {
1304 r = irealloc(ptr, size);
1305 }
1306 UTRACE(ptr, size, r);
1307 malloc_active--;
1308 THREAD_UNLOCK();
1309 return (r);
1310}