summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/libc/stdlib/malloc.3117
-rw-r--r--lib/libc/stdlib/malloc.c421
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);
}
OpenPOWER on IntegriCloud