159243Sobrien/*
259243Sobrien * tc.alloc.c (Caltech) 2/21/82
359243Sobrien * Chris Kingsley, kingsley@cit-20.
459243Sobrien *
559243Sobrien * This is a very fast storage allocator.  It allocates blocks of a small
659243Sobrien * number of different sizes, and keeps free lists of each size.  Blocks that
759243Sobrien * don't exactly fit are passed up to the next larger size.  In this
859243Sobrien * implementation, the available sizes are 2^n-4 (or 2^n-12) bytes long.
959243Sobrien * This is designed for use in a program that uses vast quantities of memory,
1059243Sobrien * but bombs when it runs out.
1159243Sobrien */
1259243Sobrien/*-
1359243Sobrien * Copyright (c) 1980, 1991 The Regents of the University of California.
1459243Sobrien * All rights reserved.
1559243Sobrien *
1659243Sobrien * Redistribution and use in source and binary forms, with or without
1759243Sobrien * modification, are permitted provided that the following conditions
1859243Sobrien * are met:
1959243Sobrien * 1. Redistributions of source code must retain the above copyright
2059243Sobrien *    notice, this list of conditions and the following disclaimer.
2159243Sobrien * 2. Redistributions in binary form must reproduce the above copyright
2259243Sobrien *    notice, this list of conditions and the following disclaimer in the
2359243Sobrien *    documentation and/or other materials provided with the distribution.
24100616Smp * 3. Neither the name of the University nor the names of its contributors
2559243Sobrien *    may be used to endorse or promote products derived from this software
2659243Sobrien *    without specific prior written permission.
2759243Sobrien *
2859243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2959243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3059243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3159243Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
3259243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3359243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3459243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3559243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3659243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3759243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3859243Sobrien * SUCH DAMAGE.
3959243Sobrien */
4059243Sobrien#include "sh.h"
41231990Smp#ifdef HAVE_MALLINFO
42231990Smp#include <malloc.h>
43231990Smp#endif
44316957Sdchagin#if defined(HAVE_SBRK) && !defined(__APPLE__)
45316957Sdchagin#define USE_SBRK
46316957Sdchagin#endif
4759243Sobrien
48167465Smp#define RCHECK
49167465Smp#define DEBUG
50167465Smp
5159243Sobrienstatic char   *memtop = NULL;		/* PWP: top of current memory */
5259243Sobrienstatic char   *membot = NULL;		/* PWP: bottom of allocatable memory */
5359243Sobrien
5459243Sobrienint dont_free = 0;
5559243Sobrien
5669408Sache#ifdef WINNT_NATIVE
5759243Sobrien# define malloc		fmalloc
5859243Sobrien# define free		ffree
5959243Sobrien# define calloc		fcalloc
6059243Sobrien# define realloc	frealloc
6169408Sache#endif /* WINNT_NATIVE */
6259243Sobrien
63167465Smp#if !defined(DEBUG) || defined(SYSMALLOC)
64167465Smpstatic void
65167465Smpout_of_memory (void)
66167465Smp{
67167465Smp    static const char msg[] = "Out of memory\n";
68167465Smp
69316957Sdchagin    TCSH_IGNORE(write(didfds ? 2 : SHDIAG, msg, strlen(msg)));
70167465Smp    _exit(1);
71167465Smp}
72167465Smp#endif
73167465Smp
7459243Sobrien#ifndef SYSMALLOC
7559243Sobrien
7659243Sobrien#ifdef SX
7759243Sobrienextern void* sbrk();
7859243Sobrien#endif
7959243Sobrien/*
8059243Sobrien * Lots of os routines are busted and try to free invalid pointers.
8159243Sobrien * Although our free routine is smart enough and it will pick bad
8259243Sobrien * pointers most of the time, in cases where we know we are going to get
8359243Sobrien * a bad pointer, we'd rather leak.
8459243Sobrien */
8559243Sobrien
8659243Sobrien#ifndef NULL
8759243Sobrien#define	NULL 0
8859243Sobrien#endif
8959243Sobrien
9059243Sobrientypedef unsigned char U_char;	/* we don't really have signed chars */
9159243Sobrientypedef unsigned int U_int;
9259243Sobrientypedef unsigned short U_short;
9359243Sobrientypedef unsigned long U_long;
9459243Sobrien
9559243Sobrien
9659243Sobrien/*
9759243Sobrien * The overhead on a block is at least 4 bytes.  When free, this space
9859243Sobrien * contains a pointer to the next free block, and the bottom two bits must
9959243Sobrien * be zero.  When in use, the first byte is set to MAGIC, and the second
10059243Sobrien * byte is the size index.  The remaining bytes are for alignment.
10159243Sobrien * If range checking is enabled and the size of the block fits
10259243Sobrien * in two bytes, then the top two bytes hold the size of the requested block
10359243Sobrien * plus the range checking words, and the header word MINUS ONE.
10459243Sobrien */
10559243Sobrien
10659243Sobrien
10759243Sobrien#define MEMALIGN(a) (((a) + ROUNDUP) & ~ROUNDUP)
10859243Sobrien
10959243Sobrienunion overhead {
11059243Sobrien    union overhead *ov_next;	/* when free */
11159243Sobrien    struct {
11259243Sobrien	U_char  ovu_magic;	/* magic number */
11359243Sobrien	U_char  ovu_index;	/* bucket # */
11459243Sobrien#ifdef RCHECK
11559243Sobrien	U_short ovu_size;	/* actual block size */
11659243Sobrien	U_int   ovu_rmagic;	/* range magic number */
11759243Sobrien#endif
11859243Sobrien    }       ovu;
11959243Sobrien#define	ov_magic	ovu.ovu_magic
12059243Sobrien#define	ov_index	ovu.ovu_index
12159243Sobrien#define	ov_size		ovu.ovu_size
12259243Sobrien#define	ov_rmagic	ovu.ovu_rmagic
12359243Sobrien};
12459243Sobrien
12559243Sobrien#define	MAGIC		0xfd	/* magic # on accounting info */
12659243Sobrien#define RMAGIC		0x55555555	/* magic # on range info */
12759243Sobrien#ifdef RCHECK
12859243Sobrien#define	RSLOP		sizeof (U_int)
12959243Sobrien#else
13059243Sobrien#define	RSLOP		0
13159243Sobrien#endif
13259243Sobrien
13359243Sobrien
134316957Sdchagin#ifdef _LP64
135316957Sdchagin#define ROUNDUP	15
136316957Sdchagin#else
13759243Sobrien#define ROUNDUP	7
138316957Sdchagin#endif
13959243Sobrien
14059243Sobrien/*
14159243Sobrien * nextf[i] is the pointer to the next free block of size 2^(i+3).  The
14259243Sobrien * smallest allocatable block is 8 bytes.  The overhead information
14359243Sobrien * precedes the data area returned to the user.
14459243Sobrien */
14559243Sobrien#define	NBUCKETS ((sizeof(long) << 3) - 3)
14659243Sobrienstatic union overhead *nextf[NBUCKETS] IZERO_STRUCT;
14759243Sobrien
14859243Sobrien/*
14959243Sobrien * nmalloc[i] is the difference between the number of mallocs and frees
15059243Sobrien * for a given block size.
15159243Sobrien */
15259243Sobrienstatic U_int nmalloc[NBUCKETS] IZERO_STRUCT;
15359243Sobrien
15459243Sobrien#ifndef lint
155167465Smpstatic	int	findbucket	(union overhead *, int);
156167465Smpstatic	void	morecore	(int);
15759243Sobrien#endif
15859243Sobrien
15959243Sobrien
16059243Sobrien#ifdef DEBUG
16159243Sobrien# define CHECK(a, str, p) \
16259243Sobrien    if (a) { \
16359243Sobrien	xprintf(str, p);	\
164167465Smp	xprintf(" (memtop = %p membot = %p)\n", memtop, membot);	\
16559243Sobrien	abort(); \
16659243Sobrien    }
16759243Sobrien#else
16859243Sobrien# define CHECK(a, str, p) \
16959243Sobrien    if (a) { \
17059243Sobrien	xprintf(str, p);	\
171167465Smp	xprintf(" (memtop = %p membot = %p)\n", memtop, membot);	\
17259243Sobrien	return; \
17359243Sobrien    }
17459243Sobrien#endif
17559243Sobrien
17659243Sobrienmemalign_t
177167465Smpmalloc(size_t nbytes)
17859243Sobrien{
17959243Sobrien#ifndef lint
180145479Smp    union overhead *p;
181145479Smp    int bucket = 0;
182145479Smp    unsigned shiftr;
18359243Sobrien
18459243Sobrien    /*
18559243Sobrien     * Convert amount of memory requested into closest block size stored in
18659243Sobrien     * hash buckets which satisfies request.  Account for space used per block
18759243Sobrien     * for accounting.
18859243Sobrien     */
18959243Sobrien#ifdef SUNOS4
19059243Sobrien    /*
19159243Sobrien     * SunOS localtime() overwrites the 9th byte on an 8 byte malloc()....
19259243Sobrien     * so we get one more...
19359243Sobrien     * From Michael Schroeder: This is not true. It depends on the
19459243Sobrien     * timezone string. In Europe it can overwrite the 13th byte on a
19559243Sobrien     * 12 byte malloc.
19659243Sobrien     * So we punt and we always allocate an extra byte.
19759243Sobrien     */
19859243Sobrien    nbytes++;
19959243Sobrien#endif
20059243Sobrien
20159243Sobrien    nbytes = MEMALIGN(MEMALIGN(sizeof(union overhead)) + nbytes + RSLOP);
20259243Sobrien    shiftr = (nbytes - 1) >> 2;
20359243Sobrien
20459243Sobrien    /* apart from this loop, this is O(1) */
20559243Sobrien    while ((shiftr >>= 1) != 0)
20659243Sobrien	bucket++;
20759243Sobrien    /*
20859243Sobrien     * If nothing in hash bucket right now, request more memory from the
20959243Sobrien     * system.
21059243Sobrien     */
21159243Sobrien    if (nextf[bucket] == NULL)
21259243Sobrien	morecore(bucket);
213167465Smp    if ((p = nextf[bucket]) == NULL) {
21459243Sobrien	child++;
21559243Sobrien#ifndef DEBUG
216167465Smp	out_of_memory();
21759243Sobrien#else
21859243Sobrien	showall(NULL, NULL);
219167465Smp	xprintf(CGETS(19, 1, "nbytes=%zu: Out of memory\n"), nbytes);
22059243Sobrien	abort();
22159243Sobrien#endif
22259243Sobrien	/* fool lint */
22359243Sobrien	return ((memalign_t) 0);
22459243Sobrien    }
22559243Sobrien    /* remove from linked list */
22659243Sobrien    nextf[bucket] = nextf[bucket]->ov_next;
22759243Sobrien    p->ov_magic = MAGIC;
22859243Sobrien    p->ov_index = bucket;
22959243Sobrien    nmalloc[bucket]++;
23059243Sobrien#ifdef RCHECK
23159243Sobrien    /*
23259243Sobrien     * Record allocated size of block and bound space with magic numbers.
23359243Sobrien     */
234354195Sbrooks    p->ov_size = (p->ov_index <= 13) ? (U_short)nbytes - 1 : 0;
23559243Sobrien    p->ov_rmagic = RMAGIC;
23659243Sobrien    *((U_int *) (((caddr_t) p) + nbytes - RSLOP)) = RMAGIC;
23759243Sobrien#endif
23859243Sobrien    return ((memalign_t) (((caddr_t) p) + MEMALIGN(sizeof(union overhead))));
23959243Sobrien#else
24059243Sobrien    if (nbytes)
24159243Sobrien	return ((memalign_t) 0);
24259243Sobrien    else
24359243Sobrien	return ((memalign_t) 0);
24459243Sobrien#endif /* !lint */
24559243Sobrien}
24659243Sobrien
24759243Sobrien#ifndef lint
24859243Sobrien/*
24959243Sobrien * Allocate more memory to the indicated bucket.
25059243Sobrien */
25159243Sobrienstatic void
252167465Smpmorecore(int bucket)
25359243Sobrien{
254145479Smp    union overhead *op;
255145479Smp    int rnu;		/* 2^rnu bytes will be requested */
256145479Smp    int nblks;		/* become nblks blocks of the desired size */
257145479Smp    int siz;
25859243Sobrien
25959243Sobrien    if (nextf[bucket])
26059243Sobrien	return;
26159243Sobrien    /*
26259243Sobrien     * Insure memory is allocated on a page boundary.  Should make getpageize
26359243Sobrien     * call?
26459243Sobrien     */
26559243Sobrien    op = (union overhead *) sbrk(0);
26659243Sobrien    memtop = (char *) op;
26759243Sobrien    if (membot == NULL)
26859243Sobrien	membot = memtop;
26959243Sobrien    if ((long) op & 0x3ff) {
270167465Smp	memtop = sbrk((int) (1024 - ((long) op & 0x3ff)));
27159243Sobrien	memtop += (long) (1024 - ((long) op & 0x3ff));
27259243Sobrien    }
27359243Sobrien
27459243Sobrien    /* take 2k unless the block is bigger than that */
27559243Sobrien    rnu = (bucket <= 8) ? 11 : bucket + 3;
27659243Sobrien    nblks = 1 << (rnu - (bucket + 3));	/* how many blocks to get */
277167465Smp    memtop = sbrk(1 << rnu);	/* PWP */
27859243Sobrien    op = (union overhead *) memtop;
27959243Sobrien    /* no more room! */
28059243Sobrien    if ((long) op == -1)
28159243Sobrien	return;
28259243Sobrien    memtop += (long) (1 << rnu);
28359243Sobrien    /*
28459243Sobrien     * Round up to minimum allocation size boundary and deduct from block count
28559243Sobrien     * to reflect.
28659243Sobrien     */
28759243Sobrien    if (((U_long) op) & ROUNDUP) {
28859243Sobrien	op = (union overhead *) (((U_long) op + (ROUNDUP + 1)) & ~ROUNDUP);
28959243Sobrien	nblks--;
29059243Sobrien    }
29159243Sobrien    /*
29259243Sobrien     * Add new memory allocated to that on free list for this hash bucket.
29359243Sobrien     */
29459243Sobrien    nextf[bucket] = op;
29559243Sobrien    siz = 1 << (bucket + 3);
29659243Sobrien    while (--nblks > 0) {
29759243Sobrien	op->ov_next = (union overhead *) (((caddr_t) op) + siz);
29859243Sobrien	op = (union overhead *) (((caddr_t) op) + siz);
29959243Sobrien    }
30059243Sobrien    op->ov_next = NULL;
30159243Sobrien}
30259243Sobrien
30359243Sobrien#endif
30459243Sobrien
30559243Sobrienvoid
306167465Smpfree(ptr_t cp)
30759243Sobrien{
30859243Sobrien#ifndef lint
309145479Smp    int size;
310145479Smp    union overhead *op;
31159243Sobrien
31259243Sobrien    /*
31359243Sobrien     * the don't free flag is there so that we avoid os bugs in routines
31459243Sobrien     * that free invalid pointers!
31559243Sobrien     */
31659243Sobrien    if (cp == NULL || dont_free)
31759243Sobrien	return;
31859243Sobrien    CHECK(!memtop || !membot,
319167465Smp	  CGETS(19, 2, "free(%p) called before any allocations."), cp);
32059243Sobrien    CHECK(cp > (ptr_t) memtop,
321167465Smp	  CGETS(19, 3, "free(%p) above top of memory."), cp);
32259243Sobrien    CHECK(cp < (ptr_t) membot,
323167465Smp	  CGETS(19, 4, "free(%p) below bottom of memory."), cp);
32459243Sobrien    op = (union overhead *) (((caddr_t) cp) - MEMALIGN(sizeof(union overhead)));
32559243Sobrien    CHECK(op->ov_magic != MAGIC,
326167465Smp	  CGETS(19, 5, "free(%p) bad block."), cp);
32759243Sobrien
32859243Sobrien#ifdef RCHECK
32959243Sobrien    if (op->ov_index <= 13)
33059243Sobrien	CHECK(*(U_int *) ((caddr_t) op + op->ov_size + 1 - RSLOP) != RMAGIC,
331167465Smp	      CGETS(19, 6, "free(%p) bad range check."), cp);
33259243Sobrien#endif
33359243Sobrien    CHECK(op->ov_index >= NBUCKETS,
334167465Smp	  CGETS(19, 7, "free(%p) bad block index."), cp);
33559243Sobrien    size = op->ov_index;
33659243Sobrien    op->ov_next = nextf[size];
33759243Sobrien    nextf[size] = op;
33859243Sobrien
33959243Sobrien    nmalloc[size]--;
34059243Sobrien
34159243Sobrien#else
34259243Sobrien    if (cp == NULL)
34359243Sobrien	return;
34459243Sobrien#endif
34559243Sobrien}
34659243Sobrien
34759243Sobrienmemalign_t
348167465Smpcalloc(size_t i, size_t j)
34959243Sobrien{
35059243Sobrien#ifndef lint
351167465Smp    char *cp;
352316957Sdchagin    volatile size_t k;
35359243Sobrien
35459243Sobrien    i *= j;
355167465Smp    cp = xmalloc(i);
356316957Sdchagin    /* Stop gcc 5.x from optimizing malloc+memset = calloc */
357316957Sdchagin    k = i;
358316957Sdchagin    memset(cp, 0, k);
35959243Sobrien
360167465Smp    return ((memalign_t) cp);
36159243Sobrien#else
36259243Sobrien    if (i && j)
36359243Sobrien	return ((memalign_t) 0);
36459243Sobrien    else
36559243Sobrien	return ((memalign_t) 0);
36659243Sobrien#endif
36759243Sobrien}
36859243Sobrien
36959243Sobrien/*
37059243Sobrien * When a program attempts "storage compaction" as mentioned in the
37159243Sobrien * old malloc man page, it realloc's an already freed block.  Usually
37259243Sobrien * this is the last block it freed; occasionally it might be farther
37359243Sobrien * back.  We have to search all the free lists for the block in order
37459243Sobrien * to determine its bucket: 1st we make one pass thru the lists
37559243Sobrien * checking only the first block in each; if that fails we search
37659243Sobrien * ``realloc_srchlen'' blocks in each list for a match (the variable
37759243Sobrien * is extern so the caller can modify it).  If that fails we just copy
37859243Sobrien * however many bytes was given to realloc() and hope it's not huge.
37959243Sobrien */
38059243Sobrien#ifndef lint
38159243Sobrien/* 4 should be plenty, -1 =>'s whole list */
38259243Sobrienstatic int     realloc_srchlen = 4;
38359243Sobrien#endif /* lint */
38459243Sobrien
38559243Sobrienmemalign_t
386167465Smprealloc(ptr_t cp, size_t nbytes)
38759243Sobrien{
38859243Sobrien#ifndef lint
389145479Smp    U_int onb;
39059243Sobrien    union overhead *op;
39159243Sobrien    ptr_t res;
392145479Smp    int i;
39359243Sobrien    int     was_alloced = 0;
39459243Sobrien
39559243Sobrien    if (cp == NULL)
39659243Sobrien	return (malloc(nbytes));
39759243Sobrien    op = (union overhead *) (((caddr_t) cp) - MEMALIGN(sizeof(union overhead)));
39859243Sobrien    if (op->ov_magic == MAGIC) {
39959243Sobrien	was_alloced++;
40059243Sobrien	i = op->ov_index;
40159243Sobrien    }
40259243Sobrien    else
40359243Sobrien	/*
40459243Sobrien	 * Already free, doing "compaction".
40559243Sobrien	 *
40659243Sobrien	 * Search for the old block of memory on the free list.  First, check the
40759243Sobrien	 * most common case (last element free'd), then (this failing) the last
40859243Sobrien	 * ``realloc_srchlen'' items free'd. If all lookups fail, then assume
40959243Sobrien	 * the size of the memory block being realloc'd is the smallest
41059243Sobrien	 * possible.
41159243Sobrien	 */
41259243Sobrien	if ((i = findbucket(op, 1)) < 0 &&
41359243Sobrien	    (i = findbucket(op, realloc_srchlen)) < 0)
41459243Sobrien	    i = 0;
41559243Sobrien
41659243Sobrien    onb = MEMALIGN(nbytes + MEMALIGN(sizeof(union overhead)) + RSLOP);
41759243Sobrien
41859243Sobrien    /* avoid the copy if same size block */
41959243Sobrien    if (was_alloced && (onb <= (U_int) (1 << (i + 3))) &&
42059243Sobrien	(onb > (U_int) (1 << (i + 2)))) {
42159243Sobrien#ifdef RCHECK
42259243Sobrien	/* JMR: formerly this wasn't updated ! */
42359243Sobrien	nbytes = MEMALIGN(MEMALIGN(sizeof(union overhead))+nbytes+RSLOP);
42459243Sobrien	*((U_int *) (((caddr_t) op) + nbytes - RSLOP)) = RMAGIC;
42559243Sobrien	op->ov_rmagic = RMAGIC;
426354195Sbrooks	op->ov_size = (op->ov_index <= 13) ? (U_short)nbytes - 1 : 0;
42759243Sobrien#endif
42859243Sobrien	return ((memalign_t) cp);
42959243Sobrien    }
43059243Sobrien    if ((res = malloc(nbytes)) == NULL)
43159243Sobrien	return ((memalign_t) NULL);
43259243Sobrien    if (cp != res) {		/* common optimization */
43359243Sobrien	/*
43459243Sobrien	 * christos: this used to copy nbytes! It should copy the
43559243Sobrien	 * smaller of the old and new size
43659243Sobrien	 */
43759243Sobrien	onb = (1 << (i + 3)) - MEMALIGN(sizeof(union overhead)) - RSLOP;
438167465Smp	(void) memmove(res, cp, onb < nbytes ? onb : nbytes);
43959243Sobrien    }
44059243Sobrien    if (was_alloced)
44159243Sobrien	free(cp);
44259243Sobrien    return ((memalign_t) res);
44359243Sobrien#else
44459243Sobrien    if (cp && nbytes)
44559243Sobrien	return ((memalign_t) 0);
44659243Sobrien    else
44759243Sobrien	return ((memalign_t) 0);
44859243Sobrien#endif /* !lint */
44959243Sobrien}
45059243Sobrien
451231990Smp/*
452231990Smp * On linux, _nss_nis_setnetgrent() calls this function to determine
453231990Smp * the usable size of the pointer passed, but this is not a portable
454231990Smp * API, so we cannot use our malloc replacement without providing one.
455231990Smp * Thanks a lot glibc!
456231990Smp */
457231990Smp#ifdef __linux__
458231990Smp#define M_U_S_CONST
459231990Smp#else
460231990Smp#define M_U_S_CONST
461231990Smp#endif
462231990Smpsize_t malloc_usable_size(M_U_S_CONST void *);
463231990Smpsize_t
464231990Smpmalloc_usable_size(M_U_S_CONST void *ptr)
465231990Smp{
466231990Smp    const union overhead *op = (const union overhead *)
467231990Smp	(((const char *) ptr) - MEMALIGN(sizeof(*op)));
468231990Smp    if (op->ov_magic == MAGIC)
469316957Sdchagin	    return 1 << (op->ov_index + 3);
470231990Smp    else
471231990Smp	    return 0;
472231990Smp}
47359243Sobrien
47459243Sobrien
47559243Sobrien#ifndef lint
47659243Sobrien/*
47759243Sobrien * Search ``srchlen'' elements of each free list for a block whose
47859243Sobrien * header starts at ``freep''.  If srchlen is -1 search the whole list.
47959243Sobrien * Return bucket number, or -1 if not found.
48059243Sobrien */
48159243Sobrienstatic int
482167465Smpfindbucket(union overhead *freep, int srchlen)
48359243Sobrien{
484145479Smp    union overhead *p;
485145479Smp    size_t i;
486145479Smp    int j;
48759243Sobrien
48859243Sobrien    for (i = 0; i < NBUCKETS; i++) {
48959243Sobrien	j = 0;
49059243Sobrien	for (p = nextf[i]; p && j != srchlen; p = p->ov_next) {
49159243Sobrien	    if (p == freep)
49259243Sobrien		return (i);
49359243Sobrien	    j++;
49459243Sobrien	}
49559243Sobrien    }
49659243Sobrien    return (-1);
49759243Sobrien}
49859243Sobrien
49959243Sobrien#endif
50059243Sobrien
50159243Sobrien
50259243Sobrien#else				/* SYSMALLOC */
50359243Sobrien
50459243Sobrien/**
50559243Sobrien ** ``Protected versions'' of malloc, realloc, calloc, and free
50659243Sobrien **
50759243Sobrien ** On many systems:
50859243Sobrien **
50959243Sobrien ** 1. malloc(0) is bad
51059243Sobrien ** 2. free(0) is bad
51159243Sobrien ** 3. realloc(0, n) is bad
51259243Sobrien ** 4. realloc(n, 0) is bad
51359243Sobrien **
51459243Sobrien ** Also we call our error routine if we run out of memory.
51559243Sobrien **/
51659243Sobrienmemalign_t
517167465Smpsmalloc(size_t n)
51859243Sobrien{
51959243Sobrien    ptr_t   ptr;
52059243Sobrien
52159243Sobrien    n = n ? n : 1;
52259243Sobrien
523316957Sdchagin#ifdef USE_SBRK
52459243Sobrien    if (membot == NULL)
525167465Smp	membot = sbrk(0);
526316957Sdchagin#endif /* USE_SBRK */
52759243Sobrien
528167465Smp    if ((ptr = malloc(n)) == NULL)
529167465Smp	out_of_memory();
530316957Sdchagin#ifndef USE_SBRK
53159243Sobrien    if (memtop < ((char *) ptr) + n)
53259243Sobrien	memtop = ((char *) ptr) + n;
53359243Sobrien    if (membot == NULL)
534167465Smp	membot = ptr;
535316957Sdchagin#endif /* !USE_SBRK */
53659243Sobrien    return ((memalign_t) ptr);
53759243Sobrien}
53859243Sobrien
53959243Sobrienmemalign_t
540167465Smpsrealloc(ptr_t p, size_t n)
54159243Sobrien{
54259243Sobrien    ptr_t   ptr;
54359243Sobrien
54459243Sobrien    n = n ? n : 1;
54559243Sobrien
546316957Sdchagin#ifdef USE_SBRK
54759243Sobrien    if (membot == NULL)
548167465Smp	membot = sbrk(0);
549316957Sdchagin#endif /* USE_SBRK */
55059243Sobrien
551167465Smp    if ((ptr = (p ? realloc(p, n) : malloc(n))) == NULL)
552167465Smp	out_of_memory();
553316957Sdchagin#ifndef USE_SBRK
55459243Sobrien    if (memtop < ((char *) ptr) + n)
55559243Sobrien	memtop = ((char *) ptr) + n;
55659243Sobrien    if (membot == NULL)
557167465Smp	membot = ptr;
558316957Sdchagin#endif /* !USE_SBRK */
55959243Sobrien    return ((memalign_t) ptr);
56059243Sobrien}
56159243Sobrien
56259243Sobrienmemalign_t
563167465Smpscalloc(size_t s, size_t n)
56459243Sobrien{
56559243Sobrien    ptr_t   ptr;
56659243Sobrien
56759243Sobrien    n *= s;
56859243Sobrien    n = n ? n : 1;
56959243Sobrien
570316957Sdchagin#ifdef USE_SBRK
57159243Sobrien    if (membot == NULL)
572167465Smp	membot = sbrk(0);
573316957Sdchagin#endif /* USE_SBRK */
57459243Sobrien
575167465Smp    if ((ptr = malloc(n)) == NULL)
576167465Smp	out_of_memory();
57759243Sobrien
578167465Smp    memset (ptr, 0, n);
57959243Sobrien
580316957Sdchagin#ifndef USE_SBRK
58159243Sobrien    if (memtop < ((char *) ptr) + n)
58259243Sobrien	memtop = ((char *) ptr) + n;
58359243Sobrien    if (membot == NULL)
584167465Smp	membot = ptr;
585316957Sdchagin#endif /* !USE_SBRK */
58659243Sobrien
58759243Sobrien    return ((memalign_t) ptr);
58859243Sobrien}
58959243Sobrien
59059243Sobrienvoid
591167465Smpsfree(ptr_t p)
59259243Sobrien{
59359243Sobrien    if (p && !dont_free)
59459243Sobrien	free(p);
59559243Sobrien}
59659243Sobrien
59759243Sobrien#endif /* SYSMALLOC */
59859243Sobrien
59959243Sobrien/*
60059243Sobrien * mstats - print out statistics about malloc
60159243Sobrien *
60259243Sobrien * Prints two lines of numbers, one showing the length of the free list
60359243Sobrien * for each size category, the second showing the number of mallocs -
60459243Sobrien * frees for each size category.
60559243Sobrien */
60659243Sobrien/*ARGSUSED*/
60759243Sobrienvoid
608167465Smpshowall(Char **v, struct command *c)
60959243Sobrien{
61059243Sobrien#ifndef SYSMALLOC
611145479Smp    size_t i, j;
612145479Smp    union overhead *p;
61359243Sobrien    int     totfree = 0, totused = 0;
61459243Sobrien
61559243Sobrien    xprintf(CGETS(19, 8, "%s current memory allocation:\nfree:\t"), progname);
61659243Sobrien    for (i = 0; i < NBUCKETS; i++) {
61759243Sobrien	for (j = 0, p = nextf[i]; p; p = p->ov_next, j++)
61859243Sobrien	    continue;
619167465Smp	xprintf(" %4zd", j);
62059243Sobrien	totfree += j * (1 << (i + 3));
62159243Sobrien    }
622231990Smp    xprintf("\n%s:\t", CGETS(19, 9, "used"));
62359243Sobrien    for (i = 0; i < NBUCKETS; i++) {
624167465Smp	xprintf(" %4d", nmalloc[i]);
62559243Sobrien	totused += nmalloc[i] * (1 << (i + 3));
62659243Sobrien    }
62759243Sobrien    xprintf(CGETS(19, 10, "\n\tTotal in use: %d, total free: %d\n"),
62859243Sobrien	    totused, totfree);
62959243Sobrien    xprintf(CGETS(19, 11,
63059243Sobrien	    "\tAllocated memory from 0x%lx to 0x%lx.  Real top at 0x%lx\n"),
63159243Sobrien	    (unsigned long) membot, (unsigned long) memtop,
63259243Sobrien	    (unsigned long) sbrk(0));
633231990Smp#else /* SYSMALLOC */
634231990Smp#ifndef HAVE_MALLINFO
635316957Sdchagin#ifdef USE_SBRK
636167465Smp    memtop = sbrk(0);
637316957Sdchagin#endif /* USE_SBRK */
63859243Sobrien    xprintf(CGETS(19, 12, "Allocated memory from 0x%lx to 0x%lx (%ld).\n"),
63959243Sobrien	    (unsigned long) membot, (unsigned long) memtop,
64059243Sobrien	    (unsigned long) (memtop - membot));
641231990Smp#else /* HAVE_MALLINFO */
642231990Smp    struct mallinfo mi;
643231990Smp
644231990Smp    mi = mallinfo();
645231990Smp    xprintf(CGETS(19, 13, "%s current memory allocation:\n"), progname);
646231990Smp    xprintf(CGETS(19, 14, "Total space allocated from system: %d\n"), mi.arena);
647231990Smp    xprintf(CGETS(19, 15, "Number of non-inuse chunks: %d\n"), mi.ordblks);
648231990Smp    xprintf(CGETS(19, 16, "Number of mmapped regions: %d\n"), mi.hblks);
649231990Smp    xprintf(CGETS(19, 17, "Total space in mmapped regions: %d\n"), mi.hblkhd);
650231990Smp    xprintf(CGETS(19, 18, "Total allocated space: %d\n"), mi.uordblks);
651231990Smp    xprintf(CGETS(19, 19, "Total non-inuse space: %d\n"), mi.fordblks);
652231990Smp    xprintf(CGETS(19, 20, "Top-most, releasable space: %d\n"), mi.keepcost);
653231990Smp#endif /* HAVE_MALLINFO */
65459243Sobrien#endif /* SYSMALLOC */
65559243Sobrien    USE(c);
65659243Sobrien    USE(v);
65759243Sobrien}
658