#include "sh.h"
RCSID("$tcsh: tc.alloc.c,v 3.46 2006/03/02 18:46:44 christos Exp $")
#define RCHECK
#define DEBUG
static char *memtop = NULL;
static char *membot = NULL;
int dont_free = 0;
#ifdef WINNT_NATIVE
# define malloc fmalloc
# define free ffree
# define calloc fcalloc
# define realloc frealloc
#endif
#if !defined(DEBUG) || defined(SYSMALLOC)
static void
out_of_memory (void)
{
static const char msg[] = "Out of memory\n";
write(didfds ? 2 : SHDIAG, msg, strlen(msg));
_exit(1);
}
#endif
#ifndef SYSMALLOC
#ifdef SX
extern void* sbrk();
#endif
#ifndef NULL
#define NULL 0
#endif
typedef unsigned char U_char;
typedef unsigned int U_int;
typedef unsigned short U_short;
typedef unsigned long U_long;
#define MEMALIGN(a) (((a) + ROUNDUP) & ~ROUNDUP)
union overhead {
union overhead *ov_next;
struct {
U_char ovu_magic;
U_char ovu_index;
#ifdef RCHECK
U_short ovu_size;
U_int ovu_rmagic;
#endif
} ovu;
#define ov_magic ovu.ovu_magic
#define ov_index ovu.ovu_index
#define ov_size ovu.ovu_size
#define ov_rmagic ovu.ovu_rmagic
};
#define MAGIC 0xfd
#define RMAGIC 0x55555555
#ifdef RCHECK
#define RSLOP sizeof (U_int)
#else
#define RSLOP 0
#endif
#define ROUNDUP 7
#define NBUCKETS ((sizeof(long) << 3) - 3)
static union overhead *nextf[NBUCKETS] IZERO_STRUCT;
static U_int nmalloc[NBUCKETS] IZERO_STRUCT;
#ifndef lint
static int findbucket (union overhead *, int);
static void morecore (int);
#endif
#ifdef DEBUG
# define CHECK(a, str, p) \
if (a) { \
xprintf(str, p); \
xprintf(" (memtop = %p membot = %p)\n", memtop, membot); \
abort(); \
}
#else
# define CHECK(a, str, p) \
if (a) { \
xprintf(str, p); \
xprintf(" (memtop = %p membot = %p)\n", memtop, membot); \
return; \
}
#endif
memalign_t
malloc(size_t nbytes)
{
#ifndef lint
union overhead *p;
int bucket = 0;
unsigned shiftr;
#ifdef SUNOS4
nbytes++;
#endif
nbytes = MEMALIGN(MEMALIGN(sizeof(union overhead)) + nbytes + RSLOP);
shiftr = (nbytes - 1) >> 2;
while ((shiftr >>= 1) != 0)
bucket++;
if (nextf[bucket] == NULL)
morecore(bucket);
if ((p = nextf[bucket]) == NULL) {
child++;
#ifndef DEBUG
out_of_memory();
#else
showall(NULL, NULL);
xprintf(CGETS(19, 1, "nbytes=%zu: Out of memory\n"), nbytes);
abort();
#endif
return ((memalign_t) 0);
}
nextf[bucket] = nextf[bucket]->ov_next;
p->ov_magic = MAGIC;
p->ov_index = bucket;
nmalloc[bucket]++;
#ifdef RCHECK
p->ov_size = (p->ov_index <= 13) ? nbytes - 1 : 0;
p->ov_rmagic = RMAGIC;
*((U_int *) (((caddr_t) p) + nbytes - RSLOP)) = RMAGIC;
#endif
return ((memalign_t) (((caddr_t) p) + MEMALIGN(sizeof(union overhead))));
#else
if (nbytes)
return ((memalign_t) 0);
else
return ((memalign_t) 0);
#endif
}
#ifndef lint
static void
morecore(int bucket)
{
union overhead *op;
int rnu;
int nblks;
int siz;
if (nextf[bucket])
return;
op = (union overhead *) sbrk(0);
memtop = (char *) op;
if (membot == NULL)
membot = memtop;
if ((long) op & 0x3ff) {
memtop = sbrk((int) (1024 - ((long) op & 0x3ff)));
memtop += (long) (1024 - ((long) op & 0x3ff));
}
rnu = (bucket <= 8) ? 11 : bucket + 3;
nblks = 1 << (rnu - (bucket + 3));
memtop = sbrk(1 << rnu);
op = (union overhead *) memtop;
if ((long) op == -1)
return;
memtop += (long) (1 << rnu);
if (((U_long) op) & ROUNDUP) {
op = (union overhead *) (((U_long) op + (ROUNDUP + 1)) & ~ROUNDUP);
nblks--;
}
nextf[bucket] = op;
siz = 1 << (bucket + 3);
while (--nblks > 0) {
op->ov_next = (union overhead *) (((caddr_t) op) + siz);
op = (union overhead *) (((caddr_t) op) + siz);
}
op->ov_next = NULL;
}
#endif
void
free(ptr_t cp)
{
#ifndef lint
int size;
union overhead *op;
if (cp == NULL || dont_free)
return;
CHECK(!memtop || !membot,
CGETS(19, 2, "free(%p) called before any allocations."), cp);
CHECK(cp > (ptr_t) memtop,
CGETS(19, 3, "free(%p) above top of memory."), cp);
CHECK(cp < (ptr_t) membot,
CGETS(19, 4, "free(%p) below bottom of memory."), cp);
op = (union overhead *) (((caddr_t) cp) - MEMALIGN(sizeof(union overhead)));
CHECK(op->ov_magic != MAGIC,
CGETS(19, 5, "free(%p) bad block."), cp);
#ifdef RCHECK
if (op->ov_index <= 13)
CHECK(*(U_int *) ((caddr_t) op + op->ov_size + 1 - RSLOP) != RMAGIC,
CGETS(19, 6, "free(%p) bad range check."), cp);
#endif
CHECK(op->ov_index >= NBUCKETS,
CGETS(19, 7, "free(%p) bad block index."), cp);
size = op->ov_index;
op->ov_next = nextf[size];
nextf[size] = op;
nmalloc[size]--;
#else
if (cp == NULL)
return;
#endif
}
memalign_t
calloc(size_t i, size_t j)
{
#ifndef lint
char *cp;
i *= j;
cp = xmalloc(i);
memset(cp, 0, i);
return ((memalign_t) cp);
#else
if (i && j)
return ((memalign_t) 0);
else
return ((memalign_t) 0);
#endif
}
#ifndef lint
static int realloc_srchlen = 4;
#endif
memalign_t
realloc(ptr_t cp, size_t nbytes)
{
#ifndef lint
U_int onb;
union overhead *op;
ptr_t res;
int i;
int was_alloced = 0;
if (cp == NULL)
return (malloc(nbytes));
op = (union overhead *) (((caddr_t) cp) - MEMALIGN(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 = 0;
onb = MEMALIGN(nbytes + MEMALIGN(sizeof(union overhead)) + RSLOP);
if (was_alloced && (onb <= (U_int) (1 << (i + 3))) &&
(onb > (U_int) (1 << (i + 2)))) {
#ifdef RCHECK
nbytes = MEMALIGN(MEMALIGN(sizeof(union overhead))+nbytes+RSLOP);
*((U_int *) (((caddr_t) op) + nbytes - RSLOP)) = RMAGIC;
op->ov_rmagic = RMAGIC;
op->ov_size = (op->ov_index <= 13) ? nbytes - 1 : 0;
#endif
return ((memalign_t) cp);
}
if ((res = malloc(nbytes)) == NULL)
return ((memalign_t) NULL);
if (cp != res) {
onb = (1 << (i + 3)) - MEMALIGN(sizeof(union overhead)) - RSLOP;
(void) memmove(res, cp, onb < nbytes ? onb : nbytes);
}
if (was_alloced)
free(cp);
return ((memalign_t) res);
#else
if (cp && nbytes)
return ((memalign_t) 0);
else
return ((memalign_t) 0);
#endif
}
#ifndef lint
static int
findbucket(union overhead *freep, int srchlen)
{
union overhead *p;
size_t i;
int 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);
}
#endif
#else
memalign_t
smalloc(size_t n)
{
ptr_t ptr;
n = n ? n : 1;
#ifdef HAVE_SBRK
if (membot == NULL)
membot = sbrk(0);
#endif
if ((ptr = malloc(n)) == NULL)
out_of_memory();
#ifndef HAVE_SBRK
if (memtop < ((char *) ptr) + n)
memtop = ((char *) ptr) + n;
if (membot == NULL)
membot = ptr;
#endif
return ((memalign_t) ptr);
}
memalign_t
srealloc(ptr_t p, size_t n)
{
ptr_t ptr;
n = n ? n : 1;
#ifdef HAVE_SBRK
if (membot == NULL)
membot = sbrk(0);
#endif
if ((ptr = (p ? realloc(p, n) : malloc(n))) == NULL)
out_of_memory();
#ifndef HAVE_SBRK
if (memtop < ((char *) ptr) + n)
memtop = ((char *) ptr) + n;
if (membot == NULL)
membot = ptr;
#endif
return ((memalign_t) ptr);
}
memalign_t
scalloc(size_t s, size_t n)
{
ptr_t ptr;
n *= s;
n = n ? n : 1;
#ifdef HAVE_SBRK
if (membot == NULL)
membot = sbrk(0);
#endif
if ((ptr = malloc(n)) == NULL)
out_of_memory();
memset (ptr, 0, n);
#ifndef HAVE_SBRK
if (memtop < ((char *) ptr) + n)
memtop = ((char *) ptr) + n;
if (membot == NULL)
membot = ptr;
#endif
return ((memalign_t) ptr);
}
void
sfree(ptr_t p)
{
if (p && !dont_free)
free(p);
}
#endif
void
showall(Char **v, struct command *c)
{
#ifndef SYSMALLOC
size_t i, j;
union overhead *p;
int totfree = 0, totused = 0;
xprintf(CGETS(19, 8, "%s current memory allocation:\nfree:\t"), progname);
for (i = 0; i < NBUCKETS; i++) {
for (j = 0, p = nextf[i]; p; p = p->ov_next, j++)
continue;
xprintf(" %4zd", j);
totfree += j * (1 << (i + 3));
}
xprintf(CGETS(19, 9, "\nused:\t"));
for (i = 0; i < NBUCKETS; i++) {
xprintf(" %4d", nmalloc[i]);
totused += nmalloc[i] * (1 << (i + 3));
}
xprintf(CGETS(19, 10, "\n\tTotal in use: %d, total free: %d\n"),
totused, totfree);
xprintf(CGETS(19, 11,
"\tAllocated memory from 0x%lx to 0x%lx. Real top at 0x%lx\n"),
(unsigned long) membot, (unsigned long) memtop,
(unsigned long) sbrk(0));
#else
#ifdef HAVE_SBRK
memtop = sbrk(0);
#endif
xprintf(CGETS(19, 12, "Allocated memory from 0x%lx to 0x%lx (%ld).\n"),
(unsigned long) membot, (unsigned long) memtop,
(unsigned long) (memtop - membot));
#endif
USE(c);
USE(v);
}