tc.alloc.c revision 69408
169408Sache/* $Header: /src/pub/tcsh/tc.alloc.c,v 3.35 2000/11/11 23:03:38 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. 2559243Sobrien * 3. All advertising materials mentioning features or use of this software 2659243Sobrien * must display the following acknowledgement: 2759243Sobrien * This product includes software developed by the University of 2859243Sobrien * California, Berkeley and its contributors. 2959243Sobrien * 4. Neither the name of the University nor the names of its contributors 3059243Sobrien * may be used to endorse or promote products derived from this software 3159243Sobrien * without specific prior written permission. 3259243Sobrien * 3359243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 3459243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 3559243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 3659243Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 3759243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3859243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3959243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 4059243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 4159243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 4259243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 4359243Sobrien * SUCH DAMAGE. 4459243Sobrien */ 4559243Sobrien#include "sh.h" 4659243Sobrien 4769408SacheRCSID("$Id: tc.alloc.c,v 3.35 2000/11/11 23:03:38 christos Exp $") 4859243Sobrien 4959243Sobrienstatic char *memtop = NULL; /* PWP: top of current memory */ 5059243Sobrienstatic char *membot = NULL; /* PWP: bottom of allocatable memory */ 5159243Sobrien 5259243Sobrienint dont_free = 0; 5359243Sobrien 5459243Sobrien#if defined(_VMS_POSIX) || defined(_AMIGA_MEMORY) 5559243Sobrien# define NO_SBRK 5659243Sobrien#endif 5759243Sobrien 5869408Sache#ifdef WINNT_NATIVE 5959243Sobrien# define malloc fmalloc 6059243Sobrien# define free ffree 6159243Sobrien# define calloc fcalloc 6259243Sobrien# define realloc frealloc 6369408Sache#endif /* WINNT_NATIVE */ 6459243Sobrien 6559243Sobrien#ifndef SYSMALLOC 6659243Sobrien 6759243Sobrien#undef RCHECK 6859243Sobrien#undef DEBUG 6959243Sobrien 7059243Sobrien#ifdef SX 7159243Sobrienextern void* sbrk(); 7259243Sobrien#endif 7359243Sobrien/* 7459243Sobrien * Lots of os routines are busted and try to free invalid pointers. 7559243Sobrien * Although our free routine is smart enough and it will pick bad 7659243Sobrien * pointers most of the time, in cases where we know we are going to get 7759243Sobrien * a bad pointer, we'd rather leak. 7859243Sobrien */ 7959243Sobrien 8059243Sobrien#ifndef NULL 8159243Sobrien#define NULL 0 8259243Sobrien#endif 8359243Sobrien 8459243Sobrientypedef unsigned char U_char; /* we don't really have signed chars */ 8559243Sobrientypedef unsigned int U_int; 8659243Sobrientypedef unsigned short U_short; 8759243Sobrientypedef unsigned long U_long; 8859243Sobrien 8959243Sobrien 9059243Sobrien/* 9159243Sobrien * The overhead on a block is at least 4 bytes. When free, this space 9259243Sobrien * contains a pointer to the next free block, and the bottom two bits must 9359243Sobrien * be zero. When in use, the first byte is set to MAGIC, and the second 9459243Sobrien * byte is the size index. The remaining bytes are for alignment. 9559243Sobrien * If range checking is enabled and the size of the block fits 9659243Sobrien * in two bytes, then the top two bytes hold the size of the requested block 9759243Sobrien * plus the range checking words, and the header word MINUS ONE. 9859243Sobrien */ 9959243Sobrien 10059243Sobrien 10159243Sobrien#define MEMALIGN(a) (((a) + ROUNDUP) & ~ROUNDUP) 10259243Sobrien 10359243Sobrienunion overhead { 10459243Sobrien union overhead *ov_next; /* when free */ 10559243Sobrien struct { 10659243Sobrien U_char ovu_magic; /* magic number */ 10759243Sobrien U_char ovu_index; /* bucket # */ 10859243Sobrien#ifdef RCHECK 10959243Sobrien U_short ovu_size; /* actual block size */ 11059243Sobrien U_int ovu_rmagic; /* range magic number */ 11159243Sobrien#endif 11259243Sobrien } ovu; 11359243Sobrien#define ov_magic ovu.ovu_magic 11459243Sobrien#define ov_index ovu.ovu_index 11559243Sobrien#define ov_size ovu.ovu_size 11659243Sobrien#define ov_rmagic ovu.ovu_rmagic 11759243Sobrien}; 11859243Sobrien 11959243Sobrien#define MAGIC 0xfd /* magic # on accounting info */ 12059243Sobrien#define RMAGIC 0x55555555 /* magic # on range info */ 12159243Sobrien#ifdef RCHECK 12259243Sobrien#define RSLOP sizeof (U_int) 12359243Sobrien#else 12459243Sobrien#define RSLOP 0 12559243Sobrien#endif 12659243Sobrien 12759243Sobrien 12859243Sobrien#define ROUNDUP 7 12959243Sobrien 13059243Sobrien/* 13159243Sobrien * nextf[i] is the pointer to the next free block of size 2^(i+3). The 13259243Sobrien * smallest allocatable block is 8 bytes. The overhead information 13359243Sobrien * precedes the data area returned to the user. 13459243Sobrien */ 13559243Sobrien#define NBUCKETS ((sizeof(long) << 3) - 3) 13659243Sobrienstatic union overhead *nextf[NBUCKETS] IZERO_STRUCT; 13759243Sobrien 13859243Sobrien/* 13959243Sobrien * nmalloc[i] is the difference between the number of mallocs and frees 14059243Sobrien * for a given block size. 14159243Sobrien */ 14259243Sobrienstatic U_int nmalloc[NBUCKETS] IZERO_STRUCT; 14359243Sobrien 14459243Sobrien#ifndef lint 14559243Sobrienstatic int findbucket __P((union overhead *, int)); 14659243Sobrienstatic void morecore __P((int)); 14759243Sobrien#endif 14859243Sobrien 14959243Sobrien 15059243Sobrien#ifdef DEBUG 15159243Sobrien# define CHECK(a, str, p) \ 15259243Sobrien if (a) { \ 15359243Sobrien xprintf(str, p); \ 15459243Sobrien xprintf(" (memtop = %lx membot = %lx)\n", memtop, membot); \ 15559243Sobrien abort(); \ 15659243Sobrien } 15759243Sobrien#else 15859243Sobrien# define CHECK(a, str, p) \ 15959243Sobrien if (a) { \ 16059243Sobrien xprintf(str, p); \ 16159243Sobrien xprintf(" (memtop = %lx membot = %lx)\n", memtop, membot); \ 16259243Sobrien return; \ 16359243Sobrien } 16459243Sobrien#endif 16559243Sobrien 16659243Sobrienmemalign_t 16759243Sobrienmalloc(nbytes) 16859243Sobrien register size_t nbytes; 16959243Sobrien{ 17059243Sobrien#ifndef lint 17159243Sobrien register union overhead *p; 17259243Sobrien register int bucket = 0; 17359243Sobrien register unsigned shiftr; 17459243Sobrien 17559243Sobrien /* 17659243Sobrien * Convert amount of memory requested into closest block size stored in 17759243Sobrien * hash buckets which satisfies request. Account for space used per block 17859243Sobrien * for accounting. 17959243Sobrien */ 18059243Sobrien#ifdef SUNOS4 18159243Sobrien /* 18259243Sobrien * SunOS localtime() overwrites the 9th byte on an 8 byte malloc().... 18359243Sobrien * so we get one more... 18459243Sobrien * From Michael Schroeder: This is not true. It depends on the 18559243Sobrien * timezone string. In Europe it can overwrite the 13th byte on a 18659243Sobrien * 12 byte malloc. 18759243Sobrien * So we punt and we always allocate an extra byte. 18859243Sobrien */ 18959243Sobrien nbytes++; 19059243Sobrien#endif 19159243Sobrien 19259243Sobrien nbytes = MEMALIGN(MEMALIGN(sizeof(union overhead)) + nbytes + RSLOP); 19359243Sobrien shiftr = (nbytes - 1) >> 2; 19459243Sobrien 19559243Sobrien /* apart from this loop, this is O(1) */ 19659243Sobrien while ((shiftr >>= 1) != 0) 19759243Sobrien bucket++; 19859243Sobrien /* 19959243Sobrien * If nothing in hash bucket right now, request more memory from the 20059243Sobrien * system. 20159243Sobrien */ 20259243Sobrien if (nextf[bucket] == NULL) 20359243Sobrien morecore(bucket); 20459243Sobrien if ((p = (union overhead *) nextf[bucket]) == NULL) { 20559243Sobrien child++; 20659243Sobrien#ifndef DEBUG 20759243Sobrien stderror(ERR_NOMEM); 20859243Sobrien#else 20959243Sobrien showall(NULL, NULL); 21059243Sobrien xprintf(CGETS(19, 1, "nbytes=%d: Out of memory\n"), nbytes); 21159243Sobrien abort(); 21259243Sobrien#endif 21359243Sobrien /* fool lint */ 21459243Sobrien return ((memalign_t) 0); 21559243Sobrien } 21659243Sobrien /* remove from linked list */ 21759243Sobrien nextf[bucket] = nextf[bucket]->ov_next; 21859243Sobrien p->ov_magic = MAGIC; 21959243Sobrien p->ov_index = bucket; 22059243Sobrien nmalloc[bucket]++; 22159243Sobrien#ifdef RCHECK 22259243Sobrien /* 22359243Sobrien * Record allocated size of block and bound space with magic numbers. 22459243Sobrien */ 22559243Sobrien p->ov_size = (p->ov_index <= 13) ? nbytes - 1 : 0; 22659243Sobrien p->ov_rmagic = RMAGIC; 22759243Sobrien *((U_int *) (((caddr_t) p) + nbytes - RSLOP)) = RMAGIC; 22859243Sobrien#endif 22959243Sobrien return ((memalign_t) (((caddr_t) p) + MEMALIGN(sizeof(union overhead)))); 23059243Sobrien#else 23159243Sobrien if (nbytes) 23259243Sobrien return ((memalign_t) 0); 23359243Sobrien else 23459243Sobrien return ((memalign_t) 0); 23559243Sobrien#endif /* !lint */ 23659243Sobrien} 23759243Sobrien 23859243Sobrien#ifndef lint 23959243Sobrien/* 24059243Sobrien * Allocate more memory to the indicated bucket. 24159243Sobrien */ 24259243Sobrienstatic void 24359243Sobrienmorecore(bucket) 24459243Sobrien register int bucket; 24559243Sobrien{ 24659243Sobrien register union overhead *op; 24759243Sobrien register int rnu; /* 2^rnu bytes will be requested */ 24859243Sobrien register int nblks; /* become nblks blocks of the desired size */ 24959243Sobrien register int siz; 25059243Sobrien 25159243Sobrien if (nextf[bucket]) 25259243Sobrien return; 25359243Sobrien /* 25459243Sobrien * Insure memory is allocated on a page boundary. Should make getpageize 25559243Sobrien * call? 25659243Sobrien */ 25759243Sobrien op = (union overhead *) sbrk(0); 25859243Sobrien memtop = (char *) op; 25959243Sobrien if (membot == NULL) 26059243Sobrien membot = memtop; 26159243Sobrien if ((long) op & 0x3ff) { 26259243Sobrien memtop = (char *) sbrk((int) (1024 - ((long) op & 0x3ff))); 26359243Sobrien memtop += (long) (1024 - ((long) op & 0x3ff)); 26459243Sobrien } 26559243Sobrien 26659243Sobrien /* take 2k unless the block is bigger than that */ 26759243Sobrien rnu = (bucket <= 8) ? 11 : bucket + 3; 26859243Sobrien nblks = 1 << (rnu - (bucket + 3)); /* how many blocks to get */ 26959243Sobrien memtop = (char *) sbrk(1 << rnu); /* PWP */ 27059243Sobrien op = (union overhead *) memtop; 27159243Sobrien /* no more room! */ 27259243Sobrien if ((long) op == -1) 27359243Sobrien return; 27459243Sobrien memtop += (long) (1 << rnu); 27559243Sobrien /* 27659243Sobrien * Round up to minimum allocation size boundary and deduct from block count 27759243Sobrien * to reflect. 27859243Sobrien */ 27959243Sobrien if (((U_long) op) & ROUNDUP) { 28059243Sobrien op = (union overhead *) (((U_long) op + (ROUNDUP + 1)) & ~ROUNDUP); 28159243Sobrien nblks--; 28259243Sobrien } 28359243Sobrien /* 28459243Sobrien * Add new memory allocated to that on free list for this hash bucket. 28559243Sobrien */ 28659243Sobrien nextf[bucket] = op; 28759243Sobrien siz = 1 << (bucket + 3); 28859243Sobrien while (--nblks > 0) { 28959243Sobrien op->ov_next = (union overhead *) (((caddr_t) op) + siz); 29059243Sobrien op = (union overhead *) (((caddr_t) op) + siz); 29159243Sobrien } 29259243Sobrien op->ov_next = NULL; 29359243Sobrien} 29459243Sobrien 29559243Sobrien#endif 29659243Sobrien 29759243Sobrienvoid 29859243Sobrienfree(cp) 29959243Sobrien ptr_t cp; 30059243Sobrien{ 30159243Sobrien#ifndef lint 30259243Sobrien register int size; 30359243Sobrien register union overhead *op; 30459243Sobrien 30559243Sobrien /* 30659243Sobrien * the don't free flag is there so that we avoid os bugs in routines 30759243Sobrien * that free invalid pointers! 30859243Sobrien */ 30959243Sobrien if (cp == NULL || dont_free) 31059243Sobrien return; 31159243Sobrien CHECK(!memtop || !membot, 31259243Sobrien CGETS(19, 2, "free(%lx) called before any allocations."), cp); 31359243Sobrien CHECK(cp > (ptr_t) memtop, 31459243Sobrien CGETS(19, 3, "free(%lx) above top of memory."), cp); 31559243Sobrien CHECK(cp < (ptr_t) membot, 31659243Sobrien CGETS(19, 4, "free(%lx) below bottom of memory."), cp); 31759243Sobrien op = (union overhead *) (((caddr_t) cp) - MEMALIGN(sizeof(union overhead))); 31859243Sobrien CHECK(op->ov_magic != MAGIC, 31959243Sobrien CGETS(19, 5, "free(%lx) bad block."), cp); 32059243Sobrien 32159243Sobrien#ifdef RCHECK 32259243Sobrien if (op->ov_index <= 13) 32359243Sobrien CHECK(*(U_int *) ((caddr_t) op + op->ov_size + 1 - RSLOP) != RMAGIC, 32459243Sobrien CGETS(19, 6, "free(%lx) bad range check."), cp); 32559243Sobrien#endif 32659243Sobrien CHECK(op->ov_index >= NBUCKETS, 32759243Sobrien CGETS(19, 7, "free(%lx) bad block index."), cp); 32859243Sobrien size = op->ov_index; 32959243Sobrien op->ov_next = nextf[size]; 33059243Sobrien nextf[size] = op; 33159243Sobrien 33259243Sobrien nmalloc[size]--; 33359243Sobrien 33459243Sobrien#else 33559243Sobrien if (cp == NULL) 33659243Sobrien return; 33759243Sobrien#endif 33859243Sobrien} 33959243Sobrien 34059243Sobrienmemalign_t 34159243Sobriencalloc(i, j) 34259243Sobrien size_t i, j; 34359243Sobrien{ 34459243Sobrien#ifndef lint 34559243Sobrien register char *cp, *scp; 34659243Sobrien 34759243Sobrien i *= j; 34859243Sobrien scp = cp = (char *) xmalloc((size_t) i); 34959243Sobrien if (i != 0) 35059243Sobrien do 35159243Sobrien *cp++ = 0; 35259243Sobrien while (--i); 35359243Sobrien 35459243Sobrien return ((memalign_t) scp); 35559243Sobrien#else 35659243Sobrien if (i && j) 35759243Sobrien return ((memalign_t) 0); 35859243Sobrien else 35959243Sobrien return ((memalign_t) 0); 36059243Sobrien#endif 36159243Sobrien} 36259243Sobrien 36359243Sobrien/* 36459243Sobrien * When a program attempts "storage compaction" as mentioned in the 36559243Sobrien * old malloc man page, it realloc's an already freed block. Usually 36659243Sobrien * this is the last block it freed; occasionally it might be farther 36759243Sobrien * back. We have to search all the free lists for the block in order 36859243Sobrien * to determine its bucket: 1st we make one pass thru the lists 36959243Sobrien * checking only the first block in each; if that fails we search 37059243Sobrien * ``realloc_srchlen'' blocks in each list for a match (the variable 37159243Sobrien * is extern so the caller can modify it). If that fails we just copy 37259243Sobrien * however many bytes was given to realloc() and hope it's not huge. 37359243Sobrien */ 37459243Sobrien#ifndef lint 37559243Sobrien/* 4 should be plenty, -1 =>'s whole list */ 37659243Sobrienstatic int realloc_srchlen = 4; 37759243Sobrien#endif /* lint */ 37859243Sobrien 37959243Sobrienmemalign_t 38059243Sobrienrealloc(cp, nbytes) 38159243Sobrien ptr_t cp; 38259243Sobrien size_t nbytes; 38359243Sobrien{ 38459243Sobrien#ifndef lint 38559243Sobrien register U_int onb; 38659243Sobrien union overhead *op; 38759243Sobrien ptr_t res; 38859243Sobrien register int i; 38959243Sobrien int was_alloced = 0; 39059243Sobrien 39159243Sobrien if (cp == NULL) 39259243Sobrien return (malloc(nbytes)); 39359243Sobrien op = (union overhead *) (((caddr_t) cp) - MEMALIGN(sizeof(union overhead))); 39459243Sobrien if (op->ov_magic == MAGIC) { 39559243Sobrien was_alloced++; 39659243Sobrien i = op->ov_index; 39759243Sobrien } 39859243Sobrien else 39959243Sobrien /* 40059243Sobrien * Already free, doing "compaction". 40159243Sobrien * 40259243Sobrien * Search for the old block of memory on the free list. First, check the 40359243Sobrien * most common case (last element free'd), then (this failing) the last 40459243Sobrien * ``realloc_srchlen'' items free'd. If all lookups fail, then assume 40559243Sobrien * the size of the memory block being realloc'd is the smallest 40659243Sobrien * possible. 40759243Sobrien */ 40859243Sobrien if ((i = findbucket(op, 1)) < 0 && 40959243Sobrien (i = findbucket(op, realloc_srchlen)) < 0) 41059243Sobrien i = 0; 41159243Sobrien 41259243Sobrien onb = MEMALIGN(nbytes + MEMALIGN(sizeof(union overhead)) + RSLOP); 41359243Sobrien 41459243Sobrien /* avoid the copy if same size block */ 41559243Sobrien if (was_alloced && (onb <= (U_int) (1 << (i + 3))) && 41659243Sobrien (onb > (U_int) (1 << (i + 2)))) { 41759243Sobrien#ifdef RCHECK 41859243Sobrien /* JMR: formerly this wasn't updated ! */ 41959243Sobrien nbytes = MEMALIGN(MEMALIGN(sizeof(union overhead))+nbytes+RSLOP); 42059243Sobrien *((U_int *) (((caddr_t) op) + nbytes - RSLOP)) = RMAGIC; 42159243Sobrien op->ov_rmagic = RMAGIC; 42259243Sobrien op->ov_size = (op->ov_index <= 13) ? nbytes - 1 : 0; 42359243Sobrien#endif 42459243Sobrien return ((memalign_t) cp); 42559243Sobrien } 42659243Sobrien if ((res = malloc(nbytes)) == NULL) 42759243Sobrien return ((memalign_t) NULL); 42859243Sobrien if (cp != res) { /* common optimization */ 42959243Sobrien /* 43059243Sobrien * christos: this used to copy nbytes! It should copy the 43159243Sobrien * smaller of the old and new size 43259243Sobrien */ 43359243Sobrien onb = (1 << (i + 3)) - MEMALIGN(sizeof(union overhead)) - RSLOP; 43459243Sobrien (void) memmove((ptr_t) res, (ptr_t) cp, 43559243Sobrien (size_t) (onb < nbytes ? onb : nbytes)); 43659243Sobrien } 43759243Sobrien if (was_alloced) 43859243Sobrien free(cp); 43959243Sobrien return ((memalign_t) res); 44059243Sobrien#else 44159243Sobrien if (cp && nbytes) 44259243Sobrien return ((memalign_t) 0); 44359243Sobrien else 44459243Sobrien return ((memalign_t) 0); 44559243Sobrien#endif /* !lint */ 44659243Sobrien} 44759243Sobrien 44859243Sobrien 44959243Sobrien 45059243Sobrien#ifndef lint 45159243Sobrien/* 45259243Sobrien * Search ``srchlen'' elements of each free list for a block whose 45359243Sobrien * header starts at ``freep''. If srchlen is -1 search the whole list. 45459243Sobrien * Return bucket number, or -1 if not found. 45559243Sobrien */ 45659243Sobrienstatic int 45759243Sobrienfindbucket(freep, srchlen) 45859243Sobrien union overhead *freep; 45959243Sobrien int srchlen; 46059243Sobrien{ 46159243Sobrien register union overhead *p; 46259243Sobrien register int i, j; 46359243Sobrien 46459243Sobrien for (i = 0; i < NBUCKETS; i++) { 46559243Sobrien j = 0; 46659243Sobrien for (p = nextf[i]; p && j != srchlen; p = p->ov_next) { 46759243Sobrien if (p == freep) 46859243Sobrien return (i); 46959243Sobrien j++; 47059243Sobrien } 47159243Sobrien } 47259243Sobrien return (-1); 47359243Sobrien} 47459243Sobrien 47559243Sobrien#endif 47659243Sobrien 47759243Sobrien 47859243Sobrien#else /* SYSMALLOC */ 47959243Sobrien 48059243Sobrien/** 48159243Sobrien ** ``Protected versions'' of malloc, realloc, calloc, and free 48259243Sobrien ** 48359243Sobrien ** On many systems: 48459243Sobrien ** 48559243Sobrien ** 1. malloc(0) is bad 48659243Sobrien ** 2. free(0) is bad 48759243Sobrien ** 3. realloc(0, n) is bad 48859243Sobrien ** 4. realloc(n, 0) is bad 48959243Sobrien ** 49059243Sobrien ** Also we call our error routine if we run out of memory. 49159243Sobrien **/ 49259243Sobrienmemalign_t 49359243Sobriensmalloc(n) 49459243Sobrien size_t n; 49559243Sobrien{ 49659243Sobrien ptr_t ptr; 49759243Sobrien 49859243Sobrien n = n ? n : 1; 49959243Sobrien 50059243Sobrien#ifndef NO_SBRK 50159243Sobrien if (membot == NULL) 50259243Sobrien membot = (char*) sbrk(0); 50359243Sobrien#endif /* !NO_SBRK */ 50459243Sobrien 50559243Sobrien if ((ptr = malloc(n)) == (ptr_t) 0) { 50659243Sobrien child++; 50759243Sobrien stderror(ERR_NOMEM); 50859243Sobrien } 50959243Sobrien#ifdef NO_SBRK 51059243Sobrien if (memtop < ((char *) ptr) + n) 51159243Sobrien memtop = ((char *) ptr) + n; 51259243Sobrien if (membot == NULL) 51359243Sobrien membot = (char*) ptr; 51459243Sobrien#endif /* NO_SBRK */ 51559243Sobrien return ((memalign_t) ptr); 51659243Sobrien} 51759243Sobrien 51859243Sobrienmemalign_t 51959243Sobriensrealloc(p, n) 52059243Sobrien ptr_t p; 52159243Sobrien size_t n; 52259243Sobrien{ 52359243Sobrien ptr_t ptr; 52459243Sobrien 52559243Sobrien n = n ? n : 1; 52659243Sobrien 52759243Sobrien#ifndef NO_SBRK 52859243Sobrien if (membot == NULL) 52959243Sobrien membot = (char*) sbrk(0); 53059243Sobrien#endif /* NO_SBRK */ 53159243Sobrien 53259243Sobrien if ((ptr = (p ? realloc(p, n) : malloc(n))) == (ptr_t) 0) { 53359243Sobrien child++; 53459243Sobrien stderror(ERR_NOMEM); 53559243Sobrien } 53659243Sobrien#ifdef NO_SBRK 53759243Sobrien if (memtop < ((char *) ptr) + n) 53859243Sobrien memtop = ((char *) ptr) + n; 53959243Sobrien if (membot == NULL) 54059243Sobrien membot = (char*) ptr; 54159243Sobrien#endif /* NO_SBRK */ 54259243Sobrien return ((memalign_t) ptr); 54359243Sobrien} 54459243Sobrien 54559243Sobrienmemalign_t 54659243Sobrienscalloc(s, n) 54759243Sobrien size_t s, n; 54859243Sobrien{ 54959243Sobrien char *sptr; 55059243Sobrien ptr_t ptr; 55159243Sobrien 55259243Sobrien n *= s; 55359243Sobrien n = n ? n : 1; 55459243Sobrien 55559243Sobrien#ifndef NO_SBRK 55659243Sobrien if (membot == NULL) 55759243Sobrien membot = (char*) sbrk(0); 55859243Sobrien#endif /* NO_SBRK */ 55959243Sobrien 56059243Sobrien if ((ptr = malloc(n)) == (ptr_t) 0) { 56159243Sobrien child++; 56259243Sobrien stderror(ERR_NOMEM); 56359243Sobrien } 56459243Sobrien 56559243Sobrien sptr = (char *) ptr; 56659243Sobrien if (n != 0) 56759243Sobrien do 56859243Sobrien *sptr++ = 0; 56959243Sobrien while (--n); 57059243Sobrien 57159243Sobrien#ifdef NO_SBRK 57259243Sobrien if (memtop < ((char *) ptr) + n) 57359243Sobrien memtop = ((char *) ptr) + n; 57459243Sobrien if (membot == NULL) 57559243Sobrien membot = (char*) ptr; 57659243Sobrien#endif /* NO_SBRK */ 57759243Sobrien 57859243Sobrien return ((memalign_t) ptr); 57959243Sobrien} 58059243Sobrien 58159243Sobrienvoid 58259243Sobriensfree(p) 58359243Sobrien ptr_t p; 58459243Sobrien{ 58559243Sobrien if (p && !dont_free) 58659243Sobrien free(p); 58759243Sobrien} 58859243Sobrien 58959243Sobrien#endif /* SYSMALLOC */ 59059243Sobrien 59159243Sobrien/* 59259243Sobrien * mstats - print out statistics about malloc 59359243Sobrien * 59459243Sobrien * Prints two lines of numbers, one showing the length of the free list 59559243Sobrien * for each size category, the second showing the number of mallocs - 59659243Sobrien * frees for each size category. 59759243Sobrien */ 59859243Sobrien/*ARGSUSED*/ 59959243Sobrienvoid 60059243Sobrienshowall(v, c) 60159243Sobrien Char **v; 60259243Sobrien struct command *c; 60359243Sobrien{ 60459243Sobrien#ifndef SYSMALLOC 60559243Sobrien register int i, j; 60659243Sobrien register union overhead *p; 60759243Sobrien int totfree = 0, totused = 0; 60859243Sobrien 60959243Sobrien xprintf(CGETS(19, 8, "%s current memory allocation:\nfree:\t"), progname); 61059243Sobrien for (i = 0; i < NBUCKETS; i++) { 61159243Sobrien for (j = 0, p = nextf[i]; p; p = p->ov_next, j++) 61259243Sobrien continue; 61359243Sobrien xprintf(" %4d", j); 61459243Sobrien totfree += j * (1 << (i + 3)); 61559243Sobrien } 61659243Sobrien xprintf(CGETS(19, 9, "\nused:\t")); 61759243Sobrien for (i = 0; i < NBUCKETS; i++) { 61859243Sobrien xprintf(" %4u", nmalloc[i]); 61959243Sobrien totused += nmalloc[i] * (1 << (i + 3)); 62059243Sobrien } 62159243Sobrien xprintf(CGETS(19, 10, "\n\tTotal in use: %d, total free: %d\n"), 62259243Sobrien totused, totfree); 62359243Sobrien xprintf(CGETS(19, 11, 62459243Sobrien "\tAllocated memory from 0x%lx to 0x%lx. Real top at 0x%lx\n"), 62559243Sobrien (unsigned long) membot, (unsigned long) memtop, 62659243Sobrien (unsigned long) sbrk(0)); 62759243Sobrien#else 62859243Sobrien#ifndef NO_SBRK 62959243Sobrien memtop = (char *) sbrk(0); 63059243Sobrien#endif /* !NO_SBRK */ 63159243Sobrien xprintf(CGETS(19, 12, "Allocated memory from 0x%lx to 0x%lx (%ld).\n"), 63259243Sobrien (unsigned long) membot, (unsigned long) memtop, 63359243Sobrien (unsigned long) (memtop - membot)); 63459243Sobrien#endif /* SYSMALLOC */ 63559243Sobrien USE(c); 63659243Sobrien USE(v); 63759243Sobrien} 638