phkmalloc/3

Various neat features added.  More documentation in the manpage.
If your machine has very little RAM, I guess that would be < 16M
these days :-(,  you may want to try this:
	ln -fs 'H<' /etc/malloc.conf
check the manpage.
This commit is contained in:
Poul-Henning Kamp 1996-09-23 19:26:39 +00:00
parent 0e0e0239f0
commit 1f05a9e73a
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=18479
2 changed files with 342 additions and 196 deletions

View file

@ -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

View file

@ -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);
malloc_func = "free():";
THREAD_LOCK();
if (malloc_active++) {
wrtwarning("recursive call.\n");
malloc_active--;
return;
}
ifree(ptr);
_thread_kern_sig_unblock(status);
#else
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);
}