#include "zsh.mdh"
#include "mem.pro"
#if defined(HAVE_SYS_MMAN_H) && defined(HAVE_MMAP) && defined(HAVE_MUNMAP)
#include <sys/mman.h>
#if defined(MAP_ANONYMOUS) && defined(MAP_PRIVATE)
#define USE_MMAP 1
#define MMAP_FLAGS (MAP_ANONYMOUS | MAP_PRIVATE)
#endif
#endif
#ifdef ZSH_MEM_WARNING
# ifndef DEBUG
# define DEBUG 1
# endif
#endif
#if defined(ZSH_MEM) && defined(ZSH_MEM_DEBUG)
static int h_m[1025], h_push, h_pop, h_free;
#endif
union mem_align {
zlong l;
double d;
};
#define H_ISIZE sizeof(union mem_align)
#define HEAPSIZE (16384 - H_ISIZE)
#define HEAP_ARENA_SIZE (HEAPSIZE - sizeof(struct heap))
#define HEAPFREE (16384 - H_ISIZE)
#define ARENA_SIZEOF(h) ((h)->size - sizeof(struct heap))
static Heap heaps;
static Heap fheap;
mod_export Heap
new_heaps(void)
{
Heap h;
queue_signals();
h = heaps;
fheap = heaps = NULL;
unqueue_signals();
return h;
}
mod_export void
old_heaps(Heap old)
{
Heap h, n;
queue_signals();
for (h = heaps; h; h = n) {
n = h->next;
DPUTS(h->sp, "BUG: old_heaps() with pushed heaps");
#ifdef USE_MMAP
munmap((void *) h, h->size);
#else
zfree(h, HEAPSIZE);
#endif
}
heaps = old;
fheap = NULL;
unqueue_signals();
}
mod_export Heap
switch_heaps(Heap new)
{
Heap h;
queue_signals();
h = heaps;
heaps = new;
fheap = NULL;
unqueue_signals();
return h;
}
mod_export void
pushheap(void)
{
Heap h;
Heapstack hs;
queue_signals();
#if defined(ZSH_MEM) && defined(ZSH_MEM_DEBUG)
h_push++;
#endif
for (h = heaps; h; h = h->next) {
DPUTS(!h->used, "BUG: empty heap");
hs = (Heapstack) zalloc(sizeof(*hs));
hs->next = h->sp;
h->sp = hs;
hs->used = h->used;
}
unqueue_signals();
}
mod_export void
freeheap(void)
{
Heap h, hn, hl = NULL;
queue_signals();
#if defined(ZSH_MEM) && defined(ZSH_MEM_DEBUG)
h_free++;
#endif
fheap = NULL;
for (h = heaps; h; h = hn) {
hn = h->next;
if (h->sp) {
#ifdef ZSH_MEM_DEBUG
memset(arena(h) + h->sp->used, 0xff, h->used - h->sp->used);
#endif
h->used = h->sp->used;
if (!fheap && h->used < ARENA_SIZEOF(h))
fheap = h;
hl = h;
} else {
#ifdef USE_MMAP
munmap((void *) h, h->size);
#else
zfree(h, HEAPSIZE);
#endif
}
}
if (hl)
hl->next = NULL;
else
heaps = NULL;
unqueue_signals();
}
mod_export void
popheap(void)
{
Heap h, hn, hl = NULL;
Heapstack hs;
queue_signals();
#if defined(ZSH_MEM) && defined(ZSH_MEM_DEBUG)
h_pop++;
#endif
fheap = NULL;
for (h = heaps; h; h = hn) {
hn = h->next;
if ((hs = h->sp)) {
h->sp = hs->next;
#ifdef ZSH_MEM_DEBUG
memset(arena(h) + hs->used, 0xff, h->used - hs->used);
#endif
h->used = hs->used;
if (!fheap && h->used < ARENA_SIZEOF(h))
fheap = h;
zfree(hs, sizeof(*hs));
hl = h;
} else {
#ifdef USE_MMAP
munmap((void *) h, h->size);
#else
zfree(h, HEAPSIZE);
#endif
}
}
if (hl)
hl->next = NULL;
else
heaps = NULL;
unqueue_signals();
}
#ifdef USE_MMAP
static Heap
mmap_heap_alloc(size_t *n)
{
Heap h;
static size_t pgsz = 0;
if (!pgsz) {
#ifdef _SC_PAGESIZE
pgsz = sysconf(_SC_PAGESIZE);
#else
# ifdef _SC_PAGE_SIZE
pgsz = sysconf(_SC_PAGE_SIZE);
# else
pgsz = getpagesize();
# endif
#endif
pgsz--;
}
*n = (*n + pgsz) & ~pgsz;
h = (Heap) mmap(NULL, *n, PROT_READ | PROT_WRITE,
MMAP_FLAGS, -1, 0);
if (h == ((Heap) -1)) {
zerr("fatal error: out of heap memory");
exit(1);
}
return h;
}
#endif
mod_export void *
zheapptr(void *p)
{
Heap h;
queue_signals();
for (h = heaps; h; h = h->next)
if ((char *)p >= arena(h) &&
(char *)p + H_ISIZE < arena(h) + ARENA_SIZEOF(h))
break;
unqueue_signals();
return (h ? p : 0);
}
mod_export void *
zhalloc(size_t size)
{
Heap h;
size_t n;
size = (size + H_ISIZE - 1) & ~(H_ISIZE - 1);
queue_signals();
#if defined(ZSH_MEM) && defined(ZSH_MEM_DEBUG)
h_m[size < (1024 * H_ISIZE) ? (size / H_ISIZE) : 1024]++;
#endif
for (h = ((fheap && ARENA_SIZEOF(fheap) >= (size + fheap->used))
? fheap : heaps);
h; h = h->next) {
if (ARENA_SIZEOF(h) >= (n = size + h->used)) {
void *ret;
h->used = n;
ret = arena(h) + n - size;
unqueue_signals();
return ret;
}
}
{
Heap hp;
#if defined(ZSH_MEM) && !defined(USE_MMAP)
static int called = 0;
void *foo = called ? (void *)malloc(HEAPFREE) : NULL;
#endif
n = HEAP_ARENA_SIZE > size ? HEAPSIZE : size + sizeof(*h);
for (hp = NULL, h = heaps; h; hp = h, h = h->next);
#ifdef USE_MMAP
h = mmap_heap_alloc(&n);
#else
h = (Heap) zalloc(n);
#endif
#if defined(ZSH_MEM) && !defined(USE_MMAP)
if (called)
zfree(foo, HEAPFREE);
called = 1;
#endif
h->size = n;
h->used = size;
h->next = NULL;
h->sp = NULL;
if (hp)
hp->next = h;
else
heaps = h;
fheap = h;
unqueue_signals();
return arena(h);
}
}
mod_export void *
hrealloc(char *p, size_t old, size_t new)
{
Heap h, ph;
old = (old + H_ISIZE - 1) & ~(H_ISIZE - 1);
new = (new + H_ISIZE - 1) & ~(H_ISIZE - 1);
if (old == new)
return p;
if (!old && !p)
return zhalloc(new);
queue_signals();
for (h = heaps, ph = NULL; h; ph = h, h = h->next)
if (p >= arena(h) && p < arena(h) + ARENA_SIZEOF(h))
break;
DPUTS(!h, "BUG: hrealloc() called for non-heap memory.");
DPUTS(h->sp && arena(h) + h->sp->used > p,
"BUG: hrealloc() wants to realloc pushed memory");
if (p + old < arena(h) + h->used) {
if (new > old) {
char *ptr = (char *) zhalloc(new);
memcpy(ptr, p, old);
#ifdef ZSH_MEM_DEBUG
memset(p, 0xff, old);
#endif
unqueue_signals();
return ptr;
} else {
unqueue_signals();
return new ? p : NULL;
}
}
DPUTS(p + old != arena(h) + h->used, "BUG: hrealloc more than allocated");
if (p == arena(h)) {
if (!new) {
if (ph)
ph->next = h->next;
else
heaps = h->next;
fheap = NULL;
#ifdef USE_MMAP
munmap((void *) h, h->size);
#else
zfree(h, HEAPSIZE);
#endif
unqueue_signals();
return NULL;
}
if (new > ARENA_SIZEOF(h)) {
size_t n = (new + sizeof(*h) + HEAPSIZE);
n -= n % HEAPSIZE;
fheap = NULL;
#ifdef USE_MMAP
{
Heap hnew;
hnew = mmap_heap_alloc(&n);
memcpy(hnew, h, h->size);
munmap((void *)h, h->size);
h = hnew;
}
#else
h = (Heap) realloc(h, n);
#endif
h->size = n;
if (ph)
ph->next = h;
else
heaps = h;
}
h->used = new;
unqueue_signals();
return arena(h);
}
#ifndef USE_MMAP
DPUTS(h->used > ARENA_SIZEOF(h), "BUG: hrealloc at invalid address");
#endif
if (h->used + (new - old) <= ARENA_SIZEOF(h)) {
h->used += new - old;
unqueue_signals();
return p;
} else {
char *t = zhalloc(new);
memcpy(t, p, old > new ? new : old);
h->used -= old;
#ifdef ZSH_MEM_DEBUG
memset(p, 0xff, old);
#endif
unqueue_signals();
return t;
}
}
mod_export void *
hcalloc(size_t size)
{
void *ptr;
ptr = zhalloc(size);
memset(ptr, 0, size);
return ptr;
}
mod_export void *
zalloc(size_t size)
{
void *ptr;
if (!size)
size = 1;
queue_signals();
if (!(ptr = (void *) malloc(size))) {
zerr("fatal error: out of memory");
exit(1);
}
unqueue_signals();
return ptr;
}
mod_export void *
zshcalloc(size_t size)
{
void *ptr;
if (!size)
size = 1;
queue_signals();
if (!(ptr = (void *) malloc(size))) {
zerr("fatal error: out of memory");
exit(1);
}
unqueue_signals();
memset(ptr, 0, size);
return ptr;
}
mod_export void *
zrealloc(void *ptr, size_t size)
{
queue_signals();
if (ptr) {
if (size) {
if (!(ptr = (void *) realloc(ptr, size))) {
zerr("fatal error: out of memory");
exit(1);
}
unqueue_signals();
return ptr;
}
else
free(ptr);
ptr = NULL;
} else {
ptr = malloc(size);
}
unqueue_signals();
return ptr;
}
#ifdef ZSH_MEM
#if !defined(__hpux) && !defined(DGUX) && !defined(__osf__)
# if defined(_BSD)
# ifndef HAVE_BRK_PROTO
extern int brk _((caddr_t));
# endif
# ifndef HAVE_SBRK_PROTO
extern caddr_t sbrk _((int));
# endif
# else
# ifndef HAVE_BRK_PROTO
extern int brk _((void *));
# endif
# ifndef HAVE_SBRK_PROTO
extern void *sbrk _((int));
# endif
# endif
#endif
#if defined(_BSD) && !defined(STDC_HEADERS)
# define FREE_RET_T int
# define FREE_ARG_T char *
# define FREE_DO_RET
# define MALLOC_RET_T char *
# define MALLOC_ARG_T size_t
#else
# define FREE_RET_T void
# define FREE_ARG_T void *
# define MALLOC_RET_T void *
# define MALLOC_ARG_T size_t
#endif
struct m_shdr {
struct m_shdr *next;
#ifdef PAD_64_BIT
struct m_shdr *dummy;
#endif
};
struct m_hdr {
zlong len;
#if defined(PAD_64_BIT) && !defined(ZSH_64_BIT_TYPE)
zlong dummy1;
#endif
struct m_hdr *next;
struct m_shdr *free;
zlong used;
#if defined(PAD_64_BIT) && !defined(ZSH_64_BIT_TYPE)
zlong dummy2;
#endif
};
#define M_ALIGN (sizeof(union mem_align))
#define M_HSIZE (sizeof(struct m_hdr))
#if defined(PAD_64_BIT) && !defined(ZSH_64_BIT_TYPE)
# define M_ISIZE (2*sizeof(zlong))
#else
# define M_ISIZE (sizeof(zlong))
#endif
#define M_MIN (2 * M_ISIZE)
#define M_FREE 32768
#define M_KEEP 16384
#define M_ALLOC M_KEEP
static struct m_hdr *m_lfree, *m_free;
static long m_pgsz = 0;
static char *m_high, *m_low;
#define M_SIDX(S) ((S) / M_ISIZE)
#define M_SNUM 128
#define M_SLEN(M) ((M)->len / M_SNUM)
#if defined(PAD_64_BIT) && !defined(ZSH_64_BIT_TYPE)
#define M_SBLEN(S) ((S) * M_SNUM + sizeof(struct m_shdr *) + \
2*sizeof(zlong) + sizeof(struct m_hdr *))
#define M_BSLEN(S) (((S) - sizeof(struct m_shdr *) - \
2*sizeof(zlong) - sizeof(struct m_hdr *)) / M_SNUM)
#else
#define M_SBLEN(S) ((S) * M_SNUM + sizeof(struct m_shdr *) + \
sizeof(zlong) + sizeof(struct m_hdr *))
#define M_BSLEN(S) (((S) - sizeof(struct m_shdr *) - \
sizeof(zlong) - sizeof(struct m_hdr *)) / M_SNUM)
#endif
#define M_NSMALL 8
static struct m_hdr *m_small[M_NSMALL];
#ifdef ZSH_MEM_DEBUG
static int m_s = 0, m_b = 0;
static int m_m[1025], m_f[1025];
static struct m_hdr *m_l;
#endif
MALLOC_RET_T
malloc(MALLOC_ARG_T size)
{
struct m_hdr *m, *mp, *mt;
long n, s, os = 0;
#ifndef USE_MMAP
struct heap *h, *hp, *hf = NULL, *hfp = NULL;
#endif
if (!size)
#if 1
size = 1;
#else
return (MALLOC_RET_T) m_high;
#endif
queue_signals();
if (!m_pgsz) {
#ifdef _SC_PAGESIZE
m_pgsz = sysconf(_SC_PAGESIZE);
#else
# ifdef _SC_PAGE_SIZE
m_pgsz = sysconf(_SC_PAGE_SIZE);
# else
m_pgsz = getpagesize();
# endif
#endif
m_free = m_lfree = NULL;
}
size = (size + M_ALIGN - 1) & ~(M_ALIGN - 1);
if ((s = M_SIDX(size)) && s < M_NSMALL) {
for (mp = NULL, m = m_small[s]; m && !m->free; mp = m, m = m->next);
if (m) {
struct m_shdr *sh = m->free;
m->free = sh->next;
m->used++;
if (m->used == M_SNUM && m->next) {
for (mt = m; mt->next; mt = mt->next);
mt->next = m;
if (mp)
mp->next = m->next;
else
m_small[s] = m->next;
m->next = NULL;
}
#ifdef ZSH_MEM_DEBUG
m_m[size / M_ISIZE]++;
#endif
unqueue_signals();
return (MALLOC_RET_T) sh;
}
os = size;
size = M_SBLEN(size);
} else
s = 0;
for (mp = NULL, m = m_free; m && m->len < size; mp = m, m = m->next);
#ifndef USE_MMAP
for (hp = NULL, h = heaps; h; hp = h, h = h->next)
if (!h->used &&
(!hf || h < hf) &&
(!m || ((char *)m) > ((char *)h)))
hf = h, hfp = hp;
if (hf) {
Heapstack hso, hsn;
for (hso = hf->sp; hso; hso = hsn) {
hsn = hso->next;
zfree(hso, sizeof(*hso));
}
if (hfp)
hfp->next = hf->next;
else
heaps = hf->next;
zfree(hf, HEAPSIZE);
for (mp = NULL, m = m_free; m && m->len < size; mp = m, m = m->next);
}
#endif
if (!m) {
long nal;
n = (size + M_HSIZE + M_ALLOC + m_pgsz - 1) & ~(m_pgsz - 1);
if (((char *)(m = (struct m_hdr *)sbrk(n))) == ((char *)-1)) {
DPUTS1(1, "MEM: allocation error at sbrk, size %L.", n);
unqueue_signals();
return NULL;
}
if ((nal = ((long)(char *)m) & (M_ALIGN-1))) {
if ((char *)sbrk(M_ALIGN - nal) == (char *)-1) {
DPUTS(1, "MEM: allocation error at sbrk.");
unqueue_signals();
return NULL;
}
m = (struct m_hdr *) ((char *)m + (M_ALIGN - nal));
}
if (!m_low)
m_low = (char *)m;
#ifdef ZSH_MEM_DEBUG
m_s += n;
if (!m_l)
m_l = m;
#endif
m_high = ((char *)m) + n;
m->len = n - M_ISIZE;
m->next = NULL;
if ((mp = m_lfree))
m_lfree->next = m;
m_lfree = m;
}
if ((n = m->len - size) > M_MIN) {
struct m_hdr *mtt = (struct m_hdr *)(((char *)m) + M_ISIZE + size);
mtt->len = n - M_ISIZE;
mtt->next = m->next;
m->len = size;
if (m_lfree == m)
m_lfree = mtt;
if (mp)
mp->next = mtt;
else
m_free = mtt;
} else if (mp) {
if (m == m_lfree)
m_lfree = mp;
mp->next = m->next;
} else {
m_free = m->next;
if (m == m_lfree)
m_lfree = m_free;
}
if (s) {
struct m_shdr *sh, *shn;
m->free = sh = (struct m_shdr *)(((char *)m) +
sizeof(struct m_hdr) + os);
for (n = M_SNUM - 2; n--; sh = shn)
shn = sh->next = sh + s;
sh->next = NULL;
m->used = 1;
m->next = m_small[s];
m_small[s] = m;
#ifdef ZSH_MEM_DEBUG
m_m[os / M_ISIZE]++;
#endif
unqueue_signals();
return (MALLOC_RET_T) (((char *)m) + sizeof(struct m_hdr));
}
#ifdef ZSH_MEM_DEBUG
m_m[m->len < (1024 * M_ISIZE) ? (m->len / M_ISIZE) : 1024]++;
#endif
unqueue_signals();
return (MALLOC_RET_T) & m->next;
}
mod_export void
zfree(void *p, int sz)
{
struct m_hdr *m = (struct m_hdr *)(((char *)p) - M_ISIZE), *mp, *mt = NULL;
int i;
# ifdef DEBUG
int osz = sz;
# endif
#ifdef ZSH_SECURE_FREE
sz = 0;
#else
sz = (sz + M_ALIGN - 1) & ~(M_ALIGN - 1);
#endif
if (!p)
return;
if (((char *)p) < m_low || ((char *)p) > m_high ||
((long)p) & (M_ALIGN - 1)) {
DPUTS(1, "BUG: attempt to free storage at invalid address");
return;
}
queue_signals();
fr_rec:
if ((i = sz / M_ISIZE) < M_NSMALL || !sz)
for (; i < M_NSMALL; i++) {
for (mp = NULL, mt = m_small[i];
mt && (((char *)mt) > ((char *)p) ||
(((char *)mt) + mt->len) < ((char *)p));
mp = mt, mt = mt->next);
if (mt) {
struct m_shdr *sh = (struct m_shdr *)p;
#ifdef ZSH_SECURE_FREE
struct m_shdr *sh2;
if ((((char *)p) - (((char *)mt) + sizeof(struct m_hdr))) %
M_BSLEN(mt->len)) {
DPUTS(1, "BUG: attempt to free storage at invalid address");
unqueue_signals();
return;
}
for (sh2 = mt->free; sh2; sh2 = sh2->next)
if (((char *)p) == ((char *)sh2)) {
DPUTS(1, "BUG: attempt to free already free storage");
unqueue_signals();
return;
}
#endif
DPUTS(M_BSLEN(mt->len) < osz,
"BUG: attempt to free more than allocated.");
#ifdef ZSH_MEM_DEBUG
m_f[M_BSLEN(mt->len) / M_ISIZE]++;
memset(sh, 0xff, M_BSLEN(mt->len));
#endif
sh->next = mt->free;
mt->free = sh;
if (--mt->used) {
if (mp) {
mp->next = mt->next;
mt->next = m_small[i];
m_small[i] = mt;
}
unqueue_signals();
return;
}
if (mp)
mp->next = mt->next;
else
m_small[i] = mt->next;
m = mt;
p = (void *) & m->next;
break;
} else if (sz) {
sz = 0;
goto fr_rec;
}
}
#ifdef ZSH_MEM_DEBUG
if (!mt)
m_f[m->len < (1024 * M_ISIZE) ? (m->len / M_ISIZE) : 1024]++;
#endif
#ifdef ZSH_SECURE_FREE
for (mt = (struct m_hdr *)m_low;
((char *)mt) < m_high;
mt = (struct m_hdr *)(((char *)mt) + M_ISIZE + mt->len))
if (((char *)p) == ((char *)&mt->next))
break;
if (((char *)mt) >= m_high) {
DPUTS(1, "BUG: attempt to free storage at invalid address");
unqueue_signals();
return;
}
#endif
for (mp = NULL, mt = m_free; mt && mt < m; mp = mt, mt = mt->next);
if (m == mt) {
DPUTS(1, "BUG: attempt to free already free storage");
unqueue_signals();
return;
}
DPUTS(m->len < osz, "BUG: attempt to free more than allocated");
#ifdef ZSH_MEM_DEBUG
memset(p, 0xff, m->len);
#endif
if (mt && ((char *)mt) == (((char *)m) + M_ISIZE + m->len)) {
m->len += mt->len + M_ISIZE;
m->next = mt->next;
if (mt == m_lfree)
m_lfree = m;
} else
m->next = mt;
if (mp && ((char *)m) == (((char *)mp) + M_ISIZE + mp->len)) {
mp->len += m->len + M_ISIZE;
mp->next = m->next;
if (m == m_lfree)
m_lfree = mp;
} else if (mp)
mp->next = m;
else {
m_free = m;
if (!m_lfree)
m_lfree = m_free;
}
if ((((char *)m_lfree) + M_ISIZE + m_lfree->len) == m_high &&
m_lfree->len >= m_pgsz + M_MIN + M_FREE) {
long n = (m_lfree->len - M_MIN - M_KEEP) & ~(m_pgsz - 1);
m_lfree->len -= n;
#ifdef HAVE_BRK
if (brk(m_high -= n) == -1) {
#else
m_high -= n;
if (sbrk(-n) == (void *)-1) {
#endif
DPUTS(1, "MEM: allocation error at brk.");
}
#ifdef ZSH_MEM_DEBUG
m_b += n;
#endif
}
unqueue_signals();
}
FREE_RET_T
free(FREE_ARG_T p)
{
zfree(p, 0);
#ifdef FREE_DO_RET
return 0;
#endif
}
mod_export void
zsfree(char *p)
{
if (p)
zfree(p, strlen(p) + 1);
}
MALLOC_RET_T
realloc(MALLOC_RET_T p, MALLOC_ARG_T size)
{
struct m_hdr *m = (struct m_hdr *)(((char *)p) - M_ISIZE), *mp, *mt;
char *r;
int i, l = 0;
if (!p && size)
return (MALLOC_RET_T) malloc(size);
if (!p || !size)
return (MALLOC_RET_T) p;
queue_signals();
for (i = 0; i < M_NSMALL; i++) {
for (mp = NULL, mt = m_small[i];
mt && (((char *)mt) > ((char *)p) ||
(((char *)mt) + mt->len) < ((char *)p));
mp = mt, mt = mt->next);
if (mt) {
l = M_BSLEN(mt->len);
break;
}
}
if (!l)
l = m->len;
r = malloc(size);
memcpy(r, (char *)p, (size > l) ? l : size);
free(p);
unqueue_signals();
return (MALLOC_RET_T) r;
}
MALLOC_RET_T
calloc(MALLOC_ARG_T n, MALLOC_ARG_T size)
{
long l;
char *r;
if (!(l = n * size))
return (MALLOC_RET_T) m_high;
r = malloc(l);
memset(r, 0, l);
return (MALLOC_RET_T) r;
}
#ifdef ZSH_MEM_DEBUG
int
bin_mem(char *name, char **argv, Options ops, int func)
{
int i, ii, fi, ui, j;
struct m_hdr *m, *mf, *ms;
char *b, *c, buf[40];
long u = 0, f = 0, to, cu;
queue_signals();
if (OPT_ISSET(ops,'v')) {
printf("The lower and the upper addresses of the heap. Diff gives\n");
printf("the difference between them, i.e. the size of the heap.\n\n");
}
printf("low mem %ld\t high mem %ld\t diff %ld\n",
(long)m_l, (long)m_high, (long)(m_high - ((char *)m_l)));
if (OPT_ISSET(ops,'v')) {
printf("\nThe number of bytes that were allocated using sbrk() and\n");
printf("the number of bytes that were given back to the system\n");
printf("via brk().\n");
}
printf("\nsbrk %d\tbrk %d\n", m_s, m_b);
if (OPT_ISSET(ops,'v')) {
printf("\nInformation about the sizes that were allocated or freed.\n");
printf("For each size that were used the number of mallocs and\n");
printf("frees is shown. Diff gives the difference between these\n");
printf("values, i.e. the number of blocks of that size that is\n");
printf("currently allocated. Total is the product of size and diff,\n");
printf("i.e. the number of bytes that are allocated for blocks of\n");
printf("this size. The last field gives the accumulated number of\n");
printf("bytes for all sizes.\n");
}
printf("\nsize\tmalloc\tfree\tdiff\ttotal\tcum\n");
for (i = 0, cu = 0; i < 1024; i++)
if (m_m[i] || m_f[i]) {
to = (long) i * M_ISIZE * (m_m[i] - m_f[i]);
printf("%ld\t%d\t%d\t%d\t%ld\t%ld\n",
(long)i * M_ISIZE, m_m[i], m_f[i], m_m[i] - m_f[i],
to, (cu += to));
}
if (m_m[i] || m_f[i])
printf("big\t%d\t%d\t%d\n", m_m[i], m_f[i], m_m[i] - m_f[i]);
if (OPT_ISSET(ops,'v')) {
printf("\nThe list of memory blocks. For each block the following\n");
printf("information is shown:\n\n");
printf("num\tthe number of this block\n");
printf("tnum\tlike num but counted separately for used and free\n");
printf("\tblocks\n");
printf("addr\tthe address of this block\n");
printf("len\tthe length of the block\n");
printf("state\tthe state of this block, this can be:\n");
printf("\t used\tthis block is used for one big block\n");
printf("\t free\tthis block is free\n");
printf("\t small\tthis block is used for an array of small blocks\n");
printf("cum\tthe accumulated sizes of the blocks, counted\n");
printf("\tseparately for used and free blocks\n");
printf("\nFor blocks holding small blocks the number of free\n");
printf("blocks, the number of used blocks and the size of the\n");
printf("blocks is shown. For otherwise used blocks the first few\n");
printf("bytes are shown as an ASCII dump.\n");
}
printf("\nblock list:\nnum\ttnum\taddr\t\tlen\tstate\tcum\n");
for (m = m_l, mf = m_free, ii = fi = ui = 1; ((char *)m) < m_high;
m = (struct m_hdr *)(((char *)m) + M_ISIZE + m->len), ii++) {
for (j = 0, ms = NULL; j < M_NSMALL && !ms; j++)
for (ms = m_small[j]; ms; ms = ms->next)
if (ms == m)
break;
if (m == mf)
buf[0] = '\0';
else if (m == ms)
sprintf(buf, "%ld %ld %ld", (long)(M_SNUM - ms->used),
(long)ms->used,
(long)(m->len - sizeof(struct m_hdr)) / M_SNUM + 1);
else {
for (i = 0, b = buf, c = (char *)&m->next; i < 20 && i < m->len;
i++, c++)
*b++ = (*c >= ' ' && *c < 127) ? *c : '.';
*b = '\0';
}
printf("%d\t%d\t%ld\t%ld\t%s\t%ld\t%s\n", ii,
(m == mf) ? fi++ : ui++,
(long)m, (long)m->len,
(m == mf) ? "free" : ((m == ms) ? "small" : "used"),
(m == mf) ? (f += m->len) : (u += m->len),
buf);
if (m == mf)
mf = mf->next;
}
if (OPT_ISSET(ops,'v')) {
printf("\nHere is some information about the small blocks used.\n");
printf("For each size the arrays with the number of free and the\n");
printf("number of used blocks are shown.\n");
}
printf("\nsmall blocks:\nsize\tblocks (free/used)\n");
for (i = 0; i < M_NSMALL; i++)
if (m_small[i]) {
printf("%ld\t", (long)i * M_ISIZE);
for (ii = 0, m = m_small[i]; m; m = m->next) {
printf("(%ld/%ld) ", (long)(M_SNUM - m->used),
(long)m->used);
if (!((++ii) & 7))
printf("\n\t");
}
putchar('\n');
}
if (OPT_ISSET(ops,'v')) {
printf("\n\nBelow is some information about the allocation\n");
printf("behaviour of the zsh heaps. First the number of times\n");
printf("pushheap(), popheap(), and freeheap() were called.\n");
}
printf("\nzsh heaps:\n\n");
printf("push %d\tpop %d\tfree %d\n\n", h_push, h_pop, h_free);
if (OPT_ISSET(ops,'v')) {
printf("\nThe next list shows for several sizes the number of times\n");
printf("memory of this size were taken from heaps.\n\n");
}
printf("size\tmalloc\ttotal\n");
for (i = 0; i < 1024; i++)
if (h_m[i])
printf("%ld\t%d\t%ld\n", (long)i * H_ISIZE, h_m[i],
(long)i * H_ISIZE * h_m[i]);
if (h_m[1024])
printf("big\t%d\n", h_m[1024]);
unqueue_signals();
return 0;
}
#endif
#else
mod_export void
zfree(void *p, UNUSED(int sz))
{
if (p)
free(p);
}
mod_export void
zsfree(char *p)
{
if (p)
free(p);
}
#endif