diff --git a/src/lib/libc/stdlib/malloc.3 b/src/lib/libc/stdlib/malloc.3 index 979e7701..e206245c 100644 --- a/src/lib/libc/stdlib/malloc.3 +++ b/src/lib/libc/stdlib/malloc.3 @@ -33,11 +33,11 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $OpenBSD: malloc.3,v 1.3 1996/08/21 03:12:18 downsj Exp $ +.\" $OpenBSD: malloc.3,v 1.4 1996/09/26 04:19:41 tholo Exp $ .\" -.Dd June 4, 1993 +.Dd August 27, 1996 .Dt MALLOC 3 -.Os BSD 4 +.Os OpenBSD .Sh NAME .Nm malloc , .Nd general memory allocation function @@ -58,6 +58,8 @@ .Fn cfree "void *ptr" .Ft void * .Fn realloc "void *ptr" "size_t size" +.Ft char * +.Va malloc_options .Sh DESCRIPTION The .Fn malloc @@ -120,11 +122,13 @@ is zero and .Fa ptr is not a null pointer, the object it points to is freed. .Pp - -.Sh ENVIRONMENT -This malloc will check the environment for a variable called -.Em MALLOC_OPTIONS -and scan it for flags. +Malloc will first look for a symbolic link called +.Pa /etc/malloc.conf +and next check the environment for a variable called +.Ev MALLOC_OPTIONS +and finally for the global variable +.Va malloc_options +and scan them for flags in that order. Flags are single letters, uppercase means on, lowercase means off. .Bl -tag -width indent .It A @@ -142,21 +146,42 @@ order to have any effect. ``junk'' fill some junk into the area allocated. Currently junk is bytes of 0xd0, this is pronounced ``Duh'' :-) +.It H +``hint'' pass a hint to the kernel about pages we don't use. If the +machine is paging a lot this may help a bit. + .It R ``realloc'' always reallocate when .Fn realloc is called, even if the initial allocation was big enough. This can substantially aid in compacting memory. +.It U +``utrace'' generate entries for ktrace(1) for all operations. +Consult the source for this one. + .It Z ``zero'' fill some junk into the area allocated (see ``J''), except for the exact length the user asked for, which is zeroed. +.It < +``Half the cache size'' Reduce the size of the cache by a factor of two. + +.It > +``Double the cache size'' Double the size of the cache by a factor of two. .El .Pp +So to set a systemwide reduction of cache size and coredumps on problems +one would: +.Li ln -s 'A<' /etc/malloc.conf +.Pp The ``J'' and ``Z'' is mostly for testing and debugging, if a program changes behavior if either of these options are used, it is buggy. +.Pp +The default cache size is 16 pages. +.Sh ENVIRONMENT +See above. .Sh RETURN VALUES The .Fn malloc @@ -172,12 +197,89 @@ The .Fn realloc function returns either a null pointer or a pointer to the possibly moved allocated space. +.Sh MESSAGES +If +.Fn malloc , +.Fn free +or +.Fn realloc +detects an error or warning condition, +a message will be printed to filedescriptor +2 (not using stdio). +Errors will always result in the process being +.Xr abort 2 'ed, +If the ``A'' option has been specified, also warnings will +.Xr abort 2 +the process. +.Pp +Here is a brief description of the error messages and what they mean: +.Pp +``(ES): mumble mumble mumble'': +malloc have been compiled with -DEXTRA_SANITY and something looks +fishy in there. Consult sources and or wizards. +.Pp +``allocation failed'' +if the ``A'' option is specified it is an error for +.Fn malloc +or +.Fn realloc +to return NULL. +.Pp +``mmap(2) failed, check limits.'' +This is a rather weird condition that is most likely to mean that +the system is seriously overloaded or that your ulimits are sick. +.Pp +``freelist is destroyed.'' +mallocs internal freelist has been stomped on. +.Pp +Here is a brief description of the warning messages and what they mean: +.Pp +``chunk/page is already free.'' +A pointer to a free chunk is attempted freed again. +.Pp +``junk pointer, too high to make sense.'' +The pointer doesn't make sense. It's above the area of memory that +malloc knows something about. +This could be a pointer from some +.Xr mmap 2 'ed +memory. +.Pp +``junk pointer, too low to make sense.'' +The pointer doesn't make sense. It's below the area of memory that +malloc knows something about. +This pointer probably came from your data or bss segments. +.Pp +``malloc() has never been called.'' +Nothing has ever been allocated, yet something is being freed or +realloc'ed. +.Pp +``modified (chunk-/page-) pointer.'' +The pointer passed to free or realloc has been modified. +.Pp +``pointer to wrong page.'' +The pointer that malloc is trying to free is not pointing to +a sensible page. +.Pp +``recursive call.'' +You have tried to call recursively into these functions. +I can only imagine this as happening if you call one of these +functions from a signal function, which happens to be called +while you're already in here. +Well, sorry to say: that's not supported. +If this is a problem for you I'd like to hear about it. It +would be possible to add a sigblock() around this package, +but it would have a performance penalty that is not acceptable +as the default. +.Pp +``unknown char in MALLOC_OPTIONS'' +we found something we didn't understand. .Sh SEE ALSO .Xr brk 2 , .Xr alloca 3 , .Xr calloc 3 , .Xr getpagesize 3 , .Xr memory 3 +.Pa /usr/share/doc/papers/malloc.ascii.gz .Sh STANDARDS The .Fn malloc diff --git a/src/lib/libc/stdlib/malloc.c b/src/lib/libc/stdlib/malloc.c index bff70c7b..a6f60b3f 100644 --- a/src/lib/libc/stdlib/malloc.c +++ b/src/lib/libc/stdlib/malloc.c @@ -8,12 +8,15 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static char rcsid[] = "$OpenBSD: malloc.c,v 1.13 1996/09/19 20:38:48 tholo Exp $"; +static char rcsid[] = "$OpenBSD: malloc.c,v 1.14 1996/09/26 04:19:42 tholo Exp $"; #endif /* LIBC_SCCS and not lint */ /* - * Defining EXTRA_SANITY will enable some checks which are related - * to internal conditions and consistency in malloc.c + * Defining EXTRA_SANITY will enable extra checks which are related + * to internal conditions and consistency in malloc.c. This has a + * noticeable runtime performance hit, and generally will not do you + * any good unless you fiddle with the internals of malloc or want + * to catch random pointer corruption as early as possible. */ #undef EXTRA_SANITY @@ -29,23 +32,23 @@ static char rcsid[] = "$OpenBSD: malloc.c,v 1.13 1996/09/19 20:38:48 tholo Exp $ #endif /* - * What to use for Junk + * What to use for Junk. This is the byte value we use to fill with + * when the 'J' option is enabled. */ #define SOME_JUNK 0xd0 /* as in "Duh" :-) */ +/* + * No user serviceable parts behind this point. + */ + #include #include +#include #include -#include #include -#include #include #include #include -#ifdef _THREAD_SAFE -#include -#include "pthread_private.h" -#endif /* * If these weren't defined here, they would be calculated on the fly, @@ -108,14 +111,14 @@ struct pgfree { * We might as well use them. There are C-language backups, but * they are considerably slower. */ -#ifdef __i386__ +#if defined(__i386__) && defined(__GNUC__) #define ffs _ffs static __inline int _ffs(input) unsigned input; { int result; - __asm("bsfl %1,%0" : "=r" (result) : "r" (input)); + __asm("bsfl %1, %0" : "=r" (result) : "r" (input)); return result+1; } @@ -125,7 +128,7 @@ _fls(input) unsigned input; { int result; - __asm("bsrl %1,%0" : "=r" (result) : "r" (input)); + __asm("bsrl %1, %0" : "=r" (result) : "r" (input)); return result+1; } @@ -135,7 +138,7 @@ _set_bit(pi, bit) struct pginfo *pi; int bit; { - __asm("btsl %0,(%1)" : + __asm("btsl %0, (%1)" : : "r" (bit & (MALLOC_BITS-1)), "r" (pi->bits+(bit/MALLOC_BITS))); } @@ -145,11 +148,11 @@ _clr_bit(pi, bit) struct pginfo *pi; int bit; { - __asm("btcl %0,(%1)" : + __asm("btcl %0, (%1)" : : "r" (bit & (MALLOC_BITS-1)), "r" (pi->bits+(bit/MALLOC_BITS))); } -#endif /* __i386__ */ +#endif /* __i386__ && __GNUC__ */ /* * Set to one when malloc_init has been called @@ -165,17 +168,13 @@ static unsigned initialized; static unsigned malloc_pagesize; #endif /* malloc_pagesize */ -/* - * A mask for the offset inside a page. - */ +/* A mask for the offset inside a page. */ #define malloc_pagemask ((malloc_pagesize)-1) #define pageround(foo) (((foo) + (malloc_pagemask))&(~(malloc_pagemask))) #define ptr2index(foo) (((u_long)(foo) >> malloc_pageshift)-malloc_origo) -/* - * malloc_pagesize == 1 << malloc_pageshift - */ +/* malloc_pagesize == 1 << malloc_pageshift */ #ifndef malloc_pageshift static unsigned malloc_pageshift; #endif /* malloc_pageshift */ @@ -197,85 +196,78 @@ static unsigned malloc_minsize; static unsigned malloc_maxsize; #endif /* malloc_maxsize */ -/* - * The minimum size (in bytes) of the free page cache. - */ -#ifndef malloc_cache -static unsigned malloc_cache; -#endif /* malloc_cache */ +/* The minimum size (in pages) of the free page cache. */ +static unsigned malloc_cache = 16; -/* - * The offset from pagenumber to index into the page directory - */ +/* The offset from pagenumber to index into the page directory */ static u_long malloc_origo; -/* - * The last index in the page directory we care about - */ +/* The last index in the page directory we care about */ static u_long last_index; -/* - * Pointer to page directory. - * Allocated "as if with" malloc - */ +/* Pointer to page directory. Allocated "as if with" malloc */ static struct pginfo **page_dir; -/* - * How many slots in the page directory - */ +/* How many slots in the page directory */ static unsigned malloc_ninfo; -/* - * Free pages line up here - */ +/* Free pages line up here */ static struct pgfree free_list; -/* - * Abort() if we fail to get VM ? - */ +/* Abort(), user doesn't handle problems. */ static int malloc_abort; -/* - * Are we trying to die ? - */ +/* Are we trying to die ? */ static int suicide; #ifdef MALLOC_STATS -/* - * dump statistics - */ +/* dump statistics */ static int malloc_stats; #endif /* MALLOC_STATS */ -/* - * always realloc ? - */ +/* always realloc ? */ static int malloc_realloc; -/* - * zero fill ? - */ +#ifdef __FreeBSD__ +/* pass the kernel a hint on free pages ? */ +static int malloc_hint; +#endif + +/* zero fill ? */ static int malloc_zero; -/* - * junk fill ? - */ +/* junk fill ? */ static int malloc_junk; -/* - * my last break. - */ +#ifdef __FreeBSD__ +/* utrace ? */ +static int malloc_utrace; + +struct ut { void *p; size_t s; void *r; }; + +#define UTRACE(a, b, c) \ + if (malloc_utrace) \ + {struct ut u; u.p=a; u.s = b; u.r=c; utrace(&u, sizeof u);} +#else /* !__FreeBSD__ */ +#define UTRACE(a,b,c) +#endif + +/* my last break. */ static void *malloc_brk; -/* - * one location cache for free-list holders - */ +/* one location cache for free-list holders */ static struct pgfree *px; +/* compile-time options */ +char *malloc_options; + /* * Necessary function declarations */ static int extend_pgdir(u_long index); +static void *imalloc(size_t size); +static void ifree(void *ptr); +static void *irealloc(void *ptr, size_t size); #ifdef MALLOC_STATS void @@ -290,60 +282,63 @@ malloc_dump(fd) /* print out all the pages */ for(j=0;j<=last_index;j++) { - fprintf(fd,"%08lx %5d ",(j+malloc_origo) << malloc_pageshift,j); + fprintf(fd, "%08lx %5d ", (j+malloc_origo) << malloc_pageshift, j); if (pd[j] == MALLOC_NOT_MINE) { for(j++;j<=last_index && pd[j] == MALLOC_NOT_MINE;j++) ; j--; - fprintf(fd,".. %5d not mine\n", j); + fprintf(fd, ".. %5d not mine\n", j); } else if (pd[j] == MALLOC_FREE) { for(j++;j<=last_index && pd[j] == MALLOC_FREE;j++) ; j--; - fprintf(fd,".. %5d free\n", j); + fprintf(fd, ".. %5d free\n", j); } else if (pd[j] == MALLOC_FIRST) { for(j++;j<=last_index && pd[j] == MALLOC_FOLLOW;j++) ; j--; - fprintf(fd,".. %5d in use\n", j); + fprintf(fd, ".. %5d in use\n", j); } else if (pd[j] < MALLOC_MAGIC) { - fprintf(fd,"(%p)\n", pd[j]); + fprintf(fd, "(%p)\n", pd[j]); } else { - fprintf(fd,"%p %d (of %d) x %d @ %p --> %p\n", - pd[j],pd[j]->free, pd[j]->total, + fprintf(fd, "%p %d (of %d) x %d @ %p --> %p\n", + pd[j], pd[j]->free, pd[j]->total, pd[j]->size, pd[j]->page, pd[j]->next); } } for(pf=free_list.next; pf; pf=pf->next) { - fprintf(fd,"Free: @%p [%p...%p[ %ld ->%p <-%p\n", - pf,pf->page,pf->end,pf->size,pf->prev,pf->next); + fprintf(fd, "Free: @%p [%p...%p[ %ld ->%p <-%p\n", + pf, pf->page, pf->end, pf->size, pf->prev, pf->next); if (pf == pf->next) { - fprintf(fd,"Free_list loops.\n"); ++ fprintf(fd, "Free_list loops.\n"); break; } } /* print out various info */ - fprintf(fd,"Minsize\t%d\n",malloc_minsize); - fprintf(fd,"Maxsize\t%d\n",malloc_maxsize); - fprintf(fd,"Pagesize\t%d\n",malloc_pagesize); - fprintf(fd,"Pageshift\t%d\n",malloc_pageshift); - fprintf(fd,"FirstPage\t%ld\n",malloc_origo); - fprintf(fd,"LastPage\t%ld %lx\n",last_index+malloc_pageshift, + fprintf(fd, "Minsize\t%d\n", malloc_minsize); + fprintf(fd, "Maxsize\t%d\n", malloc_maxsize); + fprintf(fd, "Pagesize\t%d\n", malloc_pagesize); + fprintf(fd, "Pageshift\t%d\n", malloc_pageshift); + fprintf(fd, "FirstPage\t%ld\n", malloc_origo); + fprintf(fd, "LastPage\t%ld %lx\n", last_index+malloc_pageshift, (last_index + malloc_pageshift) << malloc_pageshift); - fprintf(fd,"Break\t%ld\n",(u_long)sbrk(0) >> malloc_pageshift); + fprintf(fd, "Break\t%ld\n", (u_long)sbrk(0) >> malloc_pageshift); } #endif /* MALLOC_STATS */ +static char *malloc_func; + static void wrterror(p) char *p; { char *q = "Malloc error: "; suicide = 1; - write(2,q,strlen(q)); - write(2,p,strlen(p)); + write(2, q, strlen(q)); + write(2, malloc_func, strlen(malloc_func)); + write(2, p, strlen(p)); #ifdef MALLOC_STATS if (malloc_stats) malloc_dump(stderr); @@ -358,21 +353,22 @@ wrtwarning(p) char *q = "Malloc warning: "; if (malloc_abort) wrterror(p); - write(2,q,strlen(q)); - write(2,p,strlen(p)); + write(2, q, strlen(q)); + write(2, malloc_func, strlen(malloc_func)); + write(2, p, strlen(p)); } #ifdef EXTRA_SANITY static void malloc_exit() { - FILE *fd = fopen("malloc.out","a"); + FILE *fd = fopen("malloc.out", "a"); char *q = "malloc() warning: Couldn't dump stats.\n"; if (fd) { malloc_dump(fd); fclose(fd); } else - write(2,q,strlen(q)); + write(2, q, strlen(q)); } #endif /* EXTRA_SANITY */ @@ -384,14 +380,14 @@ static caddr_t map_pages(pages) int pages; { - caddr_t result,tail; + caddr_t result, tail; result = (caddr_t)pageround((u_long)sbrk(0)); tail = result + (pages << malloc_pageshift); if (brk(tail)) { #ifdef EXTRA_SANITY - wrterror("(internal): map_pages fails\n"); + wrterror("(ES): map_pages fails\n"); #endif /* EXTRA_SANITY */ return 0; } @@ -466,7 +462,7 @@ static int extend_pgdir(index) u_long index; { - struct pginfo **new,**old; + struct pginfo **new, **old; int i, oldlen; /* Make it this many pages */ @@ -520,35 +516,61 @@ extend_pgdir(index) static void malloc_init () { - char *p; + char *p, b[64]; + int i, j; #ifdef EXTRA_SANITY malloc_junk = 1; #endif /* EXTRA_SANITY */ - if (issetugid() == 0) { - for (p=getenv("MALLOC_OPTIONS"); p && *p; p++) { + for (i = 0; i < 3; i++) { + if (i == 0) { + j = readlink("/etc/malloc.conf", b, sizeof b - 1); + if (j <= 0) + continue; + b[j] = '\0'; + p = b; + } else if (i == 1) { + p = getenv("MALLOC_OPTIONS"); + } else if (i == 2) { + p = malloc_options; + } + for (; p && *p; p++) { switch (*p) { - case 'a': malloc_abort = 0; break; - case 'A': malloc_abort = 1; break; + case '>': malloc_cache <<= 1; break; + case '<': malloc_cache >>= 1; break; + case 'a': malloc_abort = 0; break; + case 'A': malloc_abort = 1; break; #ifdef MALLOC_STATS - case 'd': malloc_stats = 0; break; - case 'D': malloc_stats = 1; break; + case 'd': malloc_stats = 0; break; + case 'D': malloc_stats = 1; break; #endif /* MALLOC_STATS */ - case 'r': malloc_realloc = 0; break; - case 'R': malloc_realloc = 1; break; - case 'j': malloc_junk = 0; break; - case 'J': malloc_junk = 1; break; - case 'z': malloc_zero = 0; break; - case 'Z': malloc_zero = 1; break; - default: - wrtwarning("(Init): Unknown char in MALLOC_OPTIONS\n"); - p = 0; - break; +#ifdef __FreeBSD__ + case 'h': malloc_hint = 0; break; + case 'H': malloc_hint = 1; break; +#endif /* __FreeBSD__ */ + case 'r': malloc_realloc = 0; break; + case 'R': malloc_realloc = 1; break; + case 'j': malloc_junk = 0; break; + case 'J': malloc_junk = 1; break; +#ifdef __FreeBSD__ + case 'u': malloc_utrace = 0; break; + case 'U': malloc_utrace = 1; break; +#endif /* __FreeBSD__ */ + case 'z': malloc_zero = 0; break; + case 'Z': malloc_zero = 1; break; + default: + j = malloc_abort; + malloc_abort = 0; + wrtwarning("unknown char in MALLOC_OPTIONS\n"); + malloc_abort = j; + break; } } } + UTRACE(0, 0, 0); + /* * We want junk in the entire allocation, and zero only in the part * the user asked for. @@ -579,10 +601,6 @@ malloc_init () } #endif /* malloc_pageshift */ -#ifndef malloc_cache - malloc_cache = 100 << malloc_pageshift; -#endif /* malloc_cache */ - #ifndef malloc_minsize { int i; @@ -612,7 +630,7 @@ malloc_init () page_dir = (struct pginfo **) mmap(0, malloc_pagesize, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, (off_t)0); if (page_dir == (struct pginfo **) -1) - wrterror("(Init) my first mmap failed. (check limits ?)\n"); + wrterror("mmap(2) failed, check limits.\n"); /* * We need a maximum of malloc_pageshift buckets, steal these from the @@ -630,7 +648,12 @@ malloc_init () * This is a nice hack from Kaleb Keithly (kaleb@x.org). * We can sbrk(2) further back when we keep this on a low address. */ - px = (struct pgfree *) malloc (sizeof *px); + px = (struct pgfree *) imalloc (sizeof *px); + + if (!malloc_cache) + malloc_cache++; + + malloc_cache <<= malloc_pageshift; } /* @@ -640,7 +663,7 @@ void * malloc_pages(size) size_t size; { - void *p,*delay_free = 0; + void *p, *delay_free = 0; int i; struct pgfree *pf; u_long index; @@ -705,14 +728,14 @@ malloc_pages(size) page_dir[index+i] = MALLOC_FOLLOW; if (malloc_junk) - memset(p, SOME_JUNK,size << malloc_pageshift); + memset(p, SOME_JUNK, size << malloc_pageshift); } if (delay_free) { if (!px) px = delay_free; else - free(delay_free); + ifree(delay_free); } return p; @@ -728,7 +751,7 @@ malloc_make_chunks(bits) { struct pginfo *bp; void *pp; - int i,k,l; + int i, k, l; /* Allocate a new bucket */ pp = malloc_pages(malloc_pagesize); @@ -744,7 +767,7 @@ malloc_make_chunks(bits) if ((1<<(bits)) <= l+l) { bp = (struct pginfo *)pp; } else { - bp = (struct pginfo *)malloc(l); + bp = (struct pginfo *)imalloc(l); if (!bp) return 0; } @@ -768,12 +791,12 @@ malloc_make_chunks(bits) bp->bits[i / MALLOC_BITS] = (u_long)~0; for(; i < k; i++) - set_bit(bp,i); + set_bit(bp, i); if (bp == bp->page) { /* Mark the ones we stole for ourselves */ for(i=0;l > 0;i++) { - clr_bit(bp,i); + clr_bit(bp, i); bp->free--; bp->total--; l -= (1 << bits); @@ -835,8 +858,8 @@ malloc_bytes(size) /* * Allocate a piece of memory */ -void * -malloc(size) +static void * +imalloc(size) size_t size; { void *result; @@ -850,36 +873,30 @@ malloc(size) if (suicide) abort(); -#ifdef _THREAD_SAFE - _thread_kern_sig_block(&status); -#endif if (size <= malloc_maxsize) result = malloc_bytes(size); else result = malloc_pages(size); if (malloc_abort && !result) - wrterror("malloc(): returns NULL\n"); + wrterror("allocation failed.\n"); if (malloc_zero) - memset(result,0,size); + memset(result, 0, size); -#ifdef _THREAD_SAFE - _thread_kern_sig_unblock(status); -#endif return result; } /* * Change the size of an allocation. */ -void * -realloc(ptr, size) +static void * +irealloc(ptr, size) void *ptr; size_t size; { void *p; - u_long osize,index; + u_long osize, index; struct pginfo **mp; int i; #ifdef _THREAD_SAFE @@ -889,37 +906,20 @@ realloc(ptr, size) if (suicide) return 0; - if (!ptr) /* Bounce to malloc() */ - return malloc(size); - if (!initialized) { - wrtwarning("realloc(): malloc() never got called.\n"); - return 0; - } - - if (ptr && !size) { /* Bounce to free() */ - free(ptr); + wrtwarning("malloc() has never been called.\n"); return 0; } -#ifdef _THREAD_SAFE - _thread_kern_sig_block(&status); -#endif index = ptr2index(ptr); if (index < malloc_pageshift) { - wrtwarning("realloc(): junk pointer (too low)\n"); -#ifdef _THREAD_SAFE - _thread_kern_sig_unblock(status); -#endif + wrtwarning("junk pointer, too low to make sense.\n"); return 0; } if (index > last_index) { - wrtwarning("realloc(): junk pointer (too high)\n"); -#ifdef _THREAD_SAFE - _thread_kern_sig_unblock(status); -#endif + wrtwarning("junk pointer, too high to make sense.\n"); return 0; } @@ -929,10 +929,7 @@ realloc(ptr, size) /* Check the pointer */ if ((u_long)ptr & malloc_pagemask) { - wrtwarning("realloc(): modified page pointer.\n"); -#ifdef _THREAD_SAFE - _thread_kern_sig_unblock(status); -#endif + wrtwarning("modified (page-) pointer.\n"); return 0; } @@ -943,9 +940,6 @@ realloc(ptr, size) if (!malloc_realloc && /* unless we have to, */ size <= osize && /* .. or are too small, */ size > (osize - malloc_pagesize)) { /* .. or can free a page, */ -#ifdef _THREAD_SAFE - _thread_kern_sig_unblock(status); -#endif return ptr; /* don't do anything. */ } @@ -953,10 +947,7 @@ realloc(ptr, size) /* Check the pointer for sane values */ if (((u_long)ptr & ((*mp)->size-1))) { - wrtwarning("realloc(): modified chunk pointer.\n"); -#ifdef _THREAD_SAFE - _thread_kern_sig_unblock(status); -#endif + wrtwarning("modified (chunk-) pointer.\n"); return 0; } @@ -964,11 +955,8 @@ realloc(ptr, size) i = ((u_long)ptr & malloc_pagemask) >> (*mp)->shift; /* Verify that it isn't a free chunk already */ - if (tst_bit(*mp,i)) { - wrtwarning("realloc(): already free chunk.\n"); -#ifdef _THREAD_SAFE - _thread_kern_sig_unblock(status); -#endif + if (tst_bit(*mp, i)) { + wrtwarning("chunk is already free.\n"); return 0; } @@ -978,33 +966,24 @@ realloc(ptr, size) size < osize && /* ..or are too small, */ (size > osize/2 || /* ..or could use a smaller size, */ osize == malloc_minsize)) { /* ..(if there is one) */ -#ifdef _THREAD_SAFE - _thread_kern_sig_unblock(status); -#endif return ptr; /* ..Don't do anything */ } } else { - wrtwarning("realloc(): wrong page pointer.\n"); -#ifdef _THREAD_SAFE - _thread_kern_sig_unblock(status); -#endif + wrtwarning("pointer to wrong page.\n"); return 0; } - p = malloc(size); + p = imalloc(size); if (p) { /* copy the lesser of the two sizes, and free the old one */ if (osize < size) - memcpy(p,ptr,osize); + memcpy(p, ptr, osize); else - memcpy(p,ptr,size); - free(ptr); + memcpy(p, ptr, size); + ifree(ptr); } -#ifdef _THREAD_SAFE - _thread_kern_sig_unblock(status); -#endif return p; } @@ -1019,22 +998,22 @@ free_pages(ptr, index, info) struct pginfo *info; { int i; - struct pgfree *pf,*pt=0; + struct pgfree *pf, *pt=0; u_long l; void *tail; if (info == MALLOC_FREE) { - wrtwarning("free(): already free page.\n"); + wrtwarning("page is already free.\n"); return; } if (info != MALLOC_FIRST) { - wrtwarning("free(): freeing wrong page.\n"); + wrtwarning("pointer to wrong page.\n"); return; } if ((u_long)ptr & malloc_pagemask) { - wrtwarning("free(): modified page pointer.\n"); + wrtwarning("modified (page-) pointer.\n"); return; } @@ -1045,11 +1024,16 @@ free_pages(ptr, index, info) l = i << malloc_pageshift; - tail = (char *)ptr + l; +#ifdef __FreeBSD__ + if (malloc_hint) + madvise(ptr, l, MADV_FREE); +#endif + + tail = (char *)ptr+l; /* add to free-list */ if (!px) - px = malloc(sizeof *pt); /* This cannot fail... */ + px = imalloc(sizeof *pt); /* This cannot fail... */ px->page = ptr; px->end = tail; px->size = l; @@ -1065,7 +1049,7 @@ free_pages(ptr, index, info) } else { /* Find the right spot, leave pf pointing to the modified entry. */ - tail = (char *)ptr + l; + tail = (char *)ptr+l; for(pf = free_list.next; pf->end < ptr && pf->next; pf = pf->next) ; /* Race ahead here */ @@ -1103,7 +1087,7 @@ free_pages(ptr, index, info) pf = px; px = 0; } else { - wrterror("messed up free list"); + wrterror("freelist is destroyed.\n"); } } @@ -1132,7 +1116,7 @@ free_pages(ptr, index, info) /* XXX: We could realloc/shrink the pagedir here I guess. */ } if (pt) - free(pt); + ifree(pt); } /* @@ -1154,16 +1138,16 @@ free_bytes(ptr, index, info) i = ((u_long)ptr & malloc_pagemask) >> info->shift; if (((u_long)ptr & (info->size-1))) { - wrtwarning("free(): modified pointer.\n"); + wrtwarning("modified (chunk-) pointer.\n"); return; } - if (tst_bit(info,i)) { - wrtwarning("free(): already free chunk.\n"); + if (tst_bit(info, i)) { + wrtwarning("chunk is already free.\n"); return; } - set_bit(info,i); + set_bit(info, i); info->free++; mp = page_dir + info->shift; @@ -1198,12 +1182,12 @@ free_bytes(ptr, index, info) page_dir[ptr2index(info->page)] = MALLOC_FIRST; vp = info->page; /* Order is important ! */ if(vp != (void*)info) - free(info); - free(vp); + ifree(info); + ifree(vp); } -void -free(ptr) +static void +ifree(ptr) void *ptr; { struct pginfo *info; @@ -1217,7 +1201,7 @@ free(ptr) return; if (!initialized) { - wrtwarning("free(): malloc() never got called.\n"); + wrtwarning("malloc() has never been called.\n"); return; } @@ -1225,35 +1209,102 @@ free(ptr) if (suicide) return; -#ifdef _THREAD_SAFE - _thread_kern_sig_block(&status); -#endif index = ptr2index(ptr); if (index < malloc_pageshift) { - wrtwarning("free(): junk pointer (too low)\n"); -#ifdef _THREAD_SAFE - _thread_kern_sig_unblock(status); -#endif + wrtwarning("junk pointer, too low to make sense.\n"); return; } if (index > last_index) { - wrtwarning("free(): junk pointer (too high)\n"); -#ifdef _THREAD_SAFE - _thread_kern_sig_unblock(status); -#endif + wrtwarning("junk pointer, too high to make sense.\n"); return; } info = page_dir[index]; if (info < MALLOC_MAGIC) - free_pages(ptr,index,info); + free_pages(ptr, index, info); else - free_bytes(ptr,index,info); -#ifdef _THREAD_SAFE - _thread_kern_sig_unblock(status); + free_bytes(ptr, index, info); + return; +} + +/* + * These are the public exported interface routines. + */ + +#ifdef _THREAD_SAFE +#include +#include "pthread_private.h" +static int malloc_lock; +#define THREAD_LOCK() _thread_kern_sig_block(&malloc_lock); +#define THREAD_UNLOCK() _thread_kern_sig_unblock(&malloc_lock); +#else +#define THREAD_LOCK() +#define THREAD_UNLOCK() #endif + +static int malloc_active; + +void * +malloc(size_t size) +{ + register void *r; + + malloc_func = "malloc():"; + THREAD_LOCK(); + if (malloc_active++) { + wrtwarning("recursive call.\n"); + malloc_active--; + return (0); + } + r = imalloc(size); + UTRACE(0, size, r); + malloc_active--; + THREAD_UNLOCK(); + return (r); +} + +void +free(void *ptr) +{ + malloc_func = "free():"; + THREAD_LOCK(); + if (malloc_active++) { + wrtwarning("recursive call.\n"); + malloc_active--; + return; + } + ifree(ptr); + UTRACE(ptr, 0, 0); + malloc_active--; + THREAD_UNLOCK(); return; } + +void * +realloc(void *ptr, size_t size) +{ + register void *r; + + malloc_func = "realloc():"; + THREAD_LOCK(); + if (malloc_active++) { + wrtwarning("recursive call.\n"); + malloc_active--; + return (0); + } + if (!ptr) { + r = imalloc(size); + } else if (ptr && !size) { + ifree(ptr); + r = 0; + } else { + r = irealloc(ptr, size); + } + UTRACE(ptr, size, r); + malloc_active--; + THREAD_UNLOCK(); + return (r); +}