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