1316958Sdchagin/* $Header: /p/tcsh/cvsroot/tcsh/tc.alloc.c,v 3.56 2016/03/08 12:47:43 christos Exp $ */
259243Sobrien/*
359243Sobrien * tc.alloc.c (Caltech) 2/21/82
459243Sobrien * Chris Kingsley, kingsley@cit-20.
559243Sobrien *
659243Sobrien * This is a very fast storage allocator.  It allocates blocks of a small
759243Sobrien * number of different sizes, and keeps free lists of each size.  Blocks that
859243Sobrien * don't exactly fit are passed up to the next larger size.  In this
959243Sobrien * implementation, the available sizes are 2^n-4 (or 2^n-12) bytes long.
1059243Sobrien * This is designed for use in a program that uses vast quantities of memory,
1159243Sobrien * but bombs when it runs out.
1259243Sobrien */
1359243Sobrien/*-
1459243Sobrien * Copyright (c) 1980, 1991 The Regents of the University of California.
1559243Sobrien * All rights reserved.
1659243Sobrien *
1759243Sobrien * Redistribution and use in source and binary forms, with or without
1859243Sobrien * modification, are permitted provided that the following conditions
1959243Sobrien * are met:
2059243Sobrien * 1. Redistributions of source code must retain the above copyright
2159243Sobrien *    notice, this list of conditions and the following disclaimer.
2259243Sobrien * 2. Redistributions in binary form must reproduce the above copyright
2359243Sobrien *    notice, this list of conditions and the following disclaimer in the
2459243Sobrien *    documentation and/or other materials provided with the distribution.
25100616Smp * 3. Neither the name of the University nor the names of its contributors
2659243Sobrien *    may be used to endorse or promote products derived from this software
2759243Sobrien *    without specific prior written permission.
2859243Sobrien *
2959243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
3059243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3159243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3259243Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
3359243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3459243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3559243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3659243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3759243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3859243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3959243Sobrien * SUCH DAMAGE.
4059243Sobrien */
4159243Sobrien#include "sh.h"
42231990Smp#ifdef HAVE_MALLINFO
43231990Smp#include <malloc.h>
44231990Smp#endif
45316958Sdchagin#if defined(HAVE_SBRK) && !defined(__APPLE__)
46316958Sdchagin#define USE_SBRK
47316958Sdchagin#endif
4859243Sobrien
49316958SdchaginRCSID("$tcsh: tc.alloc.c,v 3.56 2016/03/08 12:47:43 christos Exp $")
5059243Sobrien
51167465Smp#define RCHECK
52167465Smp#define DEBUG
53167465Smp
5459243Sobrienstatic char   *memtop = NULL;		/* PWP: top of current memory */
5559243Sobrienstatic char   *membot = NULL;		/* PWP: bottom of allocatable memory */
5659243Sobrien
5759243Sobrienint dont_free = 0;
5859243Sobrien
5969408Sache#ifdef WINNT_NATIVE
6059243Sobrien# define malloc		fmalloc
6159243Sobrien# define free		ffree
6259243Sobrien# define calloc		fcalloc
6359243Sobrien# define realloc	frealloc
6469408Sache#endif /* WINNT_NATIVE */
6559243Sobrien
66167465Smp#if !defined(DEBUG) || defined(SYSMALLOC)
67167465Smpstatic void
68167465Smpout_of_memory (void)
69167465Smp{
70167465Smp    static const char msg[] = "Out of memory\n";
71167465Smp
72316958Sdchagin    TCSH_IGNORE(write(didfds ? 2 : SHDIAG, msg, strlen(msg)));
73167465Smp    _exit(1);
74167465Smp}
75167465Smp#endif
76167465Smp
7759243Sobrien#ifndef SYSMALLOC
7859243Sobrien
7959243Sobrien#ifdef SX
8059243Sobrienextern void* sbrk();
8159243Sobrien#endif
8259243Sobrien/*
8359243Sobrien * Lots of os routines are busted and try to free invalid pointers.
8459243Sobrien * Although our free routine is smart enough and it will pick bad
8559243Sobrien * pointers most of the time, in cases where we know we are going to get
8659243Sobrien * a bad pointer, we'd rather leak.
8759243Sobrien */
8859243Sobrien
8959243Sobrien#ifndef NULL
9059243Sobrien#define	NULL 0
9159243Sobrien#endif
9259243Sobrien
9359243Sobrientypedef unsigned char U_char;	/* we don't really have signed chars */
9459243Sobrientypedef unsigned int U_int;
9559243Sobrientypedef unsigned short U_short;
9659243Sobrientypedef unsigned long U_long;
9759243Sobrien
9859243Sobrien
9959243Sobrien/*
10059243Sobrien * The overhead on a block is at least 4 bytes.  When free, this space
10159243Sobrien * contains a pointer to the next free block, and the bottom two bits must
10259243Sobrien * be zero.  When in use, the first byte is set to MAGIC, and the second
10359243Sobrien * byte is the size index.  The remaining bytes are for alignment.
10459243Sobrien * If range checking is enabled and the size of the block fits
10559243Sobrien * in two bytes, then the top two bytes hold the size of the requested block
10659243Sobrien * plus the range checking words, and the header word MINUS ONE.
10759243Sobrien */
10859243Sobrien
10959243Sobrien
11059243Sobrien#define MEMALIGN(a) (((a) + ROUNDUP) & ~ROUNDUP)
11159243Sobrien
11259243Sobrienunion overhead {
11359243Sobrien    union overhead *ov_next;	/* when free */
11459243Sobrien    struct {
11559243Sobrien	U_char  ovu_magic;	/* magic number */
11659243Sobrien	U_char  ovu_index;	/* bucket # */
11759243Sobrien#ifdef RCHECK
11859243Sobrien	U_short ovu_size;	/* actual block size */
11959243Sobrien	U_int   ovu_rmagic;	/* range magic number */
12059243Sobrien#endif
12159243Sobrien    }       ovu;
12259243Sobrien#define	ov_magic	ovu.ovu_magic
12359243Sobrien#define	ov_index	ovu.ovu_index
12459243Sobrien#define	ov_size		ovu.ovu_size
12559243Sobrien#define	ov_rmagic	ovu.ovu_rmagic
12659243Sobrien};
12759243Sobrien
12859243Sobrien#define	MAGIC		0xfd	/* magic # on accounting info */
12959243Sobrien#define RMAGIC		0x55555555	/* magic # on range info */
13059243Sobrien#ifdef RCHECK
13159243Sobrien#define	RSLOP		sizeof (U_int)
13259243Sobrien#else
13359243Sobrien#define	RSLOP		0
13459243Sobrien#endif
13559243Sobrien
13659243Sobrien
137316958Sdchagin#ifdef _LP64
138316958Sdchagin#define ROUNDUP	15
139316958Sdchagin#else
14059243Sobrien#define ROUNDUP	7
141316958Sdchagin#endif
14259243Sobrien
14359243Sobrien/*
14459243Sobrien * nextf[i] is the pointer to the next free block of size 2^(i+3).  The
14559243Sobrien * smallest allocatable block is 8 bytes.  The overhead information
14659243Sobrien * precedes the data area returned to the user.
14759243Sobrien */
14859243Sobrien#define	NBUCKETS ((sizeof(long) << 3) - 3)
14959243Sobrienstatic union overhead *nextf[NBUCKETS] IZERO_STRUCT;
15059243Sobrien
15159243Sobrien/*
15259243Sobrien * nmalloc[i] is the difference between the number of mallocs and frees
15359243Sobrien * for a given block size.
15459243Sobrien */
15559243Sobrienstatic U_int nmalloc[NBUCKETS] IZERO_STRUCT;
15659243Sobrien
15759243Sobrien#ifndef lint
158167465Smpstatic	int	findbucket	(union overhead *, int);
159167465Smpstatic	void	morecore	(int);
16059243Sobrien#endif
16159243Sobrien
16259243Sobrien
16359243Sobrien#ifdef DEBUG
16459243Sobrien# define CHECK(a, str, p) \
16559243Sobrien    if (a) { \
16659243Sobrien	xprintf(str, p);	\
167167465Smp	xprintf(" (memtop = %p membot = %p)\n", memtop, membot);	\
16859243Sobrien	abort(); \
16959243Sobrien    }
17059243Sobrien#else
17159243Sobrien# define CHECK(a, str, p) \
17259243Sobrien    if (a) { \
17359243Sobrien	xprintf(str, p);	\
174167465Smp	xprintf(" (memtop = %p membot = %p)\n", memtop, membot);	\
17559243Sobrien	return; \
17659243Sobrien    }
17759243Sobrien#endif
17859243Sobrien
17959243Sobrienmemalign_t
180167465Smpmalloc(size_t nbytes)
18159243Sobrien{
18259243Sobrien#ifndef lint
183145479Smp    union overhead *p;
184145479Smp    int bucket = 0;
185145479Smp    unsigned shiftr;
18659243Sobrien
18759243Sobrien    /*
18859243Sobrien     * Convert amount of memory requested into closest block size stored in
18959243Sobrien     * hash buckets which satisfies request.  Account for space used per block
19059243Sobrien     * for accounting.
19159243Sobrien     */
19259243Sobrien#ifdef SUNOS4
19359243Sobrien    /*
19459243Sobrien     * SunOS localtime() overwrites the 9th byte on an 8 byte malloc()....
19559243Sobrien     * so we get one more...
19659243Sobrien     * From Michael Schroeder: This is not true. It depends on the
19759243Sobrien     * timezone string. In Europe it can overwrite the 13th byte on a
19859243Sobrien     * 12 byte malloc.
19959243Sobrien     * So we punt and we always allocate an extra byte.
20059243Sobrien     */
20159243Sobrien    nbytes++;
20259243Sobrien#endif
20359243Sobrien
20459243Sobrien    nbytes = MEMALIGN(MEMALIGN(sizeof(union overhead)) + nbytes + RSLOP);
20559243Sobrien    shiftr = (nbytes - 1) >> 2;
20659243Sobrien
20759243Sobrien    /* apart from this loop, this is O(1) */
20859243Sobrien    while ((shiftr >>= 1) != 0)
20959243Sobrien	bucket++;
21059243Sobrien    /*
21159243Sobrien     * If nothing in hash bucket right now, request more memory from the
21259243Sobrien     * system.
21359243Sobrien     */
21459243Sobrien    if (nextf[bucket] == NULL)
21559243Sobrien	morecore(bucket);
216167465Smp    if ((p = nextf[bucket]) == NULL) {
21759243Sobrien	child++;
21859243Sobrien#ifndef DEBUG
219167465Smp	out_of_memory();
22059243Sobrien#else
22159243Sobrien	showall(NULL, NULL);
222167465Smp	xprintf(CGETS(19, 1, "nbytes=%zu: Out of memory\n"), nbytes);
22359243Sobrien	abort();
22459243Sobrien#endif
22559243Sobrien	/* fool lint */
22659243Sobrien	return ((memalign_t) 0);
22759243Sobrien    }
22859243Sobrien    /* remove from linked list */
22959243Sobrien    nextf[bucket] = nextf[bucket]->ov_next;
23059243Sobrien    p->ov_magic = MAGIC;
23159243Sobrien    p->ov_index = bucket;
23259243Sobrien    nmalloc[bucket]++;
23359243Sobrien#ifdef RCHECK
23459243Sobrien    /*
23559243Sobrien     * Record allocated size of block and bound space with magic numbers.
23659243Sobrien     */
23759243Sobrien    p->ov_size = (p->ov_index <= 13) ? nbytes - 1 : 0;
23859243Sobrien    p->ov_rmagic = RMAGIC;
23959243Sobrien    *((U_int *) (((caddr_t) p) + nbytes - RSLOP)) = RMAGIC;
24059243Sobrien#endif
24159243Sobrien    return ((memalign_t) (((caddr_t) p) + MEMALIGN(sizeof(union overhead))));
24259243Sobrien#else
24359243Sobrien    if (nbytes)
24459243Sobrien	return ((memalign_t) 0);
24559243Sobrien    else
24659243Sobrien	return ((memalign_t) 0);
24759243Sobrien#endif /* !lint */
24859243Sobrien}
24959243Sobrien
25059243Sobrien#ifndef lint
25159243Sobrien/*
25259243Sobrien * Allocate more memory to the indicated bucket.
25359243Sobrien */
25459243Sobrienstatic void
255167465Smpmorecore(int bucket)
25659243Sobrien{
257145479Smp    union overhead *op;
258145479Smp    int rnu;		/* 2^rnu bytes will be requested */
259145479Smp    int nblks;		/* become nblks blocks of the desired size */
260145479Smp    int siz;
26159243Sobrien
26259243Sobrien    if (nextf[bucket])
26359243Sobrien	return;
26459243Sobrien    /*
26559243Sobrien     * Insure memory is allocated on a page boundary.  Should make getpageize
26659243Sobrien     * call?
26759243Sobrien     */
26859243Sobrien    op = (union overhead *) sbrk(0);
26959243Sobrien    memtop = (char *) op;
27059243Sobrien    if (membot == NULL)
27159243Sobrien	membot = memtop;
27259243Sobrien    if ((long) op & 0x3ff) {
273167465Smp	memtop = sbrk((int) (1024 - ((long) op & 0x3ff)));
27459243Sobrien	memtop += (long) (1024 - ((long) op & 0x3ff));
27559243Sobrien    }
27659243Sobrien
27759243Sobrien    /* take 2k unless the block is bigger than that */
27859243Sobrien    rnu = (bucket <= 8) ? 11 : bucket + 3;
27959243Sobrien    nblks = 1 << (rnu - (bucket + 3));	/* how many blocks to get */
280167465Smp    memtop = sbrk(1 << rnu);	/* PWP */
28159243Sobrien    op = (union overhead *) memtop;
28259243Sobrien    /* no more room! */
28359243Sobrien    if ((long) op == -1)
28459243Sobrien	return;
28559243Sobrien    memtop += (long) (1 << rnu);
28659243Sobrien    /*
28759243Sobrien     * Round up to minimum allocation size boundary and deduct from block count
28859243Sobrien     * to reflect.
28959243Sobrien     */
29059243Sobrien    if (((U_long) op) & ROUNDUP) {
29159243Sobrien	op = (union overhead *) (((U_long) op + (ROUNDUP + 1)) & ~ROUNDUP);
29259243Sobrien	nblks--;
29359243Sobrien    }
29459243Sobrien    /*
29559243Sobrien     * Add new memory allocated to that on free list for this hash bucket.
29659243Sobrien     */
29759243Sobrien    nextf[bucket] = op;
29859243Sobrien    siz = 1 << (bucket + 3);
29959243Sobrien    while (--nblks > 0) {
30059243Sobrien	op->ov_next = (union overhead *) (((caddr_t) op) + siz);
30159243Sobrien	op = (union overhead *) (((caddr_t) op) + siz);
30259243Sobrien    }
30359243Sobrien    op->ov_next = NULL;
30459243Sobrien}
30559243Sobrien
30659243Sobrien#endif
30759243Sobrien
30859243Sobrienvoid
309167465Smpfree(ptr_t cp)
31059243Sobrien{
31159243Sobrien#ifndef lint
312145479Smp    int size;
313145479Smp    union overhead *op;
31459243Sobrien
31559243Sobrien    /*
31659243Sobrien     * the don't free flag is there so that we avoid os bugs in routines
31759243Sobrien     * that free invalid pointers!
31859243Sobrien     */
31959243Sobrien    if (cp == NULL || dont_free)
32059243Sobrien	return;
32159243Sobrien    CHECK(!memtop || !membot,
322167465Smp	  CGETS(19, 2, "free(%p) called before any allocations."), cp);
32359243Sobrien    CHECK(cp > (ptr_t) memtop,
324167465Smp	  CGETS(19, 3, "free(%p) above top of memory."), cp);
32559243Sobrien    CHECK(cp < (ptr_t) membot,
326167465Smp	  CGETS(19, 4, "free(%p) below bottom of memory."), cp);
32759243Sobrien    op = (union overhead *) (((caddr_t) cp) - MEMALIGN(sizeof(union overhead)));
32859243Sobrien    CHECK(op->ov_magic != MAGIC,
329167465Smp	  CGETS(19, 5, "free(%p) bad block."), cp);
33059243Sobrien
33159243Sobrien#ifdef RCHECK
33259243Sobrien    if (op->ov_index <= 13)
33359243Sobrien	CHECK(*(U_int *) ((caddr_t) op + op->ov_size + 1 - RSLOP) != RMAGIC,
334167465Smp	      CGETS(19, 6, "free(%p) bad range check."), cp);
33559243Sobrien#endif
33659243Sobrien    CHECK(op->ov_index >= NBUCKETS,
337167465Smp	  CGETS(19, 7, "free(%p) bad block index."), cp);
33859243Sobrien    size = op->ov_index;
33959243Sobrien    op->ov_next = nextf[size];
34059243Sobrien    nextf[size] = op;
34159243Sobrien
34259243Sobrien    nmalloc[size]--;
34359243Sobrien
34459243Sobrien#else
34559243Sobrien    if (cp == NULL)
34659243Sobrien	return;
34759243Sobrien#endif
34859243Sobrien}
34959243Sobrien
35059243Sobrienmemalign_t
351167465Smpcalloc(size_t i, size_t j)
35259243Sobrien{
35359243Sobrien#ifndef lint
354167465Smp    char *cp;
355316958Sdchagin    volatile size_t k;
35659243Sobrien
35759243Sobrien    i *= j;
358167465Smp    cp = xmalloc(i);
359316958Sdchagin    /* Stop gcc 5.x from optimizing malloc+memset = calloc */
360316958Sdchagin    k = i;
361316958Sdchagin    memset(cp, 0, k);
36259243Sobrien
363167465Smp    return ((memalign_t) cp);
36459243Sobrien#else
36559243Sobrien    if (i && j)
36659243Sobrien	return ((memalign_t) 0);
36759243Sobrien    else
36859243Sobrien	return ((memalign_t) 0);
36959243Sobrien#endif
37059243Sobrien}
37159243Sobrien
37259243Sobrien/*
37359243Sobrien * When a program attempts "storage compaction" as mentioned in the
37459243Sobrien * old malloc man page, it realloc's an already freed block.  Usually
37559243Sobrien * this is the last block it freed; occasionally it might be farther
37659243Sobrien * back.  We have to search all the free lists for the block in order
37759243Sobrien * to determine its bucket: 1st we make one pass thru the lists
37859243Sobrien * checking only the first block in each; if that fails we search
37959243Sobrien * ``realloc_srchlen'' blocks in each list for a match (the variable
38059243Sobrien * is extern so the caller can modify it).  If that fails we just copy
38159243Sobrien * however many bytes was given to realloc() and hope it's not huge.
38259243Sobrien */
38359243Sobrien#ifndef lint
38459243Sobrien/* 4 should be plenty, -1 =>'s whole list */
38559243Sobrienstatic int     realloc_srchlen = 4;
38659243Sobrien#endif /* lint */
38759243Sobrien
38859243Sobrienmemalign_t
389167465Smprealloc(ptr_t cp, size_t nbytes)
39059243Sobrien{
39159243Sobrien#ifndef lint
392145479Smp    U_int onb;
39359243Sobrien    union overhead *op;
39459243Sobrien    ptr_t res;
395145479Smp    int i;
39659243Sobrien    int     was_alloced = 0;
39759243Sobrien
39859243Sobrien    if (cp == NULL)
39959243Sobrien	return (malloc(nbytes));
40059243Sobrien    op = (union overhead *) (((caddr_t) cp) - MEMALIGN(sizeof(union overhead)));
40159243Sobrien    if (op->ov_magic == MAGIC) {
40259243Sobrien	was_alloced++;
40359243Sobrien	i = op->ov_index;
40459243Sobrien    }
40559243Sobrien    else
40659243Sobrien	/*
40759243Sobrien	 * Already free, doing "compaction".
40859243Sobrien	 *
40959243Sobrien	 * Search for the old block of memory on the free list.  First, check the
41059243Sobrien	 * most common case (last element free'd), then (this failing) the last
41159243Sobrien	 * ``realloc_srchlen'' items free'd. If all lookups fail, then assume
41259243Sobrien	 * the size of the memory block being realloc'd is the smallest
41359243Sobrien	 * possible.
41459243Sobrien	 */
41559243Sobrien	if ((i = findbucket(op, 1)) < 0 &&
41659243Sobrien	    (i = findbucket(op, realloc_srchlen)) < 0)
41759243Sobrien	    i = 0;
41859243Sobrien
41959243Sobrien    onb = MEMALIGN(nbytes + MEMALIGN(sizeof(union overhead)) + RSLOP);
42059243Sobrien
42159243Sobrien    /* avoid the copy if same size block */
42259243Sobrien    if (was_alloced && (onb <= (U_int) (1 << (i + 3))) &&
42359243Sobrien	(onb > (U_int) (1 << (i + 2)))) {
42459243Sobrien#ifdef RCHECK
42559243Sobrien	/* JMR: formerly this wasn't updated ! */
42659243Sobrien	nbytes = MEMALIGN(MEMALIGN(sizeof(union overhead))+nbytes+RSLOP);
42759243Sobrien	*((U_int *) (((caddr_t) op) + nbytes - RSLOP)) = RMAGIC;
42859243Sobrien	op->ov_rmagic = RMAGIC;
42959243Sobrien	op->ov_size = (op->ov_index <= 13) ? nbytes - 1 : 0;
43059243Sobrien#endif
43159243Sobrien	return ((memalign_t) cp);
43259243Sobrien    }
43359243Sobrien    if ((res = malloc(nbytes)) == NULL)
43459243Sobrien	return ((memalign_t) NULL);
43559243Sobrien    if (cp != res) {		/* common optimization */
43659243Sobrien	/*
43759243Sobrien	 * christos: this used to copy nbytes! It should copy the
43859243Sobrien	 * smaller of the old and new size
43959243Sobrien	 */
44059243Sobrien	onb = (1 << (i + 3)) - MEMALIGN(sizeof(union overhead)) - RSLOP;
441167465Smp	(void) memmove(res, cp, onb < nbytes ? onb : nbytes);
44259243Sobrien    }
44359243Sobrien    if (was_alloced)
44459243Sobrien	free(cp);
44559243Sobrien    return ((memalign_t) res);
44659243Sobrien#else
44759243Sobrien    if (cp && nbytes)
44859243Sobrien	return ((memalign_t) 0);
44959243Sobrien    else
45059243Sobrien	return ((memalign_t) 0);
45159243Sobrien#endif /* !lint */
45259243Sobrien}
45359243Sobrien
454231990Smp/*
455231990Smp * On linux, _nss_nis_setnetgrent() calls this function to determine
456231990Smp * the usable size of the pointer passed, but this is not a portable
457231990Smp * API, so we cannot use our malloc replacement without providing one.
458231990Smp * Thanks a lot glibc!
459231990Smp */
460231990Smp#ifdef __linux__
461231990Smp#define M_U_S_CONST
462231990Smp#else
463231990Smp#define M_U_S_CONST
464231990Smp#endif
465231990Smpsize_t malloc_usable_size(M_U_S_CONST void *);
466231990Smpsize_t
467231990Smpmalloc_usable_size(M_U_S_CONST void *ptr)
468231990Smp{
469231990Smp    const union overhead *op = (const union overhead *)
470231990Smp	(((const char *) ptr) - MEMALIGN(sizeof(*op)));
471231990Smp    if (op->ov_magic == MAGIC)
472316958Sdchagin	    return 1 << (op->ov_index + 3);
473231990Smp    else
474231990Smp	    return 0;
475231990Smp}
47659243Sobrien
47759243Sobrien
47859243Sobrien#ifndef lint
47959243Sobrien/*
48059243Sobrien * Search ``srchlen'' elements of each free list for a block whose
48159243Sobrien * header starts at ``freep''.  If srchlen is -1 search the whole list.
48259243Sobrien * Return bucket number, or -1 if not found.
48359243Sobrien */
48459243Sobrienstatic int
485167465Smpfindbucket(union overhead *freep, int srchlen)
48659243Sobrien{
487145479Smp    union overhead *p;
488145479Smp    size_t i;
489145479Smp    int j;
49059243Sobrien
49159243Sobrien    for (i = 0; i < NBUCKETS; i++) {
49259243Sobrien	j = 0;
49359243Sobrien	for (p = nextf[i]; p && j != srchlen; p = p->ov_next) {
49459243Sobrien	    if (p == freep)
49559243Sobrien		return (i);
49659243Sobrien	    j++;
49759243Sobrien	}
49859243Sobrien    }
49959243Sobrien    return (-1);
50059243Sobrien}
50159243Sobrien
50259243Sobrien#endif
50359243Sobrien
50459243Sobrien
50559243Sobrien#else				/* SYSMALLOC */
50659243Sobrien
50759243Sobrien/**
50859243Sobrien ** ``Protected versions'' of malloc, realloc, calloc, and free
50959243Sobrien **
51059243Sobrien ** On many systems:
51159243Sobrien **
51259243Sobrien ** 1. malloc(0) is bad
51359243Sobrien ** 2. free(0) is bad
51459243Sobrien ** 3. realloc(0, n) is bad
51559243Sobrien ** 4. realloc(n, 0) is bad
51659243Sobrien **
51759243Sobrien ** Also we call our error routine if we run out of memory.
51859243Sobrien **/
51959243Sobrienmemalign_t
520167465Smpsmalloc(size_t n)
52159243Sobrien{
52259243Sobrien    ptr_t   ptr;
52359243Sobrien
52459243Sobrien    n = n ? n : 1;
52559243Sobrien
526316958Sdchagin#ifdef USE_SBRK
52759243Sobrien    if (membot == NULL)
528167465Smp	membot = sbrk(0);
529316958Sdchagin#endif /* USE_SBRK */
53059243Sobrien
531167465Smp    if ((ptr = malloc(n)) == NULL)
532167465Smp	out_of_memory();
533316958Sdchagin#ifndef USE_SBRK
53459243Sobrien    if (memtop < ((char *) ptr) + n)
53559243Sobrien	memtop = ((char *) ptr) + n;
53659243Sobrien    if (membot == NULL)
537167465Smp	membot = ptr;
538316958Sdchagin#endif /* !USE_SBRK */
53959243Sobrien    return ((memalign_t) ptr);
54059243Sobrien}
54159243Sobrien
54259243Sobrienmemalign_t
543167465Smpsrealloc(ptr_t p, size_t n)
54459243Sobrien{
54559243Sobrien    ptr_t   ptr;
54659243Sobrien
54759243Sobrien    n = n ? n : 1;
54859243Sobrien
549316958Sdchagin#ifdef USE_SBRK
55059243Sobrien    if (membot == NULL)
551167465Smp	membot = sbrk(0);
552316958Sdchagin#endif /* USE_SBRK */
55359243Sobrien
554167465Smp    if ((ptr = (p ? realloc(p, n) : malloc(n))) == NULL)
555167465Smp	out_of_memory();
556316958Sdchagin#ifndef USE_SBRK
55759243Sobrien    if (memtop < ((char *) ptr) + n)
55859243Sobrien	memtop = ((char *) ptr) + n;
55959243Sobrien    if (membot == NULL)
560167465Smp	membot = ptr;
561316958Sdchagin#endif /* !USE_SBRK */
56259243Sobrien    return ((memalign_t) ptr);
56359243Sobrien}
56459243Sobrien
56559243Sobrienmemalign_t
566167465Smpscalloc(size_t s, size_t n)
56759243Sobrien{
56859243Sobrien    ptr_t   ptr;
56959243Sobrien
57059243Sobrien    n *= s;
57159243Sobrien    n = n ? n : 1;
57259243Sobrien
573316958Sdchagin#ifdef USE_SBRK
57459243Sobrien    if (membot == NULL)
575167465Smp	membot = sbrk(0);
576316958Sdchagin#endif /* USE_SBRK */
57759243Sobrien
578167465Smp    if ((ptr = malloc(n)) == NULL)
579167465Smp	out_of_memory();
58059243Sobrien
581167465Smp    memset (ptr, 0, n);
58259243Sobrien
583316958Sdchagin#ifndef USE_SBRK
58459243Sobrien    if (memtop < ((char *) ptr) + n)
58559243Sobrien	memtop = ((char *) ptr) + n;
58659243Sobrien    if (membot == NULL)
587167465Smp	membot = ptr;
588316958Sdchagin#endif /* !USE_SBRK */
58959243Sobrien
59059243Sobrien    return ((memalign_t) ptr);
59159243Sobrien}
59259243Sobrien
59359243Sobrienvoid
594167465Smpsfree(ptr_t p)
59559243Sobrien{
59659243Sobrien    if (p && !dont_free)
59759243Sobrien	free(p);
59859243Sobrien}
59959243Sobrien
60059243Sobrien#endif /* SYSMALLOC */
60159243Sobrien
60259243Sobrien/*
60359243Sobrien * mstats - print out statistics about malloc
60459243Sobrien *
60559243Sobrien * Prints two lines of numbers, one showing the length of the free list
60659243Sobrien * for each size category, the second showing the number of mallocs -
60759243Sobrien * frees for each size category.
60859243Sobrien */
60959243Sobrien/*ARGSUSED*/
61059243Sobrienvoid
611167465Smpshowall(Char **v, struct command *c)
61259243Sobrien{
61359243Sobrien#ifndef SYSMALLOC
614145479Smp    size_t i, j;
615145479Smp    union overhead *p;
61659243Sobrien    int     totfree = 0, totused = 0;
61759243Sobrien
61859243Sobrien    xprintf(CGETS(19, 8, "%s current memory allocation:\nfree:\t"), progname);
61959243Sobrien    for (i = 0; i < NBUCKETS; i++) {
62059243Sobrien	for (j = 0, p = nextf[i]; p; p = p->ov_next, j++)
62159243Sobrien	    continue;
622167465Smp	xprintf(" %4zd", j);
62359243Sobrien	totfree += j * (1 << (i + 3));
62459243Sobrien    }
625231990Smp    xprintf("\n%s:\t", CGETS(19, 9, "used"));
62659243Sobrien    for (i = 0; i < NBUCKETS; i++) {
627167465Smp	xprintf(" %4d", nmalloc[i]);
62859243Sobrien	totused += nmalloc[i] * (1 << (i + 3));
62959243Sobrien    }
63059243Sobrien    xprintf(CGETS(19, 10, "\n\tTotal in use: %d, total free: %d\n"),
63159243Sobrien	    totused, totfree);
63259243Sobrien    xprintf(CGETS(19, 11,
63359243Sobrien	    "\tAllocated memory from 0x%lx to 0x%lx.  Real top at 0x%lx\n"),
63459243Sobrien	    (unsigned long) membot, (unsigned long) memtop,
63559243Sobrien	    (unsigned long) sbrk(0));
636231990Smp#else /* SYSMALLOC */
637231990Smp#ifndef HAVE_MALLINFO
638316958Sdchagin#ifdef USE_SBRK
639167465Smp    memtop = sbrk(0);
640316958Sdchagin#endif /* USE_SBRK */
64159243Sobrien    xprintf(CGETS(19, 12, "Allocated memory from 0x%lx to 0x%lx (%ld).\n"),
64259243Sobrien	    (unsigned long) membot, (unsigned long) memtop,
64359243Sobrien	    (unsigned long) (memtop - membot));
644231990Smp#else /* HAVE_MALLINFO */
645231990Smp    struct mallinfo mi;
646231990Smp
647231990Smp    mi = mallinfo();
648231990Smp    xprintf(CGETS(19, 13, "%s current memory allocation:\n"), progname);
649231990Smp    xprintf(CGETS(19, 14, "Total space allocated from system: %d\n"), mi.arena);
650231990Smp    xprintf(CGETS(19, 15, "Number of non-inuse chunks: %d\n"), mi.ordblks);
651231990Smp    xprintf(CGETS(19, 16, "Number of mmapped regions: %d\n"), mi.hblks);
652231990Smp    xprintf(CGETS(19, 17, "Total space in mmapped regions: %d\n"), mi.hblkhd);
653231990Smp    xprintf(CGETS(19, 18, "Total allocated space: %d\n"), mi.uordblks);
654231990Smp    xprintf(CGETS(19, 19, "Total non-inuse space: %d\n"), mi.fordblks);
655231990Smp    xprintf(CGETS(19, 20, "Top-most, releasable space: %d\n"), mi.keepcost);
656231990Smp#endif /* HAVE_MALLINFO */
65759243Sobrien#endif /* SYSMALLOC */
65859243Sobrien    USE(c);
65959243Sobrien    USE(v);
66059243Sobrien}
661