diff options
-rw-r--r-- | lib/libc/stdlib/malloc.3 | 117 | ||||
-rw-r--r-- | lib/libc/stdlib/malloc.c | 421 |
2 files changed, 342 insertions, 196 deletions
diff --git a/lib/libc/stdlib/malloc.3 b/lib/libc/stdlib/malloc.3 index 58d0ae4..cd10039 100644 --- a/lib/libc/stdlib/malloc.3 +++ b/lib/libc/stdlib/malloc.3 @@ -34,10 +34,11 @@ .\" SUCH DAMAGE. .\" .\" @(#)malloc.3 8.1 (Berkeley) 6/4/93 +.\" $Id$ .\" -.Dd June 4, 1993 +.Dd August 27, 1996 .Dt MALLOC 3 -.Os BSD 4 +.Os FreeBSD 2 .Sh NAME .Nm malloc , .Nd general memory allocation function @@ -55,6 +56,8 @@ .Fn free "void *ptr" .Ft void * .Fn realloc "void *ptr" "size_t size" +.Ft char * +.Va malloc_options .Sh DESCRIPTION The .Fn malloc @@ -110,11 +113,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 @@ -130,21 +135,42 @@ rather than when the NULL pointer was accessed. ``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 @@ -160,12 +186,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/lib/libc/stdlib/malloc.c b/lib/libc/stdlib/malloc.c index 2d5d73d..23f5ef1 100644 --- a/lib/libc/stdlib/malloc.c +++ b/lib/libc/stdlib/malloc.c @@ -6,13 +6,16 @@ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp * ---------------------------------------------------------------------------- * - * $Id: malloc.c,v 1.11 1996/07/03 05:03:07 phk Exp $ + * $Id: malloc.c,v 1.12 1996/09/17 19:50:23 phk Exp $ * */ /* - * 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 @@ -28,13 +31,14 @@ #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" :-) */ /* * If these weren't defined here, they would be calculated on the fly, - * at a considerable cost in performance. + * with a noticeable performance hit. */ #if defined(__i386__) && defined(__FreeBSD__) # define malloc_pagesize 4096U @@ -43,6 +47,10 @@ # define malloc_maxsize ((malloc_pagesize)>>1) #endif /* __i386__ && __FreeBSD__ */ +/* + * No user serviceable parts behind this point. + */ + #include <stdio.h> #include <stdlib.h> #include <unistd.h> @@ -51,10 +59,6 @@ #include <err.h> #include <sys/types.h> #include <sys/mman.h> -#ifdef _THREAD_SAFE -#include <pthread.h> -#include "pthread_private.h" -#endif /* * This structure describes a page worth of chunks. @@ -108,7 +112,7 @@ static __inline int _ffs(unsigned input) { int result; - asm("bsfl %1,%0" : "=r" (result) : "r" (input)); + asm("bsfl %1, %0" : "=r" (result) : "r" (input)); return result+1; } @@ -117,7 +121,7 @@ static __inline int _fls(unsigned input) { int result; - asm("bsrl %1,%0" : "=r" (result) : "r" (input)); + asm("bsrl %1, %0" : "=r" (result) : "r" (input)); return result+1; } @@ -125,7 +129,7 @@ _fls(unsigned input) static __inline void _set_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))); } @@ -133,7 +137,7 @@ _set_bit(struct pginfo *pi, int bit) static __inline void _clr_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))); } @@ -153,17 +157,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 */ @@ -185,85 +185,72 @@ 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 bytes) of the free page cache. */ +static unsigned malloc_cache = 16 << malloc_pageshift; -/* - * 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 ? - */ +/* pass the kernel a hint on free pages ? */ +static int malloc_hint; + +/* zero fill ? */ static int malloc_zero; -/* - * junk fill ? - */ +/* junk fill ? */ static int malloc_junk; -/* - * my last break. - */ +/* 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);} + +/* 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 @@ -277,59 +264,62 @@ malloc_dump(FILE *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(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); @@ -343,21 +333,22 @@ wrtwarning(char *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 */ @@ -368,14 +359,14 @@ malloc_exit() static caddr_t map_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; } @@ -442,7 +433,7 @@ fls(int size) static int extend_pgdir(u_long index) { - struct pginfo **new,**old; + struct pginfo **new, **old; int i, oldlen; /* Make it this many pages */ @@ -496,33 +487,59 @@ extend_pgdir(u_long index) static void malloc_init () { - char *p; + char *p, b[64]; + int i, j; + struct ut u; + #ifdef EXTRA_SANITY malloc_junk = 1; #endif /* EXTRA_SANITY */ - for (p=getenv("MALLOC_OPTIONS"); p && *p; p++) { - switch (*p) { - case 'a': malloc_abort = 0; break; - case 'A': malloc_abort = 1; break; + 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 '>': 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; + case 'h': malloc_hint = 0; break; + case 'H': malloc_hint = 1; break; + 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 'u': malloc_utrace = 0; break; + case 'U': malloc_utrace = 1; break; + 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. @@ -553,10 +570,6 @@ malloc_init () } #endif /* malloc_pageshift */ -#ifndef malloc_cache - malloc_cache = 100 << malloc_pageshift; -#endif /* malloc_cache */ - #ifndef malloc_minsize { int i; @@ -586,7 +599,7 @@ malloc_init () page_dir = (struct pginfo **) mmap(0, malloc_pagesize, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 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 @@ -604,7 +617,7 @@ 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); } /* @@ -613,7 +626,7 @@ malloc_init () void * malloc_pages(size_t size) { - void *p,*delay_free = 0; + void *p, *delay_free = 0; int i; struct pgfree *pf; u_long index; @@ -678,14 +691,14 @@ malloc_pages(size_t 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; @@ -700,7 +713,7 @@ malloc_make_chunks(int bits) { struct pginfo *bp; void *pp; - int i,k,l; + int i, k, l; /* Allocate a new bucket */ pp = malloc_pages(malloc_pagesize); @@ -716,7 +729,7 @@ malloc_make_chunks(int 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; } @@ -740,12 +753,12 @@ malloc_make_chunks(int bits) bp->bits[i / MALLOC_BITS] = ~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); @@ -806,7 +819,7 @@ malloc_bytes(size_t size) /* * Allocate a piece of memory */ -static __inline void * +static void * imalloc(size_t size) { void *result; @@ -823,10 +836,10 @@ imalloc(size_t size) 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); return result; } @@ -834,39 +847,31 @@ imalloc(size_t size) /* * Change the size of an allocation. */ -static __inline void * +static void * irealloc(void *ptr, size_t size) { void *p; - u_long osize,index; + u_long osize, index; struct pginfo **mp; int i; 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; } index = ptr2index(ptr); if (index < malloc_pageshift) { - wrtwarning("realloc(): junk pointer (too low)\n"); + wrtwarning("junk pointer, too low to make sense.\n"); return 0; } if (index > last_index) { - wrtwarning("realloc(): junk pointer (too high)\n"); + wrtwarning("junk pointer, too high to make sense.\n"); return 0; } @@ -876,7 +881,7 @@ irealloc(void *ptr, size_t size) /* Check the pointer */ if ((u_long)ptr & malloc_pagemask) { - wrtwarning("realloc(): modified page pointer.\n"); + wrtwarning("modified (page-) pointer.\n"); return 0; } @@ -894,7 +899,7 @@ irealloc(void *ptr, size_t size) /* Check the pointer for sane values */ if (((u_long)ptr & ((*mp)->size-1))) { - wrtwarning("realloc(): modified chunk pointer.\n"); + wrtwarning("modified (chunk-) pointer.\n"); return 0; } @@ -902,8 +907,8 @@ irealloc(void *ptr, size_t 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"); + if (tst_bit(*mp, i)) { + wrtwarning("chunk is already free.\n"); return 0; } @@ -917,19 +922,19 @@ irealloc(void *ptr, size_t size) } } else { - wrtwarning("realloc(): wrong page pointer.\n"); + 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); } return p; } @@ -942,22 +947,22 @@ static __inline void free_pages(void *ptr, int index, 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; } @@ -968,11 +973,14 @@ free_pages(void *ptr, int index, struct pginfo *info) l = i << malloc_pageshift; + if (malloc_hint) + madvise(ptr, l, MADV_FREE); + tail = 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; @@ -1026,7 +1034,7 @@ free_pages(void *ptr, int index, struct pginfo *info) pf = px; px = 0; } else { - wrterror("messed up free list"); + wrterror("freelist is destroyed.\n"); } } @@ -1055,7 +1063,7 @@ free_pages(void *ptr, int index, struct pginfo *info) /* XXX: We could realloc/shrink the pagedir here I guess. */ } if (pt) - free(pt); + ifree(pt); } /* @@ -1073,16 +1081,16 @@ free_bytes(void *ptr, int index, struct pginfo *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; @@ -1117,11 +1125,11 @@ free_bytes(void *ptr, int index, struct pginfo *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); } -static __inline void +static void ifree(void *ptr) { struct pginfo *info; @@ -1132,7 +1140,7 @@ ifree(void *ptr) return; if (!initialized) { - wrtwarning("free(): malloc() never got called.\n"); + wrtwarning("malloc() has never been called.\n"); return; } @@ -1143,64 +1151,99 @@ ifree(void *ptr) index = ptr2index(ptr); if (index < malloc_pageshift) { - wrtwarning("free(): junk pointer (too low)\n"); + wrtwarning("junk pointer, too low to make sense.\n"); return; } if (index > last_index) { - wrtwarning("free(): junk pointer (too high)\n"); + 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); + free_bytes(ptr, index, info); return; } +/* + * These are the public exported interface routines. + */ + +#ifdef _THREAD_SAFE +#include <pthread.h> +#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) { -#ifdef _THREAD_SAFE - int status; register void *r; - _thread_kern_sig_block(&status); + + malloc_func = "malloc():"; + THREAD_LOCK(); + if (malloc_active++) { + wrtwarning("recursive call.\n"); + malloc_active--; + return (0); + } r = imalloc(size); - _thread_kern_sig_unblock(status); - return r; -#else - return imalloc(size); -#endif + UTRACE(0, size, r); + malloc_active--; + THREAD_UNLOCK(); + return (r); } void free(void *ptr) { -#ifdef _THREAD_SAFE - int status; - _thread_kern_sig_block(&status); - ifree(ptr); - _thread_kern_sig_unblock(status); -#else + malloc_func = "free():"; + THREAD_LOCK(); + if (malloc_active++) { + wrtwarning("recursive call.\n"); + malloc_active--; + return; + } ifree(ptr); -#endif + UTRACE(ptr, 0, 0); + malloc_active--; + THREAD_UNLOCK(); return; } void * realloc(void *ptr, size_t size) { -#ifdef _THREAD_SAFE - int status; register void *r; - _thread_kern_sig_block(&status); - r = irealloc(ptr, size); - _thread_kern_sig_unblock(status); - return r; -#else - return irealloc(ptr, size); -#endif + + 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); } |