summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/libc/stdlib/malloc.3118
-rw-r--r--lib/libc/stdlib/malloc.c491
2 files changed, 381 insertions, 228 deletions
diff --git a/lib/libc/stdlib/malloc.3 b/lib/libc/stdlib/malloc.3
index 979e77016df..e206245cc27 100644
--- a/lib/libc/stdlib/malloc.3
+++ b/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/lib/libc/stdlib/malloc.c b/lib/libc/stdlib/malloc.c
index bff70c7b543..a6f60b3fe37 100644
--- a/lib/libc/stdlib/malloc.c
+++ b/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 <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <unistd.h>
-#include <memory.h>
#include <errno.h>
-#include <err.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/mman.h>
-#ifdef _THREAD_SAFE
-#include <pthread.h>
-#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 <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)
+{
+ 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);
+}