tc.alloc.c revision 100616
140516Swpaul/* $Header: /src/pub/tcsh/tc.alloc.c,v 3.36 2002/03/08 17:36:47 christos Exp $ */
240516Swpaul/*
340516Swpaul * tc.alloc.c (Caltech) 2/21/82
440516Swpaul * Chris Kingsley, kingsley@cit-20.
540516Swpaul *
640516Swpaul * This is a very fast storage allocator.  It allocates blocks of a small
740516Swpaul * number of different sizes, and keeps free lists of each size.  Blocks that
840516Swpaul * don't exactly fit are passed up to the next larger size.  In this
940516Swpaul * implementation, the available sizes are 2^n-4 (or 2^n-12) bytes long.
1040516Swpaul * This is designed for use in a program that uses vast quantities of memory,
1140516Swpaul * but bombs when it runs out.
1240516Swpaul */
1340516Swpaul/*-
1440516Swpaul * Copyright (c) 1980, 1991 The Regents of the University of California.
1540516Swpaul * All rights reserved.
1640516Swpaul *
1740516Swpaul * Redistribution and use in source and binary forms, with or without
1840516Swpaul * modification, are permitted provided that the following conditions
1940516Swpaul * are met:
2040516Swpaul * 1. Redistributions of source code must retain the above copyright
2140516Swpaul *    notice, this list of conditions and the following disclaimer.
2240516Swpaul * 2. Redistributions in binary form must reproduce the above copyright
2340516Swpaul *    notice, this list of conditions and the following disclaimer in the
2440516Swpaul *    documentation and/or other materials provided with the distribution.
2540516Swpaul * 3. Neither the name of the University nor the names of its contributors
2640516Swpaul *    may be used to endorse or promote products derived from this software
2740516Swpaul *    without specific prior written permission.
2840516Swpaul *
2940516Swpaul * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
3040516Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3140516Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3250477Speter * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
3340516Swpaul * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3440516Swpaul * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3540516Swpaul * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3640516Swpaul * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3740516Swpaul * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3840516Swpaul * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3940516Swpaul * SUCH DAMAGE.
4040516Swpaul */
4140516Swpaul#include "sh.h"
4240516Swpaul
4340516SwpaulRCSID("$Id: tc.alloc.c,v 3.36 2002/03/08 17:36:47 christos Exp $")
4440516Swpaul
4540516Swpaulstatic char   *memtop = NULL;		/* PWP: top of current memory */
4640516Swpaulstatic char   *membot = NULL;		/* PWP: bottom of allocatable memory */
4740516Swpaul
4840516Swpaulint dont_free = 0;
4940516Swpaul
5040516Swpaul#if defined(_VMS_POSIX) || defined(_AMIGA_MEMORY)
5140516Swpaul# define NO_SBRK
5240516Swpaul#endif
5340516Swpaul
5440516Swpaul#ifdef WINNT_NATIVE
5540516Swpaul# define malloc		fmalloc
5641569Swpaul# define free		ffree
5740516Swpaul# define calloc		fcalloc
5840516Swpaul# define realloc	frealloc
5940516Swpaul#endif /* WINNT_NATIVE */
6040516Swpaul
6140516Swpaul#ifndef SYSMALLOC
6240516Swpaul
6340516Swpaul#undef RCHECK
6440516Swpaul#undef DEBUG
6540516Swpaul
6640516Swpaul#ifdef SX
6740516Swpaulextern void* sbrk();
6840516Swpaul#endif
6940516Swpaul/*
7040516Swpaul * Lots of os routines are busted and try to free invalid pointers.
7140516Swpaul * Although our free routine is smart enough and it will pick bad
7240516Swpaul * pointers most of the time, in cases where we know we are going to get
7340516Swpaul * a bad pointer, we'd rather leak.
7440516Swpaul */
7540516Swpaul
7640516Swpaul#ifndef NULL
7740516Swpaul#define	NULL 0
7840516Swpaul#endif
7940516Swpaul
8040516Swpaultypedef unsigned char U_char;	/* we don't really have signed chars */
8140516Swpaultypedef unsigned int U_int;
8240516Swpaultypedef unsigned short U_short;
8340516Swpaultypedef unsigned long U_long;
8440516Swpaul
8540516Swpaul
8640516Swpaul/*
8740516Swpaul * The overhead on a block is at least 4 bytes.  When free, this space
8840516Swpaul * contains a pointer to the next free block, and the bottom two bits must
8940516Swpaul * be zero.  When in use, the first byte is set to MAGIC, and the second
9040516Swpaul * byte is the size index.  The remaining bytes are for alignment.
9140516Swpaul * If range checking is enabled and the size of the block fits
9240516Swpaul * in two bytes, then the top two bytes hold the size of the requested block
9340516Swpaul * plus the range checking words, and the header word MINUS ONE.
9440516Swpaul */
9540516Swpaul
9640516Swpaul
9740516Swpaul#define MEMALIGN(a) (((a) + ROUNDUP) & ~ROUNDUP)
9840516Swpaul
9940516Swpaulunion overhead {
10040516Swpaul    union overhead *ov_next;	/* when free */
10140516Swpaul    struct {
10241569Swpaul	U_char  ovu_magic;	/* magic number */
10341569Swpaul	U_char  ovu_index;	/* bucket # */
10441569Swpaul#ifdef RCHECK
10550703Swpaul	U_short ovu_size;	/* actual block size */
10650703Swpaul	U_int   ovu_rmagic;	/* range magic number */
10750703Swpaul#endif
10840516Swpaul    }       ovu;
10950703Swpaul#define	ov_magic	ovu.ovu_magic
11050703Swpaul#define	ov_index	ovu.ovu_index
11150703Swpaul#define	ov_size		ovu.ovu_size
11240516Swpaul#define	ov_rmagic	ovu.ovu_rmagic
11340516Swpaul};
11440516Swpaul
11559758Speter#define	MAGIC		0xfd	/* magic # on accounting info */
11659758Speter#define RMAGIC		0x55555555	/* magic # on range info */
11751089Speter#ifdef RCHECK
11850703Swpaul#define	RSLOP		sizeof (U_int)
11950703Swpaul#else
12040516Swpaul#define	RSLOP		0
12140516Swpaul#endif
12240516Swpaul
12340516Swpaul
12440516Swpaul#define ROUNDUP	7
12540516Swpaul
12640516Swpaul/*
12740516Swpaul * nextf[i] is the pointer to the next free block of size 2^(i+3).  The
12840516Swpaul * smallest allocatable block is 8 bytes.  The overhead information
12940516Swpaul * precedes the data area returned to the user.
13040516Swpaul */
13140516Swpaul#define	NBUCKETS ((sizeof(long) << 3) - 3)
13240516Swpaulstatic union overhead *nextf[NBUCKETS] IZERO_STRUCT;
13341591Sarchie
13450477Speter/*
13540516Swpaul * nmalloc[i] is the difference between the number of mallocs and frees
13640516Swpaul * for a given block size.
13740516Swpaul */
13840516Swpaulstatic U_int nmalloc[NBUCKETS] IZERO_STRUCT;
13940516Swpaul
14040516Swpaul#ifndef lint
14140516Swpaulstatic	int	findbucket	__P((union overhead *, int));
14240516Swpaulstatic	void	morecore	__P((int));
14340516Swpaul#endif
14440516Swpaul
14567771Swpaul
14667771Swpaul#ifdef DEBUG
14741243Swpaul# define CHECK(a, str, p) \
14841243Swpaul    if (a) { \
14944238Swpaul	xprintf(str, p);	\
15044238Swpaul	xprintf(" (memtop = %lx membot = %lx)\n", memtop, membot);	\
15144238Swpaul	abort(); \
15244238Swpaul    }
15372813Swpaul#else
15472813Swpaul# define CHECK(a, str, p) \
15540516Swpaul    if (a) { \
15640516Swpaul	xprintf(str, p);	\
15740516Swpaul	xprintf(" (memtop = %lx membot = %lx)\n", memtop, membot);	\
15892739Salfred	return; \
15992739Salfred    }
16092739Salfred#endif
16140516Swpaul
16292739Salfredmemalign_t
16340516Swpaulmalloc(nbytes)
16492739Salfred    register size_t nbytes;
16592739Salfred{
16692739Salfred#ifndef lint
16792739Salfred    register union overhead *p;
16892739Salfred    register int bucket = 0;
16992739Salfred    register unsigned shiftr;
17092739Salfred
17192739Salfred    /*
17292739Salfred     * Convert amount of memory requested into closest block size stored in
17392739Salfred     * hash buckets which satisfies request.  Account for space used per block
17492739Salfred     * for accounting.
17592739Salfred     */
17692739Salfred#ifdef SUNOS4
17792739Salfred    /*
17840516Swpaul     * SunOS localtime() overwrites the 9th byte on an 8 byte malloc()....
17992739Salfred     * so we get one more...
18092739Salfred     * From Michael Schroeder: This is not true. It depends on the
18192739Salfred     * timezone string. In Europe it can overwrite the 13th byte on a
18292739Salfred     * 12 byte malloc.
18392739Salfred     * So we punt and we always allocate an extra byte.
18492739Salfred     */
18592739Salfred    nbytes++;
18640516Swpaul#endif
18792739Salfred
18892739Salfred    nbytes = MEMALIGN(MEMALIGN(sizeof(union overhead)) + nbytes + RSLOP);
18992739Salfred    shiftr = (nbytes - 1) >> 2;
19040516Swpaul
19192739Salfred    /* apart from this loop, this is O(1) */
19292739Salfred    while ((shiftr >>= 1) != 0)
19392739Salfred	bucket++;
19492739Salfred    /*
19540516Swpaul     * If nothing in hash bucket right now, request more memory from the
19692739Salfred     * system.
19792739Salfred     */
19881713Swpaul    if (nextf[bucket] == NULL)
19950703Swpaul	morecore(bucket);
20050703Swpaul    if ((p = (union overhead *) nextf[bucket]) == NULL) {
20150703Swpaul	child++;
20250703Swpaul#ifndef DEBUG
20350703Swpaul	stderror(ERR_NOMEM);
20450703Swpaul#else
20550703Swpaul	showall(NULL, NULL);
20650703Swpaul	xprintf(CGETS(19, 1, "nbytes=%d: Out of memory\n"), nbytes);
20750703Swpaul	abort();
20850703Swpaul#endif
20950703Swpaul	/* fool lint */
21050703Swpaul	return ((memalign_t) 0);
21150703Swpaul    }
21286822Siwasaki    /* remove from linked list */
21386822Siwasaki    nextf[bucket] = nextf[bucket]->ov_next;
21450703Swpaul    p->ov_magic = MAGIC;
21550703Swpaul    p->ov_index = bucket;
21650703Swpaul    nmalloc[bucket]++;
21750703Swpaul#ifdef RCHECK
21850703Swpaul    /*
21950703Swpaul     * Record allocated size of block and bound space with magic numbers.
22050703Swpaul     */
22150703Swpaul    p->ov_size = (p->ov_index <= 13) ? nbytes - 1 : 0;
22250703Swpaul    p->ov_rmagic = RMAGIC;
22350703Swpaul    *((U_int *) (((caddr_t) p) + nbytes - RSLOP)) = RMAGIC;
22450703Swpaul#endif
22550703Swpaul    return ((memalign_t) (((caddr_t) p) + MEMALIGN(sizeof(union overhead))));
22650703Swpaul#else
22750703Swpaul    if (nbytes)
22850703Swpaul	return ((memalign_t) 0);
22951455Swpaul    else
23050703Swpaul	return ((memalign_t) 0);
23150703Swpaul#endif /* !lint */
23250703Swpaul}
23350703Swpaul
23450703Swpaul#ifndef lint
23550703Swpaul/*
23651533Swpaul * Allocate more memory to the indicated bucket.
23767931Swpaul */
23851473Swpaulstatic void
23950703Swpaulmorecore(bucket)
24040516Swpaul    register int bucket;
24140516Swpaul{
24240516Swpaul    register union overhead *op;
24340516Swpaul    register int rnu;		/* 2^rnu bytes will be requested */
24440516Swpaul    register int nblks;		/* become nblks blocks of the desired size */
24540516Swpaul    register int siz;
24640516Swpaul
24740516Swpaul    if (nextf[bucket])
24881713Swpaul	return;
24981713Swpaul    /*
25081713Swpaul     * Insure memory is allocated on a page boundary.  Should make getpageize
25181713Swpaul     * call?
25281713Swpaul     */
25381713Swpaul    op = (union overhead *) sbrk(0);
25481713Swpaul    memtop = (char *) op;
25581713Swpaul    if (membot == NULL)
25681713Swpaul	membot = memtop;
25781713Swpaul    if ((long) op & 0x3ff) {
25881713Swpaul	memtop = (char *) sbrk((int) (1024 - ((long) op & 0x3ff)));
25981713Swpaul	memtop += (long) (1024 - ((long) op & 0x3ff));
26081713Swpaul    }
26181713Swpaul
26281713Swpaul    /* take 2k unless the block is bigger than that */
26381713Swpaul    rnu = (bucket <= 8) ? 11 : bucket + 3;
26481713Swpaul    nblks = 1 << (rnu - (bucket + 3));	/* how many blocks to get */
26581713Swpaul    memtop = (char *) sbrk(1 << rnu);	/* PWP */
26681713Swpaul    op = (union overhead *) memtop;
26781713Swpaul    /* no more room! */
26881713Swpaul    if ((long) op == -1)
26981713Swpaul	return;
27081713Swpaul    memtop += (long) (1 << rnu);
27181713Swpaul    /*
27281713Swpaul     * Round up to minimum allocation size boundary and deduct from block count
27381713Swpaul     * to reflect.
27481713Swpaul     */
27581713Swpaul    if (((U_long) op) & ROUNDUP) {
27640516Swpaul	op = (union overhead *) (((U_long) op + (ROUNDUP + 1)) & ~ROUNDUP);
27740516Swpaul	nblks--;
27840516Swpaul    }
27940516Swpaul    /*
28040516Swpaul     * Add new memory allocated to that on free list for this hash bucket.
28141656Swpaul     */
28240516Swpaul    nextf[bucket] = op;
28340516Swpaul    siz = 1 << (bucket + 3);
28440516Swpaul    while (--nblks > 0) {
28567931Swpaul	op->ov_next = (union overhead *) (((caddr_t) op) + siz);
28640516Swpaul	op = (union overhead *) (((caddr_t) op) + siz);
28740516Swpaul    }
28855170Sbillf    op->ov_next = NULL;
28940516Swpaul}
29040516Swpaul
29140516Swpaul#endif
29240516Swpaul
29340516Swpaulvoid
29440516Swpaulfree(cp)
29540516Swpaul    ptr_t   cp;
29640516Swpaul{
29740516Swpaul#ifndef lint
29840516Swpaul    register int size;
29940516Swpaul    register union overhead *op;
30040516Swpaul
30140516Swpaul    /*
30240516Swpaul     * the don't free flag is there so that we avoid os bugs in routines
30340516Swpaul     * that free invalid pointers!
30440516Swpaul     */
30540516Swpaul    if (cp == NULL || dont_free)
30640516Swpaul	return;
30740516Swpaul    CHECK(!memtop || !membot,
30840516Swpaul	  CGETS(19, 2, "free(%lx) called before any allocations."), cp);
30940516Swpaul    CHECK(cp > (ptr_t) memtop,
31040516Swpaul	  CGETS(19, 3, "free(%lx) above top of memory."), cp);
31141656Swpaul    CHECK(cp < (ptr_t) membot,
31240516Swpaul	  CGETS(19, 4, "free(%lx) below bottom of memory."), cp);
31340516Swpaul    op = (union overhead *) (((caddr_t) cp) - MEMALIGN(sizeof(union overhead)));
31440516Swpaul    CHECK(op->ov_magic != MAGIC,
31540516Swpaul	  CGETS(19, 5, "free(%lx) bad block."), cp);
31640516Swpaul
31740516Swpaul#ifdef RCHECK
31840516Swpaul    if (op->ov_index <= 13)
31940516Swpaul	CHECK(*(U_int *) ((caddr_t) op + op->ov_size + 1 - RSLOP) != RMAGIC,
32040516Swpaul	      CGETS(19, 6, "free(%lx) bad range check."), cp);
32140516Swpaul#endif
32240516Swpaul    CHECK(op->ov_index >= NBUCKETS,
32340516Swpaul	  CGETS(19, 7, "free(%lx) bad block index."), cp);
32440516Swpaul    size = op->ov_index;
32540516Swpaul    op->ov_next = nextf[size];
32640516Swpaul    nextf[size] = op;
32740516Swpaul
32840516Swpaul    nmalloc[size]--;
32940516Swpaul
33040516Swpaul#else
33140516Swpaul    if (cp == NULL)
33240516Swpaul	return;
33340516Swpaul#endif
33440516Swpaul}
33540516Swpaul
33640516Swpaulmemalign_t
33740516Swpaulcalloc(i, j)
33840516Swpaul    size_t  i, j;
33940516Swpaul{
34040516Swpaul#ifndef lint
34140516Swpaul    register char *cp, *scp;
34240516Swpaul
34340516Swpaul    i *= j;
34440516Swpaul    scp = cp = (char *) xmalloc((size_t) i);
34540516Swpaul    if (i != 0)
34640516Swpaul	do
34740516Swpaul	    *cp++ = 0;
34840516Swpaul	while (--i);
34940516Swpaul
35040516Swpaul    return ((memalign_t) scp);
35140516Swpaul#else
35240516Swpaul    if (i && j)
35340516Swpaul	return ((memalign_t) 0);
35440516Swpaul    else
35540516Swpaul	return ((memalign_t) 0);
35640516Swpaul#endif
35740516Swpaul}
35840516Swpaul
35940516Swpaul/*
36040516Swpaul * When a program attempts "storage compaction" as mentioned in the
36140516Swpaul * old malloc man page, it realloc's an already freed block.  Usually
36240516Swpaul * this is the last block it freed; occasionally it might be farther
36340516Swpaul * back.  We have to search all the free lists for the block in order
36440516Swpaul * to determine its bucket: 1st we make one pass thru the lists
36540516Swpaul * checking only the first block in each; if that fails we search
36640516Swpaul * ``realloc_srchlen'' blocks in each list for a match (the variable
36740516Swpaul * is extern so the caller can modify it).  If that fails we just copy
36840516Swpaul * however many bytes was given to realloc() and hope it's not huge.
36940516Swpaul */
37040516Swpaul#ifndef lint
37140516Swpaul/* 4 should be plenty, -1 =>'s whole list */
37240516Swpaulstatic int     realloc_srchlen = 4;
37340516Swpaul#endif /* lint */
37440516Swpaul
37540516Swpaulmemalign_t
37640516Swpaulrealloc(cp, nbytes)
37740516Swpaul    ptr_t   cp;
37840516Swpaul    size_t  nbytes;
37940516Swpaul{
38040516Swpaul#ifndef lint
38140516Swpaul    register U_int onb;
38240516Swpaul    union overhead *op;
38340516Swpaul    ptr_t res;
38440516Swpaul    register int i;
38540516Swpaul    int     was_alloced = 0;
38640516Swpaul
38740516Swpaul    if (cp == NULL)
38840516Swpaul	return (malloc(nbytes));
38940516Swpaul    op = (union overhead *) (((caddr_t) cp) - MEMALIGN(sizeof(union overhead)));
39040516Swpaul    if (op->ov_magic == MAGIC) {
39140516Swpaul	was_alloced++;
39240516Swpaul	i = op->ov_index;
39340516Swpaul    }
39440516Swpaul    else
39540516Swpaul	/*
39640516Swpaul	 * Already free, doing "compaction".
39740516Swpaul	 *
39840516Swpaul	 * Search for the old block of memory on the free list.  First, check the
39940516Swpaul	 * most common case (last element free'd), then (this failing) the last
40040516Swpaul	 * ``realloc_srchlen'' items free'd. If all lookups fail, then assume
40140516Swpaul	 * the size of the memory block being realloc'd is the smallest
40240516Swpaul	 * possible.
40340516Swpaul	 */
40440516Swpaul	if ((i = findbucket(op, 1)) < 0 &&
40540516Swpaul	    (i = findbucket(op, realloc_srchlen)) < 0)
40640516Swpaul	    i = 0;
40740516Swpaul
40840516Swpaul    onb = MEMALIGN(nbytes + MEMALIGN(sizeof(union overhead)) + RSLOP);
40940516Swpaul
41040516Swpaul    /* avoid the copy if same size block */
41140516Swpaul    if (was_alloced && (onb <= (U_int) (1 << (i + 3))) &&
41240516Swpaul	(onb > (U_int) (1 << (i + 2)))) {
41340516Swpaul#ifdef RCHECK
41440516Swpaul	/* JMR: formerly this wasn't updated ! */
41540516Swpaul	nbytes = MEMALIGN(MEMALIGN(sizeof(union overhead))+nbytes+RSLOP);
41640516Swpaul	*((U_int *) (((caddr_t) op) + nbytes - RSLOP)) = RMAGIC;
41740516Swpaul	op->ov_rmagic = RMAGIC;
41840516Swpaul	op->ov_size = (op->ov_index <= 13) ? nbytes - 1 : 0;
41940516Swpaul#endif
42040516Swpaul	return ((memalign_t) cp);
42140516Swpaul    }
42240516Swpaul    if ((res = malloc(nbytes)) == NULL)
42340516Swpaul	return ((memalign_t) NULL);
42440516Swpaul    if (cp != res) {		/* common optimization */
42540516Swpaul	/*
42640516Swpaul	 * christos: this used to copy nbytes! It should copy the
42740516Swpaul	 * smaller of the old and new size
42840516Swpaul	 */
42940516Swpaul	onb = (1 << (i + 3)) - MEMALIGN(sizeof(union overhead)) - RSLOP;
43040516Swpaul	(void) memmove((ptr_t) res, (ptr_t) cp,
43140516Swpaul		       (size_t) (onb < nbytes ? onb : nbytes));
43240516Swpaul    }
43340516Swpaul    if (was_alloced)
43440516Swpaul	free(cp);
43540516Swpaul    return ((memalign_t) res);
43640516Swpaul#else
43740516Swpaul    if (cp && nbytes)
43840516Swpaul	return ((memalign_t) 0);
43940516Swpaul    else
44067087Swpaul	return ((memalign_t) 0);
44140516Swpaul#endif /* !lint */
44267087Swpaul}
44340516Swpaul
44440516Swpaul
44540516Swpaul
44640516Swpaul#ifndef lint
44740516Swpaul/*
44840516Swpaul * Search ``srchlen'' elements of each free list for a block whose
44940516Swpaul * header starts at ``freep''.  If srchlen is -1 search the whole list.
45040516Swpaul * Return bucket number, or -1 if not found.
45140516Swpaul */
45240516Swpaulstatic int
45340516Swpaulfindbucket(freep, srchlen)
45440516Swpaul    union overhead *freep;
45540516Swpaul    int     srchlen;
45640516Swpaul{
45740516Swpaul    register union overhead *p;
45840516Swpaul    register int i, j;
45940516Swpaul
46040516Swpaul    for (i = 0; i < NBUCKETS; i++) {
46140516Swpaul	j = 0;
46240516Swpaul	for (p = nextf[i]; p && j != srchlen; p = p->ov_next) {
46340516Swpaul	    if (p == freep)
46440516Swpaul		return (i);
46540516Swpaul	    j++;
46640516Swpaul	}
46740516Swpaul    }
46840516Swpaul    return (-1);
46940516Swpaul}
47040516Swpaul
47140516Swpaul#endif
47240516Swpaul
47340516Swpaul
47440516Swpaul#else				/* SYSMALLOC */
47540516Swpaul
47640516Swpaul/**
47740516Swpaul ** ``Protected versions'' of malloc, realloc, calloc, and free
47840516Swpaul **
47940516Swpaul ** On many systems:
48040516Swpaul **
48140516Swpaul ** 1. malloc(0) is bad
48240516Swpaul ** 2. free(0) is bad
48340516Swpaul ** 3. realloc(0, n) is bad
48440516Swpaul ** 4. realloc(n, 0) is bad
48540516Swpaul **
48640516Swpaul ** Also we call our error routine if we run out of memory.
48740516Swpaul **/
48840516Swpaulmemalign_t
48940516Swpaulsmalloc(n)
49040516Swpaul    size_t  n;
49140516Swpaul{
49240516Swpaul    ptr_t   ptr;
49340516Swpaul
49440516Swpaul    n = n ? n : 1;
49540516Swpaul
49640516Swpaul#ifndef NO_SBRK
49740516Swpaul    if (membot == NULL)
49840516Swpaul	membot = (char*) sbrk(0);
49940516Swpaul#endif /* !NO_SBRK */
50040516Swpaul
50140516Swpaul    if ((ptr = malloc(n)) == (ptr_t) 0) {
50240516Swpaul	child++;
50340516Swpaul	stderror(ERR_NOMEM);
50440516Swpaul    }
50540516Swpaul#ifdef NO_SBRK
50640516Swpaul    if (memtop < ((char *) ptr) + n)
50740516Swpaul	memtop = ((char *) ptr) + n;
50840516Swpaul    if (membot == NULL)
50940516Swpaul	membot = (char*) ptr;
51040516Swpaul#endif /* NO_SBRK */
51140516Swpaul    return ((memalign_t) ptr);
51240516Swpaul}
51340516Swpaul
51440516Swpaulmemalign_t
51540516Swpaulsrealloc(p, n)
51640516Swpaul    ptr_t   p;
51740516Swpaul    size_t  n;
51867087Swpaul{
51940516Swpaul    ptr_t   ptr;
52040516Swpaul
52140516Swpaul    n = n ? n : 1;
52240516Swpaul
52340516Swpaul#ifndef NO_SBRK
52440516Swpaul    if (membot == NULL)
52540516Swpaul	membot = (char*) sbrk(0);
52640516Swpaul#endif /* NO_SBRK */
52740516Swpaul
52840516Swpaul    if ((ptr = (p ? realloc(p, n) : malloc(n))) == (ptr_t) 0) {
52940516Swpaul	child++;
53040516Swpaul	stderror(ERR_NOMEM);
53140516Swpaul    }
53240516Swpaul#ifdef NO_SBRK
53367087Swpaul    if (memtop < ((char *) ptr) + n)
53440516Swpaul	memtop = ((char *) ptr) + n;
53540516Swpaul    if (membot == NULL)
53640516Swpaul	membot = (char*) ptr;
53740516Swpaul#endif /* NO_SBRK */
53840516Swpaul    return ((memalign_t) ptr);
53940516Swpaul}
54040516Swpaul
54140516Swpaulmemalign_t
54240516Swpaulscalloc(s, n)
54340516Swpaul    size_t  s, n;
54440516Swpaul{
54540516Swpaul    char   *sptr;
54640516Swpaul    ptr_t   ptr;
54740516Swpaul
54840516Swpaul    n *= s;
54940516Swpaul    n = n ? n : 1;
55040516Swpaul
55140516Swpaul#ifndef NO_SBRK
55240516Swpaul    if (membot == NULL)
55340516Swpaul	membot = (char*) sbrk(0);
55440516Swpaul#endif /* NO_SBRK */
55540516Swpaul
55640516Swpaul    if ((ptr = malloc(n)) == (ptr_t) 0) {
55740516Swpaul	child++;
55840516Swpaul	stderror(ERR_NOMEM);
55940516Swpaul    }
56040516Swpaul
56140516Swpaul    sptr = (char *) ptr;
56240516Swpaul    if (n != 0)
56340516Swpaul	do
56440516Swpaul	    *sptr++ = 0;
56540516Swpaul	while (--n);
56640516Swpaul
56740516Swpaul#ifdef NO_SBRK
56867087Swpaul    if (memtop < ((char *) ptr) + n)
56940516Swpaul	memtop = ((char *) ptr) + n;
57040516Swpaul    if (membot == NULL)
57140516Swpaul	membot = (char*) ptr;
57240516Swpaul#endif /* NO_SBRK */
57350703Swpaul
57450703Swpaul    return ((memalign_t) ptr);
57550703Swpaul}
57650703Swpaul
57740516Swpaulvoid
57840516Swpaulsfree(p)
57940516Swpaul    ptr_t   p;
58040516Swpaul{
58140516Swpaul    if (p && !dont_free)
58250703Swpaul	free(p);
58367087Swpaul}
58450703Swpaul
58540516Swpaul#endif /* SYSMALLOC */
58650703Swpaul
58767087Swpaul/*
58867087Swpaul * mstats - print out statistics about malloc
58950703Swpaul *
59067087Swpaul * Prints two lines of numbers, one showing the length of the free list
59140516Swpaul * for each size category, the second showing the number of mallocs -
59250703Swpaul * frees for each size category.
59340516Swpaul */
59440516Swpaul/*ARGSUSED*/
59550703Swpaulvoid
59640516Swpaulshowall(v, c)
59740516Swpaul    Char **v;
59850703Swpaul    struct command *c;
59940516Swpaul{
60040516Swpaul#ifndef SYSMALLOC
60150703Swpaul    register int i, j;
60250703Swpaul    register union overhead *p;
60350703Swpaul    int     totfree = 0, totused = 0;
60450703Swpaul
60540516Swpaul    xprintf(CGETS(19, 8, "%s current memory allocation:\nfree:\t"), progname);
60640516Swpaul    for (i = 0; i < NBUCKETS; i++) {
60750703Swpaul	for (j = 0, p = nextf[i]; p; p = p->ov_next, j++)
60850703Swpaul	    continue;
60967087Swpaul	xprintf(" %4d", j);
61050703Swpaul	totfree += j * (1 << (i + 3));
61150703Swpaul    }
61240516Swpaul    xprintf(CGETS(19, 9, "\nused:\t"));
61340516Swpaul    for (i = 0; i < NBUCKETS; i++) {
61467087Swpaul	xprintf(" %4u", nmalloc[i]);
61540516Swpaul	totused += nmalloc[i] * (1 << (i + 3));
61640516Swpaul    }
61740516Swpaul    xprintf(CGETS(19, 10, "\n\tTotal in use: %d, total free: %d\n"),
61867087Swpaul	    totused, totfree);
61940516Swpaul    xprintf(CGETS(19, 11,
62040516Swpaul	    "\tAllocated memory from 0x%lx to 0x%lx.  Real top at 0x%lx\n"),
62140516Swpaul	    (unsigned long) membot, (unsigned long) memtop,
62240516Swpaul	    (unsigned long) sbrk(0));
62340516Swpaul#else
62450703Swpaul#ifndef NO_SBRK
62540516Swpaul    memtop = (char *) sbrk(0);
62640516Swpaul#endif /* !NO_SBRK */
62767087Swpaul    xprintf(CGETS(19, 12, "Allocated memory from 0x%lx to 0x%lx (%ld).\n"),
62840516Swpaul	    (unsigned long) membot, (unsigned long) memtop,
62940516Swpaul	    (unsigned long) (memtop - membot));
63040516Swpaul#endif /* SYSMALLOC */
63140516Swpaul    USE(c);
63250703Swpaul    USE(v);
63350703Swpaul}
63450703Swpaul