1994-05-27 05:00:24 +00:00
|
|
|
/*
|
1995-09-16 09:28:13 +00:00
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
* "THE BEER-WARE LICENSE" (Revision 42):
|
|
|
|
* <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you
|
|
|
|
* can do whatever you want with this stuff. If we meet some day, and you think
|
|
|
|
* this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
|
|
|
|
* ----------------------------------------------------------------------------
|
1994-05-27 05:00:24 +00:00
|
|
|
*
|
1996-09-25 08:30:46 +00:00
|
|
|
* $Id: malloc.c,v 1.13 1996/09/23 19:26:39 phk Exp $
|
1994-05-27 05:00:24 +00:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
1995-09-16 09:28:13 +00:00
|
|
|
/*
|
1996-09-23 19:26:39 +00:00
|
|
|
* 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.
|
1995-09-16 09:28:13 +00:00
|
|
|
*/
|
1995-10-22 14:47:00 +00:00
|
|
|
#undef EXTRA_SANITY
|
1995-09-16 09:28:13 +00:00
|
|
|
|
Change phkmalloc so that the page directory is now floating and allocated
via mmap() up around the shared library area. Previously the directory
was allocated from space from it's own memory pool. Because of the way it
was being extended on processes with large malloced data segments (ie: inn)
once the page directory was extended for some reason, it was not possible
to lower the heap size any more to return pages to the OS.
(If my understanding is correct, page directory expansion occurs at 4MB,
12MB, 20MB, 28MB, etc.) I was seeing INN allocate a large amount of short
term memory, pushing it over the 28MB mark, and once it's transient demands
hit 28MB, it never freed it's pages and swap space again.)
I've been running this in my libc for about a month...
Also, seperate MALLOC_STATS from EXTRA_SANITY.. I found it useful to call
malloc_dump() from within INN from a ctlinnd command to see where the hell
all the memory was going.. :-) I've left MALLOC_STATS enabled, as it has
no run-time or data storage cost.
Reviewed by: phk
1995-12-11 14:28:12 +00:00
|
|
|
/*
|
|
|
|
* Defining MALLOC_STATS will enable you to call malloc_dump() and set
|
|
|
|
* the [dD] options in the MALLOC_OPTIONS environment variable.
|
|
|
|
* It has no run-time performance hit.
|
|
|
|
*/
|
|
|
|
#define MALLOC_STATS
|
|
|
|
|
|
|
|
#if defined(EXTRA_SANITY) && !defined(MALLOC_STATS)
|
|
|
|
# define MALLOC_STATS /* required for EXTRA_SANITY */
|
|
|
|
#endif
|
|
|
|
|
1995-09-16 09:28:13 +00:00
|
|
|
/*
|
1996-09-23 19:26:39 +00:00
|
|
|
* What to use for Junk. This is the byte value we use to fill with
|
|
|
|
* when the 'J' option is enabled.
|
1995-09-16 09:28:13 +00:00
|
|
|
*/
|
1995-10-08 18:44:20 +00:00
|
|
|
#define SOME_JUNK 0xd0 /* as in "Duh" :-) */
|
1995-09-16 09:28:13 +00:00
|
|
|
|
|
|
|
/*
|
1995-10-08 18:44:20 +00:00
|
|
|
* If these weren't defined here, they would be calculated on the fly,
|
1996-09-23 19:26:39 +00:00
|
|
|
* with a noticeable performance hit.
|
1995-09-16 09:28:13 +00:00
|
|
|
*/
|
1995-10-08 18:44:20 +00:00
|
|
|
#if defined(__i386__) && defined(__FreeBSD__)
|
1995-09-16 09:28:13 +00:00
|
|
|
# define malloc_pagesize 4096U
|
|
|
|
# define malloc_pageshift 12U
|
1995-10-08 18:44:20 +00:00
|
|
|
# define malloc_minsize 16U
|
|
|
|
# define malloc_maxsize ((malloc_pagesize)>>1)
|
1995-09-16 09:28:13 +00:00
|
|
|
#endif /* __i386__ && __FreeBSD__ */
|
|
|
|
|
1996-09-23 19:26:39 +00:00
|
|
|
/*
|
|
|
|
* No user serviceable parts behind this point.
|
|
|
|
*/
|
|
|
|
|
1995-09-16 09:28:13 +00:00
|
|
|
#include <stdio.h>
|
1994-05-27 05:00:24 +00:00
|
|
|
#include <stdlib.h>
|
1996-09-25 08:30:46 +00:00
|
|
|
#include <string.h>
|
1994-05-27 05:00:24 +00:00
|
|
|
#include <unistd.h>
|
1995-09-16 09:28:13 +00:00
|
|
|
#include <errno.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/mman.h>
|
1994-05-27 05:00:24 +00:00
|
|
|
|
1995-09-16 09:28:13 +00:00
|
|
|
/*
|
1995-10-08 18:44:20 +00:00
|
|
|
* This structure describes a page worth of chunks.
|
1995-09-16 09:28:13 +00:00
|
|
|
*/
|
1994-05-27 05:00:24 +00:00
|
|
|
|
1995-09-16 09:28:13 +00:00
|
|
|
struct pginfo {
|
|
|
|
struct pginfo *next; /* next on the free list */
|
|
|
|
void *page; /* Pointer to the page */
|
|
|
|
u_short size; /* size of this page's chunks */
|
|
|
|
u_short shift; /* How far to shift for this size chunks */
|
|
|
|
u_short free; /* How many free chunks */
|
|
|
|
u_short total; /* How many chunk */
|
|
|
|
u_long bits[1]; /* Which chunks are free */
|
|
|
|
};
|
1994-05-27 05:00:24 +00:00
|
|
|
|
1995-10-08 18:44:20 +00:00
|
|
|
/*
|
|
|
|
* This structure describes a number of free pages.
|
|
|
|
*/
|
|
|
|
|
1995-09-16 09:28:13 +00:00
|
|
|
struct pgfree {
|
|
|
|
struct pgfree *next; /* next run of free pages */
|
|
|
|
struct pgfree *prev; /* prev run of free pages */
|
|
|
|
void *page; /* pointer to free pages */
|
|
|
|
void *end; /* pointer to end of free pages */
|
|
|
|
u_long size; /* number of bytes free */
|
|
|
|
};
|
1994-05-27 05:00:24 +00:00
|
|
|
|
|
|
|
/*
|
1995-09-16 09:28:13 +00:00
|
|
|
* How many bits per u_long in the bitmap.
|
|
|
|
* Change only if not 8 bits/byte
|
1994-05-27 05:00:24 +00:00
|
|
|
*/
|
1995-09-16 09:28:13 +00:00
|
|
|
#define MALLOC_BITS (8*sizeof(u_long))
|
1994-05-27 05:00:24 +00:00
|
|
|
|
1995-09-16 09:28:13 +00:00
|
|
|
/*
|
|
|
|
* Magic values to put in the page_directory
|
|
|
|
*/
|
|
|
|
#define MALLOC_NOT_MINE ((struct pginfo*) 0)
|
|
|
|
#define MALLOC_FREE ((struct pginfo*) 1)
|
|
|
|
#define MALLOC_FIRST ((struct pginfo*) 2)
|
|
|
|
#define MALLOC_FOLLOW ((struct pginfo*) 3)
|
|
|
|
#define MALLOC_MAGIC ((struct pginfo*) 4)
|
1994-05-27 05:00:24 +00:00
|
|
|
|
|
|
|
/*
|
1995-09-16 09:28:13 +00:00
|
|
|
* The i386 architecture has some very convenient instructions.
|
1995-10-08 18:44:20 +00:00
|
|
|
* We might as well use them. There are C-language backups, but
|
|
|
|
* they are considerably slower.
|
1994-05-27 05:00:24 +00:00
|
|
|
*/
|
1996-09-25 08:30:46 +00:00
|
|
|
#if defined(__i386__) && defined(__GNUC__)
|
1995-09-16 09:28:13 +00:00
|
|
|
#define ffs _ffs
|
1996-09-25 08:30:46 +00:00
|
|
|
static __inline__ int
|
1995-09-16 09:28:13 +00:00
|
|
|
_ffs(unsigned input)
|
|
|
|
{
|
|
|
|
int result;
|
1996-09-25 08:30:46 +00:00
|
|
|
__asm__("bsfl %1, %0" : "=r" (result) : "r" (input));
|
1995-09-16 09:28:13 +00:00
|
|
|
return result+1;
|
|
|
|
}
|
1994-05-27 05:00:24 +00:00
|
|
|
|
1995-09-16 09:28:13 +00:00
|
|
|
#define fls _fls
|
1996-09-25 08:30:46 +00:00
|
|
|
static __inline__ int
|
1995-09-16 09:28:13 +00:00
|
|
|
_fls(unsigned input)
|
1994-05-27 05:00:24 +00:00
|
|
|
{
|
1995-09-16 09:28:13 +00:00
|
|
|
int result;
|
1996-09-25 08:30:46 +00:00
|
|
|
__asm__("bsrl %1, %0" : "=r" (result) : "r" (input));
|
1995-09-16 09:28:13 +00:00
|
|
|
return result+1;
|
1994-05-27 05:00:24 +00:00
|
|
|
}
|
|
|
|
|
1995-09-16 09:28:13 +00:00
|
|
|
#define set_bit _set_bit
|
1996-09-25 08:30:46 +00:00
|
|
|
static __inline__ void
|
1995-09-16 09:28:13 +00:00
|
|
|
_set_bit(struct pginfo *pi, int bit)
|
1994-05-27 05:00:24 +00:00
|
|
|
{
|
1996-09-25 08:30:46 +00:00
|
|
|
__asm__("btsl %0, (%1)" :
|
1995-09-16 09:28:13 +00:00
|
|
|
: "r" (bit & (MALLOC_BITS-1)), "r" (pi->bits+(bit/MALLOC_BITS)));
|
|
|
|
}
|
|
|
|
|
|
|
|
#define clr_bit _clr_bit
|
1996-09-25 08:30:46 +00:00
|
|
|
static __inline__ void
|
1995-09-16 09:28:13 +00:00
|
|
|
_clr_bit(struct pginfo *pi, int bit)
|
|
|
|
{
|
1996-09-25 08:30:46 +00:00
|
|
|
__asm__("btcl %0, (%1)" :
|
1995-09-16 09:28:13 +00:00
|
|
|
: "r" (bit & (MALLOC_BITS-1)), "r" (pi->bits+(bit/MALLOC_BITS)));
|
|
|
|
}
|
|
|
|
|
1996-09-25 08:30:46 +00:00
|
|
|
#endif /* __i386__ && __GNUC__ */
|
1995-09-16 09:28:13 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Set to one when malloc_init has been called
|
|
|
|
*/
|
|
|
|
static unsigned initialized;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The size of a page.
|
|
|
|
* Must be a integral multiplum of the granularity of mmap(2).
|
|
|
|
* Your toes will curl if it isn't a power of two
|
|
|
|
*/
|
1995-10-08 18:44:20 +00:00
|
|
|
#ifndef malloc_pagesize
|
|
|
|
static unsigned malloc_pagesize;
|
|
|
|
#endif /* malloc_pagesize */
|
1995-09-16 09:28:13 +00:00
|
|
|
|
1996-09-23 19:26:39 +00:00
|
|
|
/* A mask for the offset inside a page. */
|
1995-10-08 18:44:20 +00:00
|
|
|
#define malloc_pagemask ((malloc_pagesize)-1)
|
|
|
|
|
|
|
|
#define pageround(foo) (((foo) + (malloc_pagemask))&(~(malloc_pagemask)))
|
|
|
|
#define ptr2index(foo) (((u_long)(foo) >> malloc_pageshift)-malloc_origo)
|
1995-09-16 09:28:13 +00:00
|
|
|
|
1996-09-23 19:26:39 +00:00
|
|
|
/* malloc_pagesize == 1 << malloc_pageshift */
|
1995-09-16 09:28:13 +00:00
|
|
|
#ifndef malloc_pageshift
|
|
|
|
static unsigned malloc_pageshift;
|
|
|
|
#endif /* malloc_pageshift */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The smallest allocation we bother about.
|
|
|
|
* Must be power of two
|
|
|
|
*/
|
|
|
|
#ifndef malloc_minsize
|
|
|
|
static unsigned malloc_minsize;
|
|
|
|
#endif /* malloc_minsize */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The largest chunk we care about.
|
|
|
|
* Must be smaller than pagesize
|
|
|
|
* Must be power of two
|
|
|
|
*/
|
|
|
|
#ifndef malloc_maxsize
|
|
|
|
static unsigned malloc_maxsize;
|
|
|
|
#endif /* malloc_maxsize */
|
|
|
|
|
1996-09-25 08:30:46 +00:00
|
|
|
/* The minimum size (in pages) of the free page cache. */
|
|
|
|
static unsigned malloc_cache = 16;
|
1995-09-16 09:28:13 +00:00
|
|
|
|
1996-09-23 19:26:39 +00:00
|
|
|
/* The offset from pagenumber to index into the page directory */
|
1995-09-16 09:28:13 +00:00
|
|
|
static u_long malloc_origo;
|
|
|
|
|
1996-09-23 19:26:39 +00:00
|
|
|
/* The last index in the page directory we care about */
|
1995-09-16 09:28:13 +00:00
|
|
|
static u_long last_index;
|
|
|
|
|
1996-09-23 19:26:39 +00:00
|
|
|
/* Pointer to page directory. Allocated "as if with" malloc */
|
1995-09-16 09:28:13 +00:00
|
|
|
static struct pginfo **page_dir;
|
|
|
|
|
1996-09-23 19:26:39 +00:00
|
|
|
/* How many slots in the page directory */
|
1995-09-16 09:28:13 +00:00
|
|
|
static unsigned malloc_ninfo;
|
|
|
|
|
1996-09-23 19:26:39 +00:00
|
|
|
/* Free pages line up here */
|
1995-09-16 09:28:13 +00:00
|
|
|
static struct pgfree free_list;
|
|
|
|
|
1996-09-23 19:26:39 +00:00
|
|
|
/* Abort(), user doesn't handle problems. */
|
1995-09-16 09:28:13 +00:00
|
|
|
static int malloc_abort;
|
|
|
|
|
1996-09-23 19:26:39 +00:00
|
|
|
/* Are we trying to die ? */
|
1995-09-16 09:28:13 +00:00
|
|
|
static int suicide;
|
|
|
|
|
Change phkmalloc so that the page directory is now floating and allocated
via mmap() up around the shared library area. Previously the directory
was allocated from space from it's own memory pool. Because of the way it
was being extended on processes with large malloced data segments (ie: inn)
once the page directory was extended for some reason, it was not possible
to lower the heap size any more to return pages to the OS.
(If my understanding is correct, page directory expansion occurs at 4MB,
12MB, 20MB, 28MB, etc.) I was seeing INN allocate a large amount of short
term memory, pushing it over the 28MB mark, and once it's transient demands
hit 28MB, it never freed it's pages and swap space again.)
I've been running this in my libc for about a month...
Also, seperate MALLOC_STATS from EXTRA_SANITY.. I found it useful to call
malloc_dump() from within INN from a ctlinnd command to see where the hell
all the memory was going.. :-) I've left MALLOC_STATS enabled, as it has
no run-time or data storage cost.
Reviewed by: phk
1995-12-11 14:28:12 +00:00
|
|
|
#ifdef MALLOC_STATS
|
1996-09-23 19:26:39 +00:00
|
|
|
/* dump statistics */
|
1995-09-16 09:28:13 +00:00
|
|
|
static int malloc_stats;
|
Change phkmalloc so that the page directory is now floating and allocated
via mmap() up around the shared library area. Previously the directory
was allocated from space from it's own memory pool. Because of the way it
was being extended on processes with large malloced data segments (ie: inn)
once the page directory was extended for some reason, it was not possible
to lower the heap size any more to return pages to the OS.
(If my understanding is correct, page directory expansion occurs at 4MB,
12MB, 20MB, 28MB, etc.) I was seeing INN allocate a large amount of short
term memory, pushing it over the 28MB mark, and once it's transient demands
hit 28MB, it never freed it's pages and swap space again.)
I've been running this in my libc for about a month...
Also, seperate MALLOC_STATS from EXTRA_SANITY.. I found it useful to call
malloc_dump() from within INN from a ctlinnd command to see where the hell
all the memory was going.. :-) I've left MALLOC_STATS enabled, as it has
no run-time or data storage cost.
Reviewed by: phk
1995-12-11 14:28:12 +00:00
|
|
|
#endif /* MALLOC_STATS */
|
1995-09-16 09:28:13 +00:00
|
|
|
|
1996-09-23 19:26:39 +00:00
|
|
|
/* always realloc ? */
|
1995-09-16 09:28:13 +00:00
|
|
|
static int malloc_realloc;
|
|
|
|
|
1996-09-23 19:26:39 +00:00
|
|
|
/* pass the kernel a hint on free pages ? */
|
|
|
|
static int malloc_hint;
|
|
|
|
|
|
|
|
/* zero fill ? */
|
1995-10-08 18:44:20 +00:00
|
|
|
static int malloc_zero;
|
|
|
|
|
1996-09-23 19:26:39 +00:00
|
|
|
/* junk fill ? */
|
1995-10-08 18:44:20 +00:00
|
|
|
static int malloc_junk;
|
|
|
|
|
1996-09-25 08:30:46 +00:00
|
|
|
#ifdef __FreeBSD__
|
1996-09-23 19:26:39 +00:00
|
|
|
/* 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);}
|
1996-09-25 08:30:46 +00:00
|
|
|
#else /* !__FreeBSD__ */
|
|
|
|
#define UTRACE(a,b,c)
|
|
|
|
#endif
|
1996-09-23 19:26:39 +00:00
|
|
|
|
|
|
|
/* my last break. */
|
1995-09-16 09:28:13 +00:00
|
|
|
static void *malloc_brk;
|
|
|
|
|
1996-09-23 19:26:39 +00:00
|
|
|
/* one location cache for free-list holders */
|
1995-09-16 09:28:13 +00:00
|
|
|
static struct pgfree *px;
|
|
|
|
|
1996-09-23 19:26:39 +00:00
|
|
|
/* compile-time options */
|
|
|
|
char *malloc_options;
|
|
|
|
|
1995-10-08 18:44:20 +00:00
|
|
|
/*
|
|
|
|
* Necessary function declarations
|
|
|
|
*/
|
|
|
|
static int extend_pgdir(u_long index);
|
1996-09-23 19:26:39 +00:00
|
|
|
static void *imalloc(size_t size);
|
|
|
|
static void ifree(void *ptr);
|
|
|
|
static void *irealloc(void *ptr, size_t size);
|
1995-09-16 09:28:13 +00:00
|
|
|
|
Change phkmalloc so that the page directory is now floating and allocated
via mmap() up around the shared library area. Previously the directory
was allocated from space from it's own memory pool. Because of the way it
was being extended on processes with large malloced data segments (ie: inn)
once the page directory was extended for some reason, it was not possible
to lower the heap size any more to return pages to the OS.
(If my understanding is correct, page directory expansion occurs at 4MB,
12MB, 20MB, 28MB, etc.) I was seeing INN allocate a large amount of short
term memory, pushing it over the 28MB mark, and once it's transient demands
hit 28MB, it never freed it's pages and swap space again.)
I've been running this in my libc for about a month...
Also, seperate MALLOC_STATS from EXTRA_SANITY.. I found it useful to call
malloc_dump() from within INN from a ctlinnd command to see where the hell
all the memory was going.. :-) I've left MALLOC_STATS enabled, as it has
no run-time or data storage cost.
Reviewed by: phk
1995-12-11 14:28:12 +00:00
|
|
|
#ifdef MALLOC_STATS
|
1995-09-16 09:28:13 +00:00
|
|
|
void
|
|
|
|
malloc_dump(FILE *fd)
|
|
|
|
{
|
|
|
|
struct pginfo **pd;
|
|
|
|
struct pgfree *pf;
|
|
|
|
int j;
|
|
|
|
|
|
|
|
pd = page_dir;
|
|
|
|
|
|
|
|
/* print out all the pages */
|
|
|
|
for(j=0;j<=last_index;j++) {
|
1996-09-23 19:26:39 +00:00
|
|
|
fprintf(fd, "%08lx %5d ", (j+malloc_origo) << malloc_pageshift, j);
|
1995-09-16 09:28:13 +00:00
|
|
|
if (pd[j] == MALLOC_NOT_MINE) {
|
|
|
|
for(j++;j<=last_index && pd[j] == MALLOC_NOT_MINE;j++)
|
|
|
|
;
|
|
|
|
j--;
|
1996-09-23 19:26:39 +00:00
|
|
|
fprintf(fd, ".. %5d not mine\n", j);
|
1995-09-16 09:28:13 +00:00
|
|
|
} else if (pd[j] == MALLOC_FREE) {
|
|
|
|
for(j++;j<=last_index && pd[j] == MALLOC_FREE;j++)
|
|
|
|
;
|
|
|
|
j--;
|
1996-09-23 19:26:39 +00:00
|
|
|
fprintf(fd, ".. %5d free\n", j);
|
1995-09-16 09:28:13 +00:00
|
|
|
} else if (pd[j] == MALLOC_FIRST) {
|
|
|
|
for(j++;j<=last_index && pd[j] == MALLOC_FOLLOW;j++)
|
|
|
|
;
|
|
|
|
j--;
|
1996-09-23 19:26:39 +00:00
|
|
|
fprintf(fd, ".. %5d in use\n", j);
|
1995-09-16 09:28:13 +00:00
|
|
|
} else if (pd[j] < MALLOC_MAGIC) {
|
1996-09-23 19:26:39 +00:00
|
|
|
fprintf(fd, "(%p)\n", pd[j]);
|
1994-05-27 05:00:24 +00:00
|
|
|
} else {
|
1996-09-23 19:26:39 +00:00
|
|
|
fprintf(fd, "%p %d (of %d) x %d @ %p --> %p\n",
|
|
|
|
pd[j], pd[j]->free, pd[j]->total,
|
1995-09-16 09:28:13 +00:00
|
|
|
pd[j]->size, pd[j]->page, pd[j]->next);
|
1994-05-27 05:00:24 +00:00
|
|
|
}
|
1995-09-16 09:28:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for(pf=free_list.next; pf; pf=pf->next) {
|
1996-09-23 19:26:39 +00:00
|
|
|
fprintf(fd, "Free: @%p [%p...%p[ %ld ->%p <-%p\n",
|
|
|
|
pf, pf->page, pf->end, pf->size, pf->prev, pf->next);
|
1995-09-16 09:28:13 +00:00
|
|
|
if (pf == pf->next) {
|
1996-09-23 19:26:39 +00:00
|
|
|
fprintf(fd, "Free_list loops.\n");
|
1995-09-16 09:28:13 +00:00
|
|
|
break;
|
1994-05-27 05:00:24 +00:00
|
|
|
}
|
1995-09-16 09:28:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* print out various info */
|
1996-09-23 19:26:39 +00:00
|
|
|
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,
|
1995-09-16 09:28:13 +00:00
|
|
|
(last_index + malloc_pageshift) << malloc_pageshift);
|
1996-09-23 19:26:39 +00:00
|
|
|
fprintf(fd, "Break\t%ld\n", (u_long)sbrk(0) >> malloc_pageshift);
|
1995-09-16 09:28:13 +00:00
|
|
|
}
|
Change phkmalloc so that the page directory is now floating and allocated
via mmap() up around the shared library area. Previously the directory
was allocated from space from it's own memory pool. Because of the way it
was being extended on processes with large malloced data segments (ie: inn)
once the page directory was extended for some reason, it was not possible
to lower the heap size any more to return pages to the OS.
(If my understanding is correct, page directory expansion occurs at 4MB,
12MB, 20MB, 28MB, etc.) I was seeing INN allocate a large amount of short
term memory, pushing it over the 28MB mark, and once it's transient demands
hit 28MB, it never freed it's pages and swap space again.)
I've been running this in my libc for about a month...
Also, seperate MALLOC_STATS from EXTRA_SANITY.. I found it useful to call
malloc_dump() from within INN from a ctlinnd command to see where the hell
all the memory was going.. :-) I've left MALLOC_STATS enabled, as it has
no run-time or data storage cost.
Reviewed by: phk
1995-12-11 14:28:12 +00:00
|
|
|
#endif /* MALLOC_STATS */
|
1995-09-16 09:28:13 +00:00
|
|
|
|
1996-09-23 19:26:39 +00:00
|
|
|
static char *malloc_func;
|
|
|
|
|
1995-09-16 09:28:13 +00:00
|
|
|
static void
|
|
|
|
wrterror(char *p)
|
|
|
|
{
|
1995-10-08 18:44:20 +00:00
|
|
|
char *q = "Malloc error: ";
|
1995-09-16 09:28:13 +00:00
|
|
|
suicide = 1;
|
1996-09-23 19:26:39 +00:00
|
|
|
write(2, q, strlen(q));
|
|
|
|
write(2, malloc_func, strlen(malloc_func));
|
|
|
|
write(2, p, strlen(p));
|
Change phkmalloc so that the page directory is now floating and allocated
via mmap() up around the shared library area. Previously the directory
was allocated from space from it's own memory pool. Because of the way it
was being extended on processes with large malloced data segments (ie: inn)
once the page directory was extended for some reason, it was not possible
to lower the heap size any more to return pages to the OS.
(If my understanding is correct, page directory expansion occurs at 4MB,
12MB, 20MB, 28MB, etc.) I was seeing INN allocate a large amount of short
term memory, pushing it over the 28MB mark, and once it's transient demands
hit 28MB, it never freed it's pages and swap space again.)
I've been running this in my libc for about a month...
Also, seperate MALLOC_STATS from EXTRA_SANITY.. I found it useful to call
malloc_dump() from within INN from a ctlinnd command to see where the hell
all the memory was going.. :-) I've left MALLOC_STATS enabled, as it has
no run-time or data storage cost.
Reviewed by: phk
1995-12-11 14:28:12 +00:00
|
|
|
#ifdef MALLOC_STATS
|
1995-10-08 18:44:20 +00:00
|
|
|
if (malloc_stats)
|
|
|
|
malloc_dump(stderr);
|
Change phkmalloc so that the page directory is now floating and allocated
via mmap() up around the shared library area. Previously the directory
was allocated from space from it's own memory pool. Because of the way it
was being extended on processes with large malloced data segments (ie: inn)
once the page directory was extended for some reason, it was not possible
to lower the heap size any more to return pages to the OS.
(If my understanding is correct, page directory expansion occurs at 4MB,
12MB, 20MB, 28MB, etc.) I was seeing INN allocate a large amount of short
term memory, pushing it over the 28MB mark, and once it's transient demands
hit 28MB, it never freed it's pages and swap space again.)
I've been running this in my libc for about a month...
Also, seperate MALLOC_STATS from EXTRA_SANITY.. I found it useful to call
malloc_dump() from within INN from a ctlinnd command to see where the hell
all the memory was going.. :-) I've left MALLOC_STATS enabled, as it has
no run-time or data storage cost.
Reviewed by: phk
1995-12-11 14:28:12 +00:00
|
|
|
#endif /* MALLOC_STATS */
|
1995-09-16 09:28:13 +00:00
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
wrtwarning(char *p)
|
|
|
|
{
|
1995-10-08 18:44:20 +00:00
|
|
|
char *q = "Malloc warning: ";
|
|
|
|
if (malloc_abort)
|
|
|
|
wrterror(p);
|
1996-09-23 19:26:39 +00:00
|
|
|
write(2, q, strlen(q));
|
|
|
|
write(2, malloc_func, strlen(malloc_func));
|
|
|
|
write(2, p, strlen(p));
|
1995-09-16 09:28:13 +00:00
|
|
|
}
|
|
|
|
|
1995-10-08 18:44:20 +00:00
|
|
|
#ifdef EXTRA_SANITY
|
1995-09-16 09:28:13 +00:00
|
|
|
static void
|
|
|
|
malloc_exit()
|
|
|
|
{
|
1996-09-23 19:26:39 +00:00
|
|
|
FILE *fd = fopen("malloc.out", "a");
|
1995-09-22 14:11:00 +00:00
|
|
|
char *q = "malloc() warning: Couldn't dump stats.\n";
|
|
|
|
if (fd) {
|
1995-09-16 09:28:13 +00:00
|
|
|
malloc_dump(fd);
|
1995-09-22 14:11:00 +00:00
|
|
|
fclose(fd);
|
|
|
|
} else
|
1996-09-23 19:26:39 +00:00
|
|
|
write(2, q, strlen(q));
|
1995-09-16 09:28:13 +00:00
|
|
|
}
|
1995-10-08 18:44:20 +00:00
|
|
|
#endif /* EXTRA_SANITY */
|
1995-09-16 09:28:13 +00:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Allocate a number of pages from the OS
|
|
|
|
*/
|
|
|
|
static caddr_t
|
1996-01-05 23:30:41 +00:00
|
|
|
map_pages(int pages)
|
1995-09-16 09:28:13 +00:00
|
|
|
{
|
1996-09-23 19:26:39 +00:00
|
|
|
caddr_t result, tail;
|
1995-09-16 09:28:13 +00:00
|
|
|
|
1995-10-08 18:44:20 +00:00
|
|
|
result = (caddr_t)pageround((u_long)sbrk(0));
|
1995-09-16 09:28:13 +00:00
|
|
|
tail = result + (pages << malloc_pageshift);
|
1995-10-08 18:44:20 +00:00
|
|
|
|
|
|
|
if (brk(tail)) {
|
1995-09-16 09:28:13 +00:00
|
|
|
#ifdef EXTRA_SANITY
|
1996-09-23 19:26:39 +00:00
|
|
|
wrterror("(ES): map_pages fails\n");
|
1995-10-08 18:44:20 +00:00
|
|
|
#endif /* EXTRA_SANITY */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
last_index = ptr2index(tail) - 1;
|
|
|
|
malloc_brk = tail;
|
|
|
|
|
1996-01-05 23:30:41 +00:00
|
|
|
if ((last_index+1) >= malloc_ninfo && !extend_pgdir(last_index))
|
1995-10-08 18:44:20 +00:00
|
|
|
return 0;;
|
|
|
|
|
|
|
|
return result;
|
1995-09-16 09:28:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set a bit in the bitmap
|
|
|
|
*/
|
|
|
|
#ifndef set_bit
|
1996-09-25 08:30:46 +00:00
|
|
|
static __inline__ void
|
1995-09-16 09:28:13 +00:00
|
|
|
set_bit(struct pginfo *pi, int bit)
|
|
|
|
{
|
|
|
|
pi->bits[bit/MALLOC_BITS] |= 1<<(bit%MALLOC_BITS);
|
|
|
|
}
|
|
|
|
#endif /* set_bit */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Clear a bit in the bitmap
|
|
|
|
*/
|
|
|
|
#ifndef clr_bit
|
1996-09-25 08:30:46 +00:00
|
|
|
static __inline__ void
|
1995-09-16 09:28:13 +00:00
|
|
|
clr_bit(struct pginfo *pi, int bit)
|
|
|
|
{
|
|
|
|
pi->bits[bit/MALLOC_BITS] &= ~(1<<(bit%MALLOC_BITS));
|
|
|
|
}
|
|
|
|
#endif /* clr_bit */
|
|
|
|
|
|
|
|
#ifndef tst_bit
|
|
|
|
/*
|
|
|
|
* Test a bit in the bitmap
|
|
|
|
*/
|
1996-09-25 08:30:46 +00:00
|
|
|
static __inline__ int
|
1995-09-16 09:28:13 +00:00
|
|
|
tst_bit(struct pginfo *pi, int bit)
|
|
|
|
{
|
|
|
|
return pi->bits[bit/MALLOC_BITS] & (1<<(bit%MALLOC_BITS));
|
|
|
|
}
|
|
|
|
#endif /* tst_bit */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Find last bit
|
|
|
|
*/
|
|
|
|
#ifndef fls
|
1996-09-25 08:30:46 +00:00
|
|
|
static __inline__ int
|
1995-09-16 09:28:13 +00:00
|
|
|
fls(int size)
|
|
|
|
{
|
|
|
|
int i = 1;
|
|
|
|
while (size >>= 1)
|
|
|
|
i++;
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
#endif /* fls */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Extend page directory
|
|
|
|
*/
|
|
|
|
static int
|
1995-10-08 18:44:20 +00:00
|
|
|
extend_pgdir(u_long index)
|
1995-09-16 09:28:13 +00:00
|
|
|
{
|
1996-09-23 19:26:39 +00:00
|
|
|
struct pginfo **new, **old;
|
Change phkmalloc so that the page directory is now floating and allocated
via mmap() up around the shared library area. Previously the directory
was allocated from space from it's own memory pool. Because of the way it
was being extended on processes with large malloced data segments (ie: inn)
once the page directory was extended for some reason, it was not possible
to lower the heap size any more to return pages to the OS.
(If my understanding is correct, page directory expansion occurs at 4MB,
12MB, 20MB, 28MB, etc.) I was seeing INN allocate a large amount of short
term memory, pushing it over the 28MB mark, and once it's transient demands
hit 28MB, it never freed it's pages and swap space again.)
I've been running this in my libc for about a month...
Also, seperate MALLOC_STATS from EXTRA_SANITY.. I found it useful to call
malloc_dump() from within INN from a ctlinnd command to see where the hell
all the memory was going.. :-) I've left MALLOC_STATS enabled, as it has
no run-time or data storage cost.
Reviewed by: phk
1995-12-11 14:28:12 +00:00
|
|
|
int i, oldlen;
|
1995-09-16 09:28:13 +00:00
|
|
|
|
|
|
|
/* Make it this many pages */
|
|
|
|
i = index * sizeof *page_dir;
|
|
|
|
i /= malloc_pagesize;
|
|
|
|
i += 2;
|
|
|
|
|
Change phkmalloc so that the page directory is now floating and allocated
via mmap() up around the shared library area. Previously the directory
was allocated from space from it's own memory pool. Because of the way it
was being extended on processes with large malloced data segments (ie: inn)
once the page directory was extended for some reason, it was not possible
to lower the heap size any more to return pages to the OS.
(If my understanding is correct, page directory expansion occurs at 4MB,
12MB, 20MB, 28MB, etc.) I was seeing INN allocate a large amount of short
term memory, pushing it over the 28MB mark, and once it's transient demands
hit 28MB, it never freed it's pages and swap space again.)
I've been running this in my libc for about a month...
Also, seperate MALLOC_STATS from EXTRA_SANITY.. I found it useful to call
malloc_dump() from within INN from a ctlinnd command to see where the hell
all the memory was going.. :-) I've left MALLOC_STATS enabled, as it has
no run-time or data storage cost.
Reviewed by: phk
1995-12-11 14:28:12 +00:00
|
|
|
/* remember the old mapping size */
|
|
|
|
oldlen = malloc_ninfo * sizeof *page_dir;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* NOTE: we allocate new pages and copy the directory rather than tempt
|
|
|
|
* fate by trying to "grow" the region.. There is nothing to prevent
|
|
|
|
* us from accidently re-mapping space that's been allocated by our caller
|
|
|
|
* via dlopen() or other mmap().
|
|
|
|
*
|
|
|
|
* The copy problem is not too bad, as there is 4K of page index per
|
|
|
|
* 4MB of malloc arena.
|
|
|
|
*
|
|
|
|
* We can totally avoid the copy if we open a file descriptor to associate
|
|
|
|
* the anon mappings with. Then, when we remap the pages at the new
|
|
|
|
* address, the old pages will be "magically" remapped.. But this means
|
|
|
|
* keeping open a "secret" file descriptor.....
|
|
|
|
*/
|
|
|
|
|
1995-10-08 18:44:20 +00:00
|
|
|
/* Get new pages */
|
Change phkmalloc so that the page directory is now floating and allocated
via mmap() up around the shared library area. Previously the directory
was allocated from space from it's own memory pool. Because of the way it
was being extended on processes with large malloced data segments (ie: inn)
once the page directory was extended for some reason, it was not possible
to lower the heap size any more to return pages to the OS.
(If my understanding is correct, page directory expansion occurs at 4MB,
12MB, 20MB, 28MB, etc.) I was seeing INN allocate a large amount of short
term memory, pushing it over the 28MB mark, and once it's transient demands
hit 28MB, it never freed it's pages and swap space again.)
I've been running this in my libc for about a month...
Also, seperate MALLOC_STATS from EXTRA_SANITY.. I found it useful to call
malloc_dump() from within INN from a ctlinnd command to see where the hell
all the memory was going.. :-) I've left MALLOC_STATS enabled, as it has
no run-time or data storage cost.
Reviewed by: phk
1995-12-11 14:28:12 +00:00
|
|
|
new = (struct pginfo**) mmap(0, i * malloc_pagesize, PROT_READ|PROT_WRITE,
|
|
|
|
MAP_ANON|MAP_PRIVATE, -1, 0);
|
|
|
|
if (new == (struct pginfo **)-1)
|
1995-09-16 09:28:13 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Copy the old stuff */
|
|
|
|
memcpy(new, page_dir,
|
|
|
|
malloc_ninfo * sizeof *page_dir);
|
|
|
|
|
|
|
|
/* register the new size */
|
|
|
|
malloc_ninfo = i * malloc_pagesize / sizeof *page_dir;
|
|
|
|
|
|
|
|
/* swap the pointers */
|
|
|
|
old = page_dir;
|
|
|
|
page_dir = new;
|
|
|
|
|
|
|
|
/* Now free the old stuff */
|
Change phkmalloc so that the page directory is now floating and allocated
via mmap() up around the shared library area. Previously the directory
was allocated from space from it's own memory pool. Because of the way it
was being extended on processes with large malloced data segments (ie: inn)
once the page directory was extended for some reason, it was not possible
to lower the heap size any more to return pages to the OS.
(If my understanding is correct, page directory expansion occurs at 4MB,
12MB, 20MB, 28MB, etc.) I was seeing INN allocate a large amount of short
term memory, pushing it over the 28MB mark, and once it's transient demands
hit 28MB, it never freed it's pages and swap space again.)
I've been running this in my libc for about a month...
Also, seperate MALLOC_STATS from EXTRA_SANITY.. I found it useful to call
malloc_dump() from within INN from a ctlinnd command to see where the hell
all the memory was going.. :-) I've left MALLOC_STATS enabled, as it has
no run-time or data storage cost.
Reviewed by: phk
1995-12-11 14:28:12 +00:00
|
|
|
munmap((caddr_t)old, oldlen);
|
1995-09-16 09:28:13 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
1994-05-27 05:00:24 +00:00
|
|
|
/*
|
1995-09-16 09:28:13 +00:00
|
|
|
* Initialize the world
|
1994-05-27 05:00:24 +00:00
|
|
|
*/
|
|
|
|
static void
|
1995-09-16 09:28:13 +00:00
|
|
|
malloc_init ()
|
1994-05-27 05:00:24 +00:00
|
|
|
{
|
1996-09-23 19:26:39 +00:00
|
|
|
char *p, b[64];
|
|
|
|
int i, j;
|
|
|
|
|
1995-09-16 09:28:13 +00:00
|
|
|
|
1995-10-08 18:44:20 +00:00
|
|
|
#ifdef EXTRA_SANITY
|
|
|
|
malloc_junk = 1;
|
|
|
|
#endif /* EXTRA_SANITY */
|
|
|
|
|
1996-09-23 19:26:39 +00:00
|
|
|
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;
|
Change phkmalloc so that the page directory is now floating and allocated
via mmap() up around the shared library area. Previously the directory
was allocated from space from it's own memory pool. Because of the way it
was being extended on processes with large malloced data segments (ie: inn)
once the page directory was extended for some reason, it was not possible
to lower the heap size any more to return pages to the OS.
(If my understanding is correct, page directory expansion occurs at 4MB,
12MB, 20MB, 28MB, etc.) I was seeing INN allocate a large amount of short
term memory, pushing it over the 28MB mark, and once it's transient demands
hit 28MB, it never freed it's pages and swap space again.)
I've been running this in my libc for about a month...
Also, seperate MALLOC_STATS from EXTRA_SANITY.. I found it useful to call
malloc_dump() from within INN from a ctlinnd command to see where the hell
all the memory was going.. :-) I've left MALLOC_STATS enabled, as it has
no run-time or data storage cost.
Reviewed by: phk
1995-12-11 14:28:12 +00:00
|
|
|
#ifdef MALLOC_STATS
|
1996-09-23 19:26:39 +00:00
|
|
|
case 'd': malloc_stats = 0; break;
|
|
|
|
case 'D': malloc_stats = 1; break;
|
Change phkmalloc so that the page directory is now floating and allocated
via mmap() up around the shared library area. Previously the directory
was allocated from space from it's own memory pool. Because of the way it
was being extended on processes with large malloced data segments (ie: inn)
once the page directory was extended for some reason, it was not possible
to lower the heap size any more to return pages to the OS.
(If my understanding is correct, page directory expansion occurs at 4MB,
12MB, 20MB, 28MB, etc.) I was seeing INN allocate a large amount of short
term memory, pushing it over the 28MB mark, and once it's transient demands
hit 28MB, it never freed it's pages and swap space again.)
I've been running this in my libc for about a month...
Also, seperate MALLOC_STATS from EXTRA_SANITY.. I found it useful to call
malloc_dump() from within INN from a ctlinnd command to see where the hell
all the memory was going.. :-) I've left MALLOC_STATS enabled, as it has
no run-time or data storage cost.
Reviewed by: phk
1995-12-11 14:28:12 +00:00
|
|
|
#endif /* MALLOC_STATS */
|
1996-09-23 19:26:39 +00:00
|
|
|
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;
|
1996-09-25 08:30:46 +00:00
|
|
|
#ifdef __FreeBSD__
|
1996-09-23 19:26:39 +00:00
|
|
|
case 'u': malloc_utrace = 0; break;
|
|
|
|
case 'U': malloc_utrace = 1; break;
|
1996-09-25 08:30:46 +00:00
|
|
|
#endif /* !__FreeBSD__ */
|
1996-09-23 19:26:39 +00:00
|
|
|
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;
|
|
|
|
}
|
1994-05-27 05:00:24 +00:00
|
|
|
}
|
1995-09-16 09:28:13 +00:00
|
|
|
}
|
|
|
|
|
1996-09-23 19:26:39 +00:00
|
|
|
UTRACE(0, 0, 0);
|
|
|
|
|
1995-10-08 18:44:20 +00:00
|
|
|
/*
|
|
|
|
* We want junk in the entire allocation, and zero only in the part
|
|
|
|
* the user asked for.
|
|
|
|
*/
|
|
|
|
if (malloc_zero)
|
|
|
|
malloc_junk=1;
|
|
|
|
|
|
|
|
#ifdef EXTRA_SANITY
|
1995-09-16 09:28:13 +00:00
|
|
|
if (malloc_stats)
|
|
|
|
atexit(malloc_exit);
|
1995-10-08 18:44:20 +00:00
|
|
|
#endif /* EXTRA_SANITY */
|
1995-09-16 09:28:13 +00:00
|
|
|
|
|
|
|
#ifndef malloc_pagesize
|
|
|
|
/* determine our pagesize */
|
|
|
|
malloc_pagesize = getpagesize();
|
|
|
|
#endif /* malloc_pagesize */
|
|
|
|
|
1995-10-08 18:44:20 +00:00
|
|
|
#ifndef malloc_maxsize
|
|
|
|
malloc_maxsize = malloc_pagesize >> 1;
|
|
|
|
#endif /* malloc_maxsize */
|
|
|
|
|
1995-09-16 09:28:13 +00:00
|
|
|
#ifndef malloc_pageshift
|
1995-10-22 14:47:00 +00:00
|
|
|
{
|
|
|
|
int i;
|
1995-09-16 09:28:13 +00:00
|
|
|
/* determine how much we shift by to get there */
|
|
|
|
for (i = malloc_pagesize; i > 1; i >>= 1)
|
|
|
|
malloc_pageshift++;
|
1995-10-22 14:47:00 +00:00
|
|
|
}
|
1995-09-16 09:28:13 +00:00
|
|
|
#endif /* malloc_pageshift */
|
|
|
|
|
|
|
|
#ifndef malloc_minsize
|
1995-10-22 14:47:00 +00:00
|
|
|
{
|
|
|
|
int i;
|
1995-09-16 09:28:13 +00:00
|
|
|
/*
|
|
|
|
* find the smallest size allocation we will bother about.
|
|
|
|
* this is determined as the smallest allocation that can hold
|
|
|
|
* it's own pginfo;
|
|
|
|
*/
|
|
|
|
i = 2;
|
|
|
|
for(;;) {
|
|
|
|
int j;
|
|
|
|
|
|
|
|
/* Figure out the size of the bits */
|
|
|
|
j = malloc_pagesize/i;
|
|
|
|
j /= 8;
|
|
|
|
if (j < sizeof(u_long))
|
|
|
|
j = sizeof (u_long);
|
|
|
|
if (sizeof(struct pginfo) + j - sizeof (u_long) <= i)
|
|
|
|
break;
|
|
|
|
i += i;
|
|
|
|
}
|
|
|
|
malloc_minsize = i;
|
1995-10-22 14:47:00 +00:00
|
|
|
}
|
1995-09-16 09:28:13 +00:00
|
|
|
#endif /* malloc_minsize */
|
|
|
|
|
|
|
|
/* Allocate one page for the page directory */
|
Change phkmalloc so that the page directory is now floating and allocated
via mmap() up around the shared library area. Previously the directory
was allocated from space from it's own memory pool. Because of the way it
was being extended on processes with large malloced data segments (ie: inn)
once the page directory was extended for some reason, it was not possible
to lower the heap size any more to return pages to the OS.
(If my understanding is correct, page directory expansion occurs at 4MB,
12MB, 20MB, 28MB, etc.) I was seeing INN allocate a large amount of short
term memory, pushing it over the 28MB mark, and once it's transient demands
hit 28MB, it never freed it's pages and swap space again.)
I've been running this in my libc for about a month...
Also, seperate MALLOC_STATS from EXTRA_SANITY.. I found it useful to call
malloc_dump() from within INN from a ctlinnd command to see where the hell
all the memory was going.. :-) I've left MALLOC_STATS enabled, as it has
no run-time or data storage cost.
Reviewed by: phk
1995-12-11 14:28:12 +00:00
|
|
|
page_dir = (struct pginfo **) mmap(0, malloc_pagesize, PROT_READ|PROT_WRITE,
|
|
|
|
MAP_ANON|MAP_PRIVATE, -1, 0);
|
|
|
|
if (page_dir == (struct pginfo **) -1)
|
1996-09-23 19:26:39 +00:00
|
|
|
wrterror("mmap(2) failed, check limits.\n");
|
1995-09-16 09:28:13 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We need a maximum of malloc_pageshift buckets, steal these from the
|
|
|
|
* front of the page_directory;
|
|
|
|
*/
|
Change phkmalloc so that the page directory is now floating and allocated
via mmap() up around the shared library area. Previously the directory
was allocated from space from it's own memory pool. Because of the way it
was being extended on processes with large malloced data segments (ie: inn)
once the page directory was extended for some reason, it was not possible
to lower the heap size any more to return pages to the OS.
(If my understanding is correct, page directory expansion occurs at 4MB,
12MB, 20MB, 28MB, etc.) I was seeing INN allocate a large amount of short
term memory, pushing it over the 28MB mark, and once it's transient demands
hit 28MB, it never freed it's pages and swap space again.)
I've been running this in my libc for about a month...
Also, seperate MALLOC_STATS from EXTRA_SANITY.. I found it useful to call
malloc_dump() from within INN from a ctlinnd command to see where the hell
all the memory was going.. :-) I've left MALLOC_STATS enabled, as it has
no run-time or data storage cost.
Reviewed by: phk
1995-12-11 14:28:12 +00:00
|
|
|
malloc_origo = ((u_long)pageround((u_long)sbrk(0))) >> malloc_pageshift;
|
1995-09-16 09:28:13 +00:00
|
|
|
malloc_origo -= malloc_pageshift;
|
|
|
|
|
|
|
|
malloc_ninfo = malloc_pagesize / sizeof *page_dir;
|
|
|
|
|
|
|
|
/* Been here, done that */
|
|
|
|
initialized++;
|
1995-12-18 12:03:54 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
1996-09-23 19:26:39 +00:00
|
|
|
px = (struct pgfree *) imalloc (sizeof *px);
|
1996-09-25 08:30:46 +00:00
|
|
|
|
|
|
|
if (!malloc_cache)
|
|
|
|
malloc_cache++;
|
|
|
|
|
|
|
|
malloc_cache <<= malloc_pageshift;
|
1994-05-27 05:00:24 +00:00
|
|
|
}
|
|
|
|
|
1995-09-16 09:28:13 +00:00
|
|
|
/*
|
|
|
|
* Allocate a number of complete pages
|
|
|
|
*/
|
|
|
|
void *
|
|
|
|
malloc_pages(size_t size)
|
1995-05-30 05:51:47 +00:00
|
|
|
{
|
1996-09-23 19:26:39 +00:00
|
|
|
void *p, *delay_free = 0;
|
1995-09-16 09:28:13 +00:00
|
|
|
int i;
|
|
|
|
struct pgfree *pf;
|
|
|
|
u_long index;
|
|
|
|
|
1995-10-08 18:44:20 +00:00
|
|
|
size = pageround(size);
|
1995-09-16 09:28:13 +00:00
|
|
|
|
|
|
|
p = 0;
|
|
|
|
/* Look for free pages before asking for more */
|
|
|
|
for(pf = free_list.next; pf; pf = pf->next) {
|
1995-10-08 18:44:20 +00:00
|
|
|
|
1995-09-16 09:28:13 +00:00
|
|
|
#ifdef EXTRA_SANITY
|
1995-10-08 18:44:20 +00:00
|
|
|
if (pf->size & malloc_pagemask)
|
|
|
|
wrterror("(ES): junk length entry on free_list\n");
|
|
|
|
if (!pf->size)
|
|
|
|
wrterror("(ES): zero length entry on free_list\n");
|
1995-09-16 09:28:13 +00:00
|
|
|
if (pf->page == pf->end)
|
1995-10-08 18:44:20 +00:00
|
|
|
wrterror("(ES): zero entry on free_list\n");
|
|
|
|
if (pf->page > pf->end)
|
|
|
|
wrterror("(ES): sick entry on free_list\n");
|
|
|
|
if ((void*)pf->page >= (void*)sbrk(0))
|
|
|
|
wrterror("(ES): entry on free_list past brk\n");
|
|
|
|
if (page_dir[ptr2index(pf->page)] != MALLOC_FREE)
|
|
|
|
wrterror("(ES): non-free first page on free-list\n");
|
|
|
|
if (page_dir[ptr2index(pf->end)-1] != MALLOC_FREE)
|
|
|
|
wrterror("(ES): non-free last page on free-list\n");
|
1995-09-16 09:28:13 +00:00
|
|
|
#endif /* EXTRA_SANITY */
|
1995-10-08 18:44:20 +00:00
|
|
|
|
|
|
|
if (pf->size < size)
|
1995-09-16 09:28:13 +00:00
|
|
|
continue;
|
1995-10-08 18:44:20 +00:00
|
|
|
|
|
|
|
if (pf->size == size) {
|
1995-09-16 09:28:13 +00:00
|
|
|
p = pf->page;
|
|
|
|
if (pf->next)
|
|
|
|
pf->next->prev = pf->prev;
|
|
|
|
pf->prev->next = pf->next;
|
|
|
|
delay_free = pf;
|
|
|
|
break;
|
1995-10-08 18:44:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
p = pf->page;
|
1996-09-25 08:30:46 +00:00
|
|
|
pf->page = (char *)pg->page + size;
|
1995-10-08 18:44:20 +00:00
|
|
|
pf->size -= size;
|
|
|
|
break;
|
1995-09-16 09:28:13 +00:00
|
|
|
}
|
1995-10-08 18:44:20 +00:00
|
|
|
|
1995-09-16 09:28:13 +00:00
|
|
|
#ifdef EXTRA_SANITY
|
1995-10-08 18:44:20 +00:00
|
|
|
if (p && page_dir[ptr2index(p)] != MALLOC_FREE)
|
|
|
|
wrterror("(ES): allocated non-free page on free-list\n");
|
1995-09-16 09:28:13 +00:00
|
|
|
#endif /* EXTRA_SANITY */
|
|
|
|
|
|
|
|
size >>= malloc_pageshift;
|
|
|
|
|
|
|
|
/* Map new pages */
|
|
|
|
if (!p)
|
1996-01-05 23:30:41 +00:00
|
|
|
p = map_pages(size);
|
1995-09-16 09:28:13 +00:00
|
|
|
|
|
|
|
if (p) {
|
1995-10-08 18:44:20 +00:00
|
|
|
|
|
|
|
index = ptr2index(p);
|
1995-09-16 09:28:13 +00:00
|
|
|
page_dir[index] = MALLOC_FIRST;
|
|
|
|
for (i=1;i<size;i++)
|
|
|
|
page_dir[index+i] = MALLOC_FOLLOW;
|
1995-10-08 18:44:20 +00:00
|
|
|
|
|
|
|
if (malloc_junk)
|
1996-09-23 19:26:39 +00:00
|
|
|
memset(p, SOME_JUNK, size << malloc_pageshift);
|
1995-09-16 09:28:13 +00:00
|
|
|
}
|
1995-10-08 18:44:20 +00:00
|
|
|
|
1995-09-16 09:28:13 +00:00
|
|
|
if (delay_free) {
|
1995-10-08 18:44:20 +00:00
|
|
|
if (!px)
|
1995-09-16 09:28:13 +00:00
|
|
|
px = delay_free;
|
|
|
|
else
|
1996-09-23 19:26:39 +00:00
|
|
|
ifree(delay_free);
|
1995-09-16 09:28:13 +00:00
|
|
|
}
|
1995-10-08 18:44:20 +00:00
|
|
|
|
1995-09-16 09:28:13 +00:00
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Allocate a page of fragments
|
|
|
|
*/
|
|
|
|
|
1996-09-25 08:30:46 +00:00
|
|
|
static __inline__ int
|
1995-09-16 09:28:13 +00:00
|
|
|
malloc_make_chunks(int bits)
|
|
|
|
{
|
|
|
|
struct pginfo *bp;
|
|
|
|
void *pp;
|
1996-09-23 19:26:39 +00:00
|
|
|
int i, k, l;
|
1995-09-16 09:28:13 +00:00
|
|
|
|
|
|
|
/* Allocate a new bucket */
|
|
|
|
pp = malloc_pages(malloc_pagesize);
|
|
|
|
if (!pp)
|
|
|
|
return 0;
|
1995-10-08 18:44:20 +00:00
|
|
|
|
|
|
|
/* Find length of admin structure */
|
1995-09-16 09:28:13 +00:00
|
|
|
l = sizeof *bp - sizeof(u_long);
|
|
|
|
l += sizeof(u_long) *
|
|
|
|
(((malloc_pagesize >> bits)+MALLOC_BITS-1) / MALLOC_BITS);
|
1995-10-08 18:44:20 +00:00
|
|
|
|
|
|
|
/* Don't waste more than two chunks on this */
|
1995-09-16 09:28:13 +00:00
|
|
|
if ((1<<(bits)) <= l+l) {
|
|
|
|
bp = (struct pginfo *)pp;
|
|
|
|
} else {
|
1996-09-23 19:26:39 +00:00
|
|
|
bp = (struct pginfo *)imalloc(l);
|
1995-10-08 18:44:20 +00:00
|
|
|
if (!bp)
|
|
|
|
return 0;
|
1995-09-16 09:28:13 +00:00
|
|
|
}
|
1995-10-08 18:44:20 +00:00
|
|
|
|
1995-09-16 09:28:13 +00:00
|
|
|
bp->size = (1<<bits);
|
|
|
|
bp->shift = bits;
|
|
|
|
bp->total = bp->free = malloc_pagesize >> bits;
|
|
|
|
bp->page = pp;
|
|
|
|
|
1995-10-08 18:44:20 +00:00
|
|
|
page_dir[ptr2index(pp)] = bp;
|
|
|
|
|
|
|
|
bp->next = page_dir[bits];
|
1995-09-16 09:28:13 +00:00
|
|
|
page_dir[bits] = bp;
|
|
|
|
|
|
|
|
/* set all valid bits in the bits */
|
|
|
|
k = bp->total;
|
|
|
|
i = 0;
|
1995-10-08 18:44:20 +00:00
|
|
|
|
|
|
|
/* Do a bunch at a time */
|
1995-09-16 09:28:13 +00:00
|
|
|
for(;k-i >= MALLOC_BITS; i += MALLOC_BITS)
|
|
|
|
bp->bits[i / MALLOC_BITS] = ~0;
|
1995-10-08 18:44:20 +00:00
|
|
|
|
1995-09-16 09:28:13 +00:00
|
|
|
for(; i < k; i++)
|
1996-09-23 19:26:39 +00:00
|
|
|
set_bit(bp, i);
|
1995-09-16 09:28:13 +00:00
|
|
|
|
1995-10-08 18:44:20 +00:00
|
|
|
if (bp == bp->page) {
|
|
|
|
/* Mark the ones we stole for ourselves */
|
|
|
|
for(i=0;l > 0;i++) {
|
1996-09-23 19:26:39 +00:00
|
|
|
clr_bit(bp, i);
|
1995-10-08 18:44:20 +00:00
|
|
|
bp->free--;
|
|
|
|
bp->total--;
|
|
|
|
l -= (1 << bits);
|
|
|
|
}
|
1995-09-16 09:28:13 +00:00
|
|
|
}
|
1995-10-08 18:44:20 +00:00
|
|
|
|
1995-09-16 09:28:13 +00:00
|
|
|
return 1;
|
1994-05-27 05:00:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
1995-09-16 09:28:13 +00:00
|
|
|
* Allocate a fragment
|
1994-05-27 05:00:24 +00:00
|
|
|
*/
|
1995-09-16 09:28:13 +00:00
|
|
|
static void *
|
|
|
|
malloc_bytes(size_t size)
|
|
|
|
{
|
|
|
|
int j;
|
|
|
|
struct pginfo *bp;
|
|
|
|
int k;
|
|
|
|
u_long *lp;
|
|
|
|
|
|
|
|
/* Don't bother with anything less than this */
|
|
|
|
if (size < malloc_minsize)
|
|
|
|
size = malloc_minsize;
|
|
|
|
|
|
|
|
/* Find the right bucket */
|
|
|
|
j = fls((size)-1);
|
|
|
|
|
|
|
|
/* If it's empty, make a page more of that size chunks */
|
|
|
|
if (!page_dir[j] && !malloc_make_chunks(j))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
bp = page_dir[j];
|
|
|
|
|
|
|
|
/* Find first word of bitmap which isn't empty */
|
|
|
|
for (lp = bp->bits; !*lp; lp++)
|
|
|
|
;
|
|
|
|
|
1995-10-08 18:44:20 +00:00
|
|
|
/* Find that bit, and tweak it */
|
1995-09-16 09:28:13 +00:00
|
|
|
k = ffs(*lp) - 1;
|
|
|
|
*lp ^= 1<<k;
|
1995-10-08 18:44:20 +00:00
|
|
|
|
|
|
|
/* If there are no more free, remove from free-list */
|
|
|
|
if (!--bp->free) {
|
1995-09-16 09:28:13 +00:00
|
|
|
page_dir[j] = bp->next;
|
|
|
|
bp->next = 0;
|
|
|
|
}
|
1995-10-08 18:44:20 +00:00
|
|
|
|
|
|
|
/* Adjust to the real offset of that chunk */
|
1995-09-16 09:28:13 +00:00
|
|
|
k += (lp-bp->bits)*MALLOC_BITS;
|
1995-10-08 18:44:20 +00:00
|
|
|
k <<= bp->shift;
|
|
|
|
|
|
|
|
if (malloc_junk)
|
|
|
|
memset(bp->page + k, SOME_JUNK, bp->size);
|
|
|
|
|
|
|
|
return bp->page + k;
|
1995-09-16 09:28:13 +00:00
|
|
|
}
|
1994-05-27 05:00:24 +00:00
|
|
|
|
1995-09-16 09:28:13 +00:00
|
|
|
/*
|
|
|
|
* Allocate a piece of memory
|
|
|
|
*/
|
1996-09-23 19:26:39 +00:00
|
|
|
static void *
|
1996-07-03 05:03:07 +00:00
|
|
|
imalloc(size_t size)
|
1995-05-30 05:51:47 +00:00
|
|
|
{
|
1995-09-16 09:28:13 +00:00
|
|
|
void *result;
|
|
|
|
|
|
|
|
if (!initialized)
|
|
|
|
malloc_init();
|
|
|
|
|
|
|
|
if (suicide)
|
|
|
|
abort();
|
|
|
|
|
|
|
|
if (size <= malloc_maxsize)
|
|
|
|
result = malloc_bytes(size);
|
|
|
|
else
|
|
|
|
result = malloc_pages(size);
|
1995-10-08 18:44:20 +00:00
|
|
|
|
1995-09-16 09:28:13 +00:00
|
|
|
if (malloc_abort && !result)
|
1996-09-23 19:26:39 +00:00
|
|
|
wrterror("allocation failed.\n");
|
1995-10-08 18:44:20 +00:00
|
|
|
|
|
|
|
if (malloc_zero)
|
1996-09-23 19:26:39 +00:00
|
|
|
memset(result, 0, size);
|
1995-10-08 18:44:20 +00:00
|
|
|
|
1995-09-16 09:28:13 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
1995-10-08 18:44:20 +00:00
|
|
|
* Change the size of an allocation.
|
1995-09-16 09:28:13 +00:00
|
|
|
*/
|
1996-09-23 19:26:39 +00:00
|
|
|
static void *
|
1996-07-03 05:03:07 +00:00
|
|
|
irealloc(void *ptr, size_t size)
|
1995-09-16 09:28:13 +00:00
|
|
|
{
|
|
|
|
void *p;
|
1996-09-23 19:26:39 +00:00
|
|
|
u_long osize, index;
|
1995-09-16 09:28:13 +00:00
|
|
|
struct pginfo **mp;
|
1995-10-08 18:44:20 +00:00
|
|
|
int i;
|
1995-09-16 09:28:13 +00:00
|
|
|
|
|
|
|
if (suicide)
|
1995-10-08 18:44:20 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!initialized) {
|
1996-09-23 19:26:39 +00:00
|
|
|
wrtwarning("malloc() has never been called.\n");
|
1995-09-16 09:28:13 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
1995-10-08 18:44:20 +00:00
|
|
|
index = ptr2index(ptr);
|
1995-09-16 09:28:13 +00:00
|
|
|
|
1995-10-08 18:44:20 +00:00
|
|
|
if (index < malloc_pageshift) {
|
1996-09-23 19:26:39 +00:00
|
|
|
wrtwarning("junk pointer, too low to make sense.\n");
|
1995-10-08 18:44:20 +00:00
|
|
|
return 0;
|
|
|
|
}
|
1995-09-16 09:28:13 +00:00
|
|
|
|
1995-10-08 18:44:20 +00:00
|
|
|
if (index > last_index) {
|
1996-09-23 19:26:39 +00:00
|
|
|
wrtwarning("junk pointer, too high to make sense.\n");
|
1995-09-16 09:28:13 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
mp = &page_dir[index];
|
1995-10-08 18:44:20 +00:00
|
|
|
|
|
|
|
if (*mp == MALLOC_FIRST) { /* Page allocation */
|
|
|
|
|
|
|
|
/* Check the pointer */
|
|
|
|
if ((u_long)ptr & malloc_pagemask) {
|
1996-09-23 19:26:39 +00:00
|
|
|
wrtwarning("modified (page-) pointer.\n");
|
1995-10-08 18:44:20 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Find the size in bytes */
|
|
|
|
for (osize = malloc_pagesize; *++mp == MALLOC_FOLLOW;)
|
1995-09-16 09:28:13 +00:00
|
|
|
osize += malloc_pagesize;
|
1995-10-08 18:44:20 +00:00
|
|
|
|
|
|
|
if (!malloc_realloc && /* unless we have to, */
|
|
|
|
size <= osize && /* .. or are too small, */
|
1996-01-22 00:02:33 +00:00
|
|
|
size > (osize - malloc_pagesize)) { /* .. or can free a page, */
|
1995-10-08 18:44:20 +00:00
|
|
|
return ptr; /* don't do anything. */
|
1996-01-22 00:02:33 +00:00
|
|
|
}
|
1995-10-08 18:44:20 +00:00
|
|
|
|
|
|
|
} else if (*mp >= MALLOC_MAGIC) { /* Chunk allocation */
|
|
|
|
|
|
|
|
/* Check the pointer for sane values */
|
|
|
|
if (((u_long)ptr & ((*mp)->size-1))) {
|
1996-09-23 19:26:39 +00:00
|
|
|
wrtwarning("modified (chunk-) pointer.\n");
|
1995-10-08 18:44:20 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Find the chunk index in the page */
|
|
|
|
i = ((u_long)ptr & malloc_pagemask) >> (*mp)->shift;
|
|
|
|
|
|
|
|
/* Verify that it isn't a free chunk already */
|
1996-09-23 19:26:39 +00:00
|
|
|
if (tst_bit(*mp, i)) {
|
|
|
|
wrtwarning("chunk is already free.\n");
|
1995-10-08 18:44:20 +00:00
|
|
|
return 0;
|
1994-05-27 05:00:24 +00:00
|
|
|
}
|
1995-10-08 18:44:20 +00:00
|
|
|
|
1995-09-16 09:28:13 +00:00
|
|
|
osize = (*mp)->size;
|
1995-10-08 18:44:20 +00:00
|
|
|
|
|
|
|
if (!malloc_realloc && /* Unless we have to, */
|
|
|
|
size < osize && /* ..or are too small, */
|
|
|
|
(size > osize/2 || /* ..or could use a smaller size, */
|
1996-01-22 00:02:33 +00:00
|
|
|
osize == malloc_minsize)) { /* ..(if there is one) */
|
1995-10-08 18:44:20 +00:00
|
|
|
return ptr; /* ..Don't do anything */
|
1996-01-22 00:02:33 +00:00
|
|
|
}
|
1995-10-08 18:44:20 +00:00
|
|
|
|
1995-09-16 09:28:13 +00:00
|
|
|
} else {
|
1996-09-23 19:26:39 +00:00
|
|
|
wrtwarning("pointer to wrong page.\n");
|
1995-10-08 18:44:20 +00:00
|
|
|
return 0;
|
1995-09-16 09:28:13 +00:00
|
|
|
}
|
|
|
|
|
1996-09-23 19:26:39 +00:00
|
|
|
p = imalloc(size);
|
1995-09-16 09:28:13 +00:00
|
|
|
|
|
|
|
if (p) {
|
1995-10-08 18:44:20 +00:00
|
|
|
/* copy the lesser of the two sizes, and free the old one */
|
1995-09-16 09:28:13 +00:00
|
|
|
if (osize < size)
|
1996-09-23 19:26:39 +00:00
|
|
|
memcpy(p, ptr, osize);
|
1994-05-27 05:00:24 +00:00
|
|
|
else
|
1996-09-23 19:26:39 +00:00
|
|
|
memcpy(p, ptr, size);
|
|
|
|
ifree(ptr);
|
1995-10-08 18:44:20 +00:00
|
|
|
}
|
1995-09-16 09:28:13 +00:00
|
|
|
return p;
|
1994-05-27 05:00:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
1995-09-16 09:28:13 +00:00
|
|
|
* Free a sequence of pages
|
1994-05-27 05:00:24 +00:00
|
|
|
*/
|
1995-09-16 09:28:13 +00:00
|
|
|
|
1996-09-25 08:30:46 +00:00
|
|
|
static __inline__ void
|
1995-10-08 18:44:20 +00:00
|
|
|
free_pages(void *ptr, int index, struct pginfo *info)
|
1994-05-27 05:00:24 +00:00
|
|
|
{
|
1995-09-16 09:28:13 +00:00
|
|
|
int i;
|
1996-09-23 19:26:39 +00:00
|
|
|
struct pgfree *pf, *pt=0;
|
1995-09-16 09:28:13 +00:00
|
|
|
u_long l;
|
|
|
|
void *tail;
|
|
|
|
|
|
|
|
if (info == MALLOC_FREE) {
|
1996-09-23 19:26:39 +00:00
|
|
|
wrtwarning("page is already free.\n");
|
1995-09-16 09:28:13 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
1995-10-08 18:44:20 +00:00
|
|
|
if (info != MALLOC_FIRST) {
|
1996-09-23 19:26:39 +00:00
|
|
|
wrtwarning("pointer to wrong page.\n");
|
1995-10-08 18:44:20 +00:00
|
|
|
return;
|
|
|
|
}
|
1995-09-16 09:28:13 +00:00
|
|
|
|
1995-10-08 18:44:20 +00:00
|
|
|
if ((u_long)ptr & malloc_pagemask) {
|
1996-09-23 19:26:39 +00:00
|
|
|
wrtwarning("modified (page-) pointer.\n");
|
1995-10-08 18:44:20 +00:00
|
|
|
return;
|
|
|
|
}
|
1995-09-16 09:28:13 +00:00
|
|
|
|
1995-10-08 18:44:20 +00:00
|
|
|
/* Count how many pages and mark them free at the same time */
|
1995-09-16 09:28:13 +00:00
|
|
|
page_dir[index] = MALLOC_FREE;
|
|
|
|
for (i = 1; page_dir[index+i] == MALLOC_FOLLOW; i++)
|
|
|
|
page_dir[index + i] = MALLOC_FREE;
|
|
|
|
|
|
|
|
l = i << malloc_pageshift;
|
|
|
|
|
1996-09-23 19:26:39 +00:00
|
|
|
if (malloc_hint)
|
|
|
|
madvise(ptr, l, MADV_FREE);
|
|
|
|
|
1996-09-25 08:30:46 +00:00
|
|
|
tail = (char *)ptr+l;
|
1995-09-16 09:28:13 +00:00
|
|
|
|
|
|
|
/* add to free-list */
|
|
|
|
if (!px)
|
1996-09-23 19:26:39 +00:00
|
|
|
px = imalloc(sizeof *pt); /* This cannot fail... */
|
1995-09-16 09:28:13 +00:00
|
|
|
px->page = ptr;
|
|
|
|
px->end = tail;
|
|
|
|
px->size = l;
|
|
|
|
if (!free_list.next) {
|
1995-10-08 18:44:20 +00:00
|
|
|
|
|
|
|
/* Nothing on free list, put this at head */
|
1995-09-16 09:28:13 +00:00
|
|
|
px->next = free_list.next;
|
|
|
|
px->prev = &free_list;
|
|
|
|
free_list.next = px;
|
|
|
|
pf = px;
|
|
|
|
px = 0;
|
1995-10-08 18:44:20 +00:00
|
|
|
|
1995-09-16 09:28:13 +00:00
|
|
|
} else {
|
1995-10-08 18:44:20 +00:00
|
|
|
|
|
|
|
/* Find the right spot, leave pf pointing to the modified entry. */
|
1996-09-25 08:30:46 +00:00
|
|
|
tail = (char *)ptr+l;
|
1995-10-08 18:44:20 +00:00
|
|
|
|
|
|
|
for(pf = free_list.next; pf->end < ptr && pf->next; pf = pf->next)
|
|
|
|
; /* Race ahead here */
|
|
|
|
|
|
|
|
if (pf->page > tail) {
|
|
|
|
/* Insert before entry */
|
|
|
|
px->next = pf;
|
|
|
|
px->prev = pf->prev;
|
|
|
|
pf->prev = px;
|
|
|
|
px->prev->next = px;
|
|
|
|
pf = px;
|
|
|
|
px = 0;
|
|
|
|
} else if (pf->end == ptr ) {
|
1995-12-18 12:03:54 +00:00
|
|
|
/* Append to the previous entry */
|
1996-09-25 08:30:46 +00:00
|
|
|
pf->end = (char *)pf->end + l;
|
1995-10-08 18:44:20 +00:00
|
|
|
pf->size += l;
|
|
|
|
if (pf->next && pf->end == pf->next->page ) {
|
|
|
|
/* And collapse the next too. */
|
|
|
|
pt = pf->next;
|
|
|
|
pf->end = pt->end;
|
|
|
|
pf->size += pt->size;
|
|
|
|
pf->next = pt->next;
|
|
|
|
if (pf->next)
|
|
|
|
pf->next->prev = pf;
|
1995-09-16 09:28:13 +00:00
|
|
|
}
|
1995-10-08 18:44:20 +00:00
|
|
|
} else if (pf->page == tail) {
|
|
|
|
/* Prepend to entry */
|
|
|
|
pf->size += l;
|
|
|
|
pf->page = ptr;
|
|
|
|
} else if (!pf->next) {
|
|
|
|
/* Append at tail of chain */
|
|
|
|
px->next = 0;
|
|
|
|
px->prev = pf;
|
|
|
|
pf->next = px;
|
|
|
|
pf = px;
|
|
|
|
px = 0;
|
|
|
|
} else {
|
1996-09-23 19:26:39 +00:00
|
|
|
wrterror("freelist is destroyed.\n");
|
1994-05-27 05:00:24 +00:00
|
|
|
}
|
1995-09-16 09:28:13 +00:00
|
|
|
}
|
1995-10-08 18:44:20 +00:00
|
|
|
|
|
|
|
/* Return something to OS ? */
|
|
|
|
if (!pf->next && /* If we're the last one, */
|
|
|
|
pf->size > malloc_cache && /* ..and the cache is full, */
|
|
|
|
pf->end == malloc_brk && /* ..and none behind us, */
|
|
|
|
malloc_brk == sbrk(0)) { /* ..and it's OK to do... */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Keep the cache intact. Notice that the '>' above guarantees that
|
|
|
|
* the pf will always have at least one page afterwards.
|
|
|
|
*/
|
1996-09-25 08:30:46 +00:00
|
|
|
pf->end = (char *)pf->page + malloc_cache;
|
1995-09-16 09:28:13 +00:00
|
|
|
pf->size = malloc_cache;
|
1995-10-08 18:44:20 +00:00
|
|
|
|
1995-09-16 09:28:13 +00:00
|
|
|
brk(pf->end);
|
|
|
|
malloc_brk = pf->end;
|
1995-10-08 18:44:20 +00:00
|
|
|
|
|
|
|
index = ptr2index(pf->end);
|
|
|
|
last_index = index - 1;
|
|
|
|
|
1995-09-16 09:28:13 +00:00
|
|
|
for(i=index;i <= last_index;)
|
|
|
|
page_dir[i++] = MALLOC_NOT_MINE;
|
1995-10-08 18:44:20 +00:00
|
|
|
|
|
|
|
/* XXX: We could realloc/shrink the pagedir here I guess. */
|
1995-09-16 09:28:13 +00:00
|
|
|
}
|
1996-09-17 19:50:23 +00:00
|
|
|
if (pt)
|
1996-09-23 19:26:39 +00:00
|
|
|
ifree(pt);
|
1994-05-27 05:00:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
1995-09-16 09:28:13 +00:00
|
|
|
* Free a chunk, and possibly the page it's on, if the page becomes empty.
|
1994-05-27 05:00:24 +00:00
|
|
|
*/
|
1995-09-16 09:28:13 +00:00
|
|
|
|
1996-09-25 08:30:46 +00:00
|
|
|
static __inline__ void
|
1995-10-08 18:44:20 +00:00
|
|
|
free_bytes(void *ptr, int index, struct pginfo *info)
|
1994-05-27 05:00:24 +00:00
|
|
|
{
|
1995-09-16 09:28:13 +00:00
|
|
|
int i;
|
|
|
|
struct pginfo **mp;
|
|
|
|
void *vp;
|
|
|
|
|
|
|
|
/* Find the chunk number on the page */
|
|
|
|
i = ((u_long)ptr & malloc_pagemask) >> info->shift;
|
|
|
|
|
1995-10-08 18:44:20 +00:00
|
|
|
if (((u_long)ptr & (info->size-1))) {
|
1996-09-23 19:26:39 +00:00
|
|
|
wrtwarning("modified (chunk-) pointer.\n");
|
1995-10-08 18:44:20 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
1996-09-23 19:26:39 +00:00
|
|
|
if (tst_bit(info, i)) {
|
|
|
|
wrtwarning("chunk is already free.\n");
|
1995-09-16 09:28:13 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
1996-09-23 19:26:39 +00:00
|
|
|
set_bit(info, i);
|
1995-09-16 09:28:13 +00:00
|
|
|
info->free++;
|
|
|
|
|
1995-10-08 18:44:20 +00:00
|
|
|
mp = page_dir + info->shift;
|
|
|
|
|
1995-09-16 09:28:13 +00:00
|
|
|
if (info->free == 1) {
|
1995-10-08 18:44:20 +00:00
|
|
|
|
|
|
|
/* Page became non-full */
|
|
|
|
|
1995-09-16 09:28:13 +00:00
|
|
|
mp = page_dir + info->shift;
|
1995-10-08 18:44:20 +00:00
|
|
|
/* Insert in address order */
|
1995-09-16 09:28:13 +00:00
|
|
|
while (*mp && (*mp)->next && (*mp)->next->page < info->page)
|
|
|
|
mp = &(*mp)->next;
|
|
|
|
info->next = *mp;
|
|
|
|
*mp = info;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (info->free != info->total)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Find & remove this page in the queue */
|
|
|
|
while (*mp != info) {
|
|
|
|
mp = &((*mp)->next);
|
|
|
|
#ifdef EXTRA_SANITY
|
1995-10-08 18:44:20 +00:00
|
|
|
if (!*mp)
|
|
|
|
wrterror("(ES): Not on queue\n");
|
|
|
|
#endif /* EXTRA_SANITY */
|
1995-09-16 09:28:13 +00:00
|
|
|
}
|
|
|
|
*mp = info->next;
|
|
|
|
|
|
|
|
/* Free the page & the info structure if need be */
|
1995-10-08 18:44:20 +00:00
|
|
|
page_dir[ptr2index(info->page)] = MALLOC_FIRST;
|
|
|
|
vp = info->page; /* Order is important ! */
|
|
|
|
if(vp != (void*)info)
|
1996-09-23 19:26:39 +00:00
|
|
|
ifree(info);
|
|
|
|
ifree(vp);
|
1994-05-27 05:00:24 +00:00
|
|
|
}
|
1995-09-16 09:28:13 +00:00
|
|
|
|
1996-09-23 19:26:39 +00:00
|
|
|
static void
|
1996-07-03 05:03:07 +00:00
|
|
|
ifree(void *ptr)
|
1995-09-16 09:28:13 +00:00
|
|
|
{
|
|
|
|
struct pginfo *info;
|
|
|
|
int index;
|
|
|
|
|
|
|
|
/* This is legal */
|
|
|
|
if (!ptr)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!initialized) {
|
1996-09-23 19:26:39 +00:00
|
|
|
wrtwarning("malloc() has never been called.\n");
|
1995-09-16 09:28:13 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
1995-10-08 18:44:20 +00:00
|
|
|
/* If we're already sinking, don't make matters any worse. */
|
1995-09-16 09:28:13 +00:00
|
|
|
if (suicide)
|
1995-10-08 18:44:20 +00:00
|
|
|
return;
|
1995-09-16 09:28:13 +00:00
|
|
|
|
1995-10-08 18:44:20 +00:00
|
|
|
index = ptr2index(ptr);
|
1995-09-16 09:28:13 +00:00
|
|
|
|
|
|
|
if (index < malloc_pageshift) {
|
1996-09-23 19:26:39 +00:00
|
|
|
wrtwarning("junk pointer, too low to make sense.\n");
|
1995-09-16 09:28:13 +00:00
|
|
|
return;
|
|
|
|
}
|
1995-10-08 18:44:20 +00:00
|
|
|
|
1995-09-16 09:28:13 +00:00
|
|
|
if (index > last_index) {
|
1996-09-23 19:26:39 +00:00
|
|
|
wrtwarning("junk pointer, too high to make sense.\n");
|
1995-09-16 09:28:13 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
info = page_dir[index];
|
1995-10-08 18:44:20 +00:00
|
|
|
|
1995-09-16 09:28:13 +00:00
|
|
|
if (info < MALLOC_MAGIC)
|
1996-09-23 19:26:39 +00:00
|
|
|
free_pages(ptr, index, info);
|
1995-10-08 18:44:20 +00:00
|
|
|
else
|
1996-09-23 19:26:39 +00:00
|
|
|
free_bytes(ptr, index, info);
|
1996-07-03 05:03:07 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
1996-09-23 19:26:39 +00:00
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
|
1996-07-03 05:03:07 +00:00
|
|
|
void *
|
|
|
|
malloc(size_t size)
|
|
|
|
{
|
|
|
|
register void *r;
|
1996-09-23 19:26:39 +00:00
|
|
|
|
|
|
|
malloc_func = "malloc():";
|
|
|
|
THREAD_LOCK();
|
|
|
|
if (malloc_active++) {
|
|
|
|
wrtwarning("recursive call.\n");
|
|
|
|
malloc_active--;
|
|
|
|
return (0);
|
|
|
|
}
|
1996-07-03 05:03:07 +00:00
|
|
|
r = imalloc(size);
|
1996-09-23 19:26:39 +00:00
|
|
|
UTRACE(0, size, r);
|
|
|
|
malloc_active--;
|
|
|
|
THREAD_UNLOCK();
|
|
|
|
return (r);
|
1996-07-03 05:03:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
free(void *ptr)
|
|
|
|
{
|
1996-09-23 19:26:39 +00:00
|
|
|
malloc_func = "free():";
|
|
|
|
THREAD_LOCK();
|
|
|
|
if (malloc_active++) {
|
|
|
|
wrtwarning("recursive call.\n");
|
|
|
|
malloc_active--;
|
|
|
|
return;
|
|
|
|
}
|
1996-07-03 05:03:07 +00:00
|
|
|
ifree(ptr);
|
1996-09-23 19:26:39 +00:00
|
|
|
UTRACE(ptr, 0, 0);
|
|
|
|
malloc_active--;
|
|
|
|
THREAD_UNLOCK();
|
1995-09-16 09:28:13 +00:00
|
|
|
return;
|
|
|
|
}
|
1996-07-03 05:03:07 +00:00
|
|
|
|
|
|
|
void *
|
|
|
|
realloc(void *ptr, size_t size)
|
|
|
|
{
|
|
|
|
register void *r;
|
1996-09-23 19:26:39 +00:00
|
|
|
|
|
|
|
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);
|
1996-07-03 05:03:07 +00:00
|
|
|
}
|