#include <sys/types.h>
#include <paths.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/param.h>
#include <sys/mman.h>
#include "rtld_printf.h"
static void morecore();
static int findbucket();
#define NPOOLPAGES (32*1024/pagesz)
static caddr_t pagepool_start, pagepool_end;
static int morepages();
union overhead {
union overhead *ov_next;
struct {
u_char ovu_magic;
u_char ovu_index;
#ifdef RCHECK
u_short ovu_rmagic;
u_int ovu_size;
#endif
} ovu;
#define ov_magic ovu.ovu_magic
#define ov_index ovu.ovu_index
#define ov_rmagic ovu.ovu_rmagic
#define ov_size ovu.ovu_size
};
#define MAGIC 0xef
#define RMAGIC 0x5555
#ifdef RCHECK
#define RSLOP sizeof (u_short)
#else
#define RSLOP 0
#endif
#define NBUCKETS 30
static union overhead *nextf[NBUCKETS];
static int pagesz;
static int pagebucket;
#ifdef MSTATS
static u_int nmalloc[NBUCKETS];
#include <stdio.h>
#endif
#if defined(MALLOC_DEBUG) || defined(RCHECK)
#define ASSERT(p) if (!(p)) botch("p")
#include <stdio.h>
static void
botch(char *s)
{
fprintf(stderr, "\r\nassertion botched: %s\r\n", s);
(void) fflush(stderr);
abort();
}
#else
#define ASSERT(p)
#endif
#define TRACE() rtld_printf("TRACE %s:%d\n", __FILE__, __LINE__)
void *
malloc(size_t nbytes)
{
union overhead *op;
int bucket;
long n;
size_t amt;
if (pagesz == 0) {
pagesz = n = getpagesize();
if (morepages(NPOOLPAGES) == 0)
return NULL;
op = (union overhead *)(pagepool_start);
n = n - sizeof (*op) - ((long)op & (n - 1));
if (n < 0)
n += pagesz;
if (n) {
pagepool_start += n;
}
bucket = 0;
amt = 8;
while ((size_t)pagesz > amt) {
amt <<= 1;
bucket++;
}
pagebucket = bucket;
}
if (nbytes <= (unsigned long)(n = pagesz - sizeof (*op) - RSLOP)) {
#ifndef RCHECK
amt = 8;
bucket = 0;
#else
amt = 16;
bucket = 1;
#endif
n = -(sizeof (*op) + RSLOP);
} else {
amt = (size_t)pagesz;
bucket = pagebucket;
}
while (nbytes > amt + n) {
amt <<= 1;
if (amt == 0)
return (NULL);
bucket++;
}
if ((op = nextf[bucket]) == NULL) {
morecore(bucket);
if ((op = nextf[bucket]) == NULL)
return (NULL);
}
nextf[bucket] = op->ov_next;
op->ov_magic = MAGIC;
op->ov_index = bucket;
#ifdef MSTATS
nmalloc[bucket]++;
#endif
#ifdef RCHECK
op->ov_size = roundup2(nbytes, RSLOP);
op->ov_rmagic = RMAGIC;
*(u_short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC;
#endif
return ((char *)(op + 1));
}
void *
calloc(size_t num, size_t size)
{
void *p;
size *= num;
if ((p = malloc(size)) != NULL)
bzero(p, size);
return(p);
}
static void
morecore(int bucket)
{
union overhead *op;
size_t sz;
size_t amt;
int nblks;
sz = 1LU << (bucket + 3);
#ifdef MALLOC_DEBUG
ASSERT(sz > 0);
#else
if (sz == 0)
return;
#endif
if (sz < pagesz) {
amt = pagesz;
nblks = amt / sz;
} else {
amt = sz + pagesz;
nblks = 1;
}
if (amt > pagepool_end - pagepool_start)
if (morepages(amt/pagesz + NPOOLPAGES) == 0)
return;
op = (union overhead *)pagepool_start;
pagepool_start += amt;
nextf[bucket] = op;
while (--nblks > 0) {
op->ov_next = (union overhead *)((caddr_t)op + sz);
op = (union overhead *)((caddr_t)op + sz);
}
}
void
free(void *cp)
{
int size;
union overhead *op;
if (cp == NULL)
return;
op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
#ifdef MALLOC_DEBUG
ASSERT(op->ov_magic == MAGIC);
#else
if (op->ov_magic != MAGIC)
return;
#endif
#ifdef RCHECK
ASSERT(op->ov_rmagic == RMAGIC);
ASSERT(*(u_short *)((caddr_t)(op + 1) + op->ov_size) == RMAGIC);
#endif
size = op->ov_index;
ASSERT(size < NBUCKETS);
op->ov_next = nextf[size];
nextf[size] = op;
#ifdef MSTATS
nmalloc[size]--;
#endif
}
int realloc_srchlen = 4;
void *
realloc(void *cp, size_t nbytes)
{
size_t onb;
int i;
union overhead *op;
char *res;
int was_alloced = 0;
if (cp == NULL)
return (malloc(nbytes));
op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
if (op->ov_magic == MAGIC) {
was_alloced++;
i = op->ov_index;
} else {
if ((i = findbucket(op, 1)) < 0 &&
(i = findbucket(op, realloc_srchlen)) < 0)
i = NBUCKETS;
}
onb = 1LU << (i + 3);
if (onb < (u_int)pagesz)
onb -= sizeof (*op) + RSLOP;
else
onb += pagesz - sizeof (*op) - RSLOP;
if (was_alloced) {
if (i) {
i = 1LU << (i + 2);
if (i < pagesz)
i -= sizeof (*op) + RSLOP;
else
i += pagesz - sizeof (*op) - RSLOP;
}
if (nbytes <= onb && nbytes > (size_t)i) {
#ifdef RCHECK
op->ov_size = roundup2(nbytes, RSLOP);
*(u_short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC;
#endif
return(cp);
} else
free(cp);
}
if ((res = malloc(nbytes)) == NULL)
return (NULL);
if (cp != res)
bcopy(cp, res, (nbytes < onb) ? nbytes : onb);
return (res);
}
static int
findbucket(union overhead *freep, int srchlen)
{
union overhead *p;
int i, j;
for (i = 0; i < NBUCKETS; i++) {
j = 0;
for (p = nextf[i]; p && j != srchlen; p = p->ov_next) {
if (p == freep)
return (i);
j++;
}
}
return (-1);
}
#ifdef MSTATS
void
mstats(char *s)
{
int i, j;
union overhead *p;
size_t totfree, totused;
totfree = 0;
totused = 0;
fprintf(stderr, "Memory allocation statistics %s\nfree:\t", s);
for (i = 0; i < NBUCKETS; i++) {
for (j = 0, p = nextf[i]; p; p = p->ov_next, j++)
;
fprintf(stderr, " %d", j);
totfree += j * (1LU << (i + 3));
}
fprintf(stderr, "\nused:\t");
for (i = 0; i < NBUCKETS; i++) {
fprintf(stderr, " %d", nmalloc[i]);
totused += nmalloc[i] * (1LU << (i + 3));
}
fprintf(stderr, "\n\tTotal in use: %zd, total free: %zd\n",
totused, totfree);
}
#endif
static int
morepages(int n)
{
int fd = -1;
int offset;
if (pagepool_end - pagepool_start > pagesz) {
caddr_t addr = (caddr_t)
roundup2((long)pagepool_start, pagesz);
if (munmap(addr, pagepool_end - addr) != 0)
rtld_fdprintf(STDERR_FILENO, "morepages: munmap %p",
addr);
}
offset = (long)pagepool_start - rounddown2((long)pagepool_start, pagesz);
if ((pagepool_start = mmap(0, n * pagesz,
PROT_READ|PROT_WRITE,
MAP_ANON|MAP_COPY, fd, 0)) == (caddr_t)-1) {
rtld_printf("Cannot map anonymous memory\n");
return 0;
}
pagepool_end = pagepool_start + n * pagesz;
pagepool_start += offset;
return n;
}