diff options
author | Jari Aalto <jari.aalto@cante.net> | 1998-04-17 19:52:44 +0000 |
---|---|---|
committer | Jari Aalto <jari.aalto@cante.net> | 2009-09-12 16:46:51 +0000 |
commit | cce855bc5b117cb7ae70064131120687bc69fac0 (patch) | |
tree | 39c7a4ec8f6d22ef03df74f2684e6a04fef10399 /lib/malloc | |
parent | e8ce775db824de329b81293b4e5d8fbd65624528 (diff) | |
download | bash-cce855bc5b117cb7ae70064131120687bc69fac0.tar.gz |
Imported from ../bash-2.02.tar.gz.
Diffstat (limited to 'lib/malloc')
-rw-r--r-- | lib/malloc/getpagesize.h | 7 | ||||
-rw-r--r-- | lib/malloc/gmalloc.c | 1213 | ||||
-rw-r--r-- | lib/malloc/malloc.c | 957 | ||||
-rw-r--r-- | lib/malloc/ogmalloc.c | 1579 | ||||
-rw-r--r-- | lib/malloc/omalloc.c | 759 |
5 files changed, 3450 insertions, 1065 deletions
diff --git a/lib/malloc/getpagesize.h b/lib/malloc/getpagesize.h index 0b75b898..6085a5c5 100644 --- a/lib/malloc/getpagesize.h +++ b/lib/malloc/getpagesize.h @@ -16,6 +16,9 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif # include <unistd.h> # if defined (_SC_PAGESIZE) # define getpagesize() sysconf(_SC_PAGESIZE) @@ -27,7 +30,9 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #endif #if !defined (getpagesize) -# include <sys/param.h> +# ifndef _MINIX +# include <sys/param.h> +# endif # if defined (PAGESIZE) # define getpagesize() PAGESIZE # else /* !PAGESIZE */ diff --git a/lib/malloc/gmalloc.c b/lib/malloc/gmalloc.c index 8690b126..dd24146d 100644 --- a/lib/malloc/gmalloc.c +++ b/lib/malloc/gmalloc.c @@ -1,7 +1,3 @@ -/* DO NOT EDIT THIS FILE -- it is automagically generated. -*- C -*- */ - -#define _MALLOC_INTERNAL - /* The malloc headers and source files from the C library follow here. */ /* Declarations for `malloc' and friends. @@ -20,118 +16,173 @@ Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If -not, write to the Free Software Foundation, Inc., 675 Mass Ave, -Cambridge, MA 02139, USA. +ot, write to the Free Software Foundation, Inc., 59 Temple Place - +Suite 330, Boston, MA 02111-1307, USA. The author may be reached (Email) at the address mike@ai.mit.edu, or (US mail) as Mike Haertel c/o Free Software Foundation. */ -#ifndef _MALLOC_H - -#define _MALLOC_H 1 +/* XXX NOTES: + 1. Augment the mstats struct so we can see how many blocks for fragments + and how many blocks for large requests were allocated. +*/ -#ifdef _MALLOC_INTERNAL +/* CHANGES: + 1. Reorganized the source for my benefit. + 2. Integrated the range-checking code by default. + 3. free(0) no longer dumps core. + 4. Extended the statistics. + 5. Fixed a couple of places where the stats were not kept correctly. +*/ #ifdef HAVE_CONFIG_H #include <config.h> #endif -#if defined(_LIBC) || defined(STDC_HEADERS) || defined(USG) -#include <string.h> +#if defined (HAVE_STRING_H) +# include <string.h> #else -#ifndef memset -#define memset(s, zero, n) bzero ((s), (n)) -#endif -#ifndef memcpy -#define memcpy(d, s, n) bcopy ((s), (d), (n)) -#endif +# include <strings.h> #endif -#if defined (__GNU_LIBRARY__) || (defined (__STDC__) && __STDC__) -#include <limits.h> -#else -#ifndef CHAR_BIT -#define CHAR_BIT 8 +#if defined (HAVE_LIMITS_H) +# include <limits.h> #endif + +#if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif +# include <unistd.h> #endif -#ifdef HAVE_UNISTD_H -#include <unistd.h> +#if defined (HAVE_STDDEF_H) +# include <stddef.h> #endif +#include <errno.h> -#endif /* _MALLOC_INTERNAL. */ +#if defined (RCHECK) && !defined (botch) +# include <stdio.h> +# define STDIO_H_INCLUDED +#endif +#include "stdc.h" -#ifdef __cplusplus -extern "C" -{ +#ifndef errno +extern int errno; #endif -#if defined (__cplusplus) || (defined (__STDC__) && __STDC__) -#undef __P -#define __P(args) args -#undef __ptr_t -#define __ptr_t void * -#else /* Not C++ or ANSI C. */ -#undef __P -#define __P(args) () -#undef const -#define const -#undef __ptr_t -#define __ptr_t char * -#endif /* C++ or ANSI C. */ - -#if defined (__STDC__) && __STDC__ -#include <stddef.h> -#define __malloc_size_t size_t -#define __malloc_ptrdiff_t ptrdiff_t +/* Need an autoconf test for this. */ +#if __STDC__ +# undef genptr_t +# define genptr_t void * #else -#define __malloc_size_t unsigned int -#define __malloc_ptrdiff_t int +# undef genptr_t +# define genptr_t char * +#endif /* !__STDC__ */ + +#if !defined (HAVE_MEMSET) +# define memset(s, zero, n) bzero ((s), (n)) +#endif +#if !defined (HAVE_MEMCPY) +# define memcpy(d, s, n) bcopy ((s), (d), (n)) +#endif + +/* Cope with systems lacking `memmove'. */ +#if !defined (HAVE_MEMMOVE) && !defined (memmove) +static void malloc_safe_bcopy __P ((genptr_t, genptr_t, size_t)); +# define memmove(to, from, size) malloc_safe_bcopy ((from), (to), (size)) #endif #ifndef NULL #define NULL 0 #endif +#ifndef min +#define min(A, B) ((A) < (B) ? (A) : (B)) +#endif + +/* Return values for `mprobe': these are the kinds of inconsistencies that + `mcheck' enables detection of. */ +enum mcheck_status + { + MCHECK_DISABLED = -1, /* Consistency checking is not turned on. */ + MCHECK_OK, /* Block is fine. */ + MCHECK_FREE, /* Block freed twice. */ + MCHECK_HEAD, /* Memory before the block was clobbered. */ + MCHECK_TAIL /* Memory after the block was clobbered. */ + }; + +/* Statistics available to the user. */ +struct mstats + { + size_t bytes_total; /* Total size of the heap. */ + size_t chunks_used; /* Chunks allocated by the user. */ + size_t bytes_used; /* Byte total of user-allocated chunks. */ + size_t chunks_free; /* Chunks in the free list. */ + size_t bytes_free; /* Byte total of chunks in the free list. */ + int nmalloc; /* Total number of calls to malloc. */ + int nfree; /* Total number of calls to free. */ + int nrealloc; /* Total number of calls to realloc. */ + int nsbrk; /* Total number of calls to sbrk. */ + size_t tsbrk; /* Total number of bytes allocated via sbrk. */ + int negsbrk; /* Total number of calls to sbrk with a negative arg */ + size_t tnegsbrk; /* Total number of bytes returned to the kernel. */ + }; + +#ifdef RCHECK +/* Arbitrary magical numbers. */ +#define MAGICWORD 0xfedabeeb +#define MAGICFREE 0xd8675309 +#define MAGICBYTE ((char) 0xd7) +#define MALLOCFLOOD ((char) 0x93) +#define FREEFLOOD ((char) 0x95) +struct hdr + { + size_t size; /* Exact size requested by user. */ + u_int32_t magic; /* Magic number to check header integrity. */ + }; +#endif /* RCHECK */ + +/* Functions exported by this library. */ /* Allocate SIZE bytes of memory. */ -extern __ptr_t malloc __P ((__malloc_size_t __size)); +extern genptr_t malloc __P ((size_t __size)); + /* Re-allocate the previously allocated block - in __ptr_t, making the new block SIZE bytes long. */ -extern __ptr_t realloc __P ((__ptr_t __ptr, __malloc_size_t __size)); + in genptr_t, making the new block SIZE bytes long. */ +extern genptr_t realloc __P ((genptr_t __ptr, size_t __size)); + /* Allocate NMEMB elements of SIZE bytes each, all initialized to 0. */ -extern __ptr_t calloc __P ((__malloc_size_t __nmemb, __malloc_size_t __size)); +extern genptr_t calloc __P ((size_t __nmemb, size_t __size)); + /* Free a block allocated by `malloc', `realloc' or `calloc'. */ -extern void free __P ((__ptr_t __ptr)); +extern void free __P ((genptr_t __ptr)); /* Allocate SIZE bytes allocated to ALIGNMENT bytes. */ -#if ! (defined (_MALLOC_INTERNAL) && __DJGPP__ - 0 == 1) /* Avoid conflict. */ -extern __ptr_t memalign __P ((__malloc_size_t __alignment, - __malloc_size_t __size)); -#endif +extern genptr_t memalign __P ((size_t __alignment, size_t __size)); -/* Allocate SIZE bytes on a page boundary. */ -#if ! (defined (_MALLOC_INTERNAL) && defined (emacs)) /* Avoid conflict. */ -extern __ptr_t valloc __P ((__malloc_size_t __size)); -#endif +/* Pick up the current statistics. */ +extern struct mstats mstats __P ((void)); +#ifdef RCHECK +extern enum mcheck_status mprobe __P((genptr_t ptr)); +#endif -#ifdef _MALLOC_INTERNAL +/* End of exported functions. */ /* The allocator divides the heap into blocks of fixed size; large requests receive one or more whole blocks, and small requests receive a fragment of a block. Fragment sizes are powers of two, and all fragments of a block are the same size. When all the fragments in a block have been freed, the block itself is freed. */ -#define INT_BIT (CHAR_BIT * sizeof(int)) -#define BLOCKLOG (INT_BIT > 16 ? 12 : 9) -#define BLOCKSIZE (1 << BLOCKLOG) +#define BLOCKLOG 12 +#define BLOCKSIZE 4096 /* 1 << BLOCKLOG */ #define BLOCKIFY(SIZE) (((SIZE) + BLOCKSIZE - 1) / BLOCKSIZE) /* Determine the amount of memory spanned by the initial heap table (not an absolute limit). */ -#define HEAP (INT_BIT > 16 ? 4194304 : 65536) +#define HEAP 4194304 /* 1 << 22 */ /* Number of contiguous free blocks allowed to build up at the end of memory before they will be returned to the system. */ @@ -150,40 +201,43 @@ typedef union { struct { - __malloc_size_t nfree; /* Free frags in a fragmented block. */ - __malloc_size_t first; /* First free fragment of the block. */ + size_t nfree; /* Free frags in a fragmented block. */ + size_t first; /* First free fragment of the block. */ } frag; /* For a large object, in its first block, this has the number of blocks in the object. In the other blocks, this has a negative number which says how far back the first block is. */ - __malloc_ptrdiff_t size; + ptrdiff_t size; } info; } busy; - /* Heap information for a free block - (that may be the first of a free cluster). */ + /* Heap information for a free block (that may be the first of a + free cluster). */ struct { - __malloc_size_t size; /* Size (in blocks) of a free cluster. */ - __malloc_size_t next; /* Index of next free cluster. */ - __malloc_size_t prev; /* Index of previous free cluster. */ + size_t size; /* Size (in blocks) of a free cluster. */ + size_t next; /* Index of next free cluster. */ + size_t prev; /* Index of previous free cluster. */ } free; } malloc_info; /* Pointer to first block of the heap. */ -extern char *_heapbase; +static char *_heapbase; /* Table indexed by block number giving per-block information. */ -extern malloc_info *_heapinfo; +static malloc_info *_heapinfo; /* Address to block number and vice versa. */ #define BLOCK(A) (((char *) (A) - _heapbase) / BLOCKSIZE + 1) -#define ADDRESS(B) ((__ptr_t) (((B) - 1) * BLOCKSIZE + _heapbase)) +#define ADDRESS(B) ((genptr_t) (((B) - 1) * BLOCKSIZE + _heapbase)) + +/* Number of info entries. */ +static size_t heapsize; /* Current search index for the heap table. */ -extern __malloc_size_t _heapindex; +static size_t _heapindex; /* Limit of valid info table indices. */ -extern __malloc_size_t _heaplimit; +static size_t _heaplimit; /* Doubly linked lists of free fragments. */ struct list @@ -193,270 +247,127 @@ struct list }; /* Free list headers for each fragment size. */ -extern struct list _fraghead[]; +static struct list _fraghead[BLOCKLOG]; -/* List of blocks allocated with `memalign' (or `valloc'). */ +/* List of blocks allocated with `memalign'. */ struct alignlist { struct alignlist *next; - __ptr_t aligned; /* The address that memaligned returned. */ - __ptr_t exact; /* The address that malloc returned. */ + genptr_t aligned; /* The address that memaligned returned. */ + genptr_t exact; /* The address that malloc returned. */ }; -extern struct alignlist *_aligned_blocks; -/* Instrumentation. */ -extern __malloc_size_t _chunks_used; -extern __malloc_size_t _bytes_used; -extern __malloc_size_t _chunks_free; -extern __malloc_size_t _bytes_free; +/* List of blocks allocated by memalign. */ +static struct alignlist *_aligned_blocks = NULL; /* Internal versions of `malloc', `realloc', and `free' - used when these functions need to call each other. - They are the same but don't call the hooks. */ -extern __ptr_t _malloc_internal __P ((__malloc_size_t __size)); -extern __ptr_t _realloc_internal __P ((__ptr_t __ptr, __malloc_size_t __size)); -extern void _free_internal __P ((__ptr_t __ptr)); - -#endif /* _MALLOC_INTERNAL. */ + used when these functions need to call each other. */ +static genptr_t imalloc __P ((size_t __size)); +static genptr_t irealloc __P ((genptr_t __ptr, size_t __size)); +static void ifree __P ((genptr_t __ptr)); /* Given an address in the middle of a malloc'd object, return the address of the beginning of the object. */ -extern __ptr_t malloc_find_object_address __P ((__ptr_t __ptr)); +static genptr_t malloc_find_object_address __P ((genptr_t __ptr)); /* Underlying allocation function; successive calls should return contiguous pieces of memory. */ -extern __ptr_t (*__morecore) __P ((__malloc_ptrdiff_t __size)); - -/* Default value of `__morecore'. */ -extern __ptr_t __default_morecore __P ((__malloc_ptrdiff_t __size)); - -/* If not NULL, this function is called after each time - `__morecore' is called to increase the data size. */ -extern void (*__after_morecore_hook) __P ((void)); +static genptr_t default_morecore __P ((ptrdiff_t __size)); /* Number of extra blocks to get each time we ask for more core. - This reduces the frequency of calling `(*__morecore)'. */ -extern __malloc_size_t __malloc_extra_blocks; + This reduces the frequency of calling `default_morecore'. */ +static size_t malloc_extra_blocks; /* Nonzero if `malloc' has been called and done its initialization. */ -extern int __malloc_initialized; +static int malloc_initialized; /* Function called to initialize malloc data structures. */ -extern int __malloc_initialize __P ((void)); +static int malloc_initialize __P ((void)); -/* Hooks for debugging versions. */ -extern void (*__malloc_initialize_hook) __P ((void)); -extern void (*__free_hook) __P ((__ptr_t __ptr)); -extern __ptr_t (*__malloc_hook) __P ((__malloc_size_t __size)); -extern __ptr_t (*__realloc_hook) __P ((__ptr_t __ptr, __malloc_size_t __size)); -extern __ptr_t (*__memalign_hook) __P ((__malloc_size_t __size, - __malloc_size_t __alignment)); - -/* Return values for `mprobe': these are the kinds of inconsistencies that - `mcheck' enables detection of. */ -enum mcheck_status - { - MCHECK_DISABLED = -1, /* Consistency checking is not turned on. */ - MCHECK_OK, /* Block is fine. */ - MCHECK_FREE, /* Block freed twice. */ - MCHECK_HEAD, /* Memory before the block was clobbered. */ - MCHECK_TAIL /* Memory after the block was clobbered. */ - }; - -/* Activate a standard collection of debugging hooks. This must be called - before `malloc' is ever called. ABORTFUNC is called with an error code - (see enum above) when an inconsistency is detected. If ABORTFUNC is - null, the standard function prints on stderr and then calls `abort'. */ -extern int mcheck __P ((void (*__abortfunc) __P ((enum mcheck_status)))); - -/* Check for aberrations in a particular malloc'd block. You must have - called `mcheck' already. These are the same checks that `mcheck' does - when you free or reallocate a block. */ -extern enum mcheck_status mprobe __P ((__ptr_t __ptr)); - -/* Activate a standard collection of tracing hooks. */ -extern void mtrace __P ((void)); -extern void muntrace __P ((void)); - -/* Statistics available to the user. */ -struct mstats - { - __malloc_size_t bytes_total; /* Total size of the heap. */ - __malloc_size_t chunks_used; /* Chunks allocated by the user. */ - __malloc_size_t bytes_used; /* Byte total of user-allocated chunks. */ - __malloc_size_t chunks_free; /* Chunks in the free list. */ - __malloc_size_t bytes_free; /* Byte total of chunks in the free list. */ - }; - -/* Pick up the current statistics. */ -extern struct mstats mstats __P ((void)); - -/* Call WARNFUN with a warning message when memory usage is high. */ -extern void memory_warnings __P ((__ptr_t __start, - void (*__warnfun) __P ((const char *)))); - - -/* Relocating allocator. */ - -/* Allocate SIZE bytes, and store the address in *HANDLEPTR. */ -extern __ptr_t r_alloc __P ((__ptr_t *__handleptr, __malloc_size_t __size)); - -/* Free the storage allocated in HANDLEPTR. */ -extern void r_alloc_free __P ((__ptr_t *__handleptr)); - -/* Adjust the block at HANDLEPTR to be SIZE bytes long. */ -extern __ptr_t r_re_alloc __P ((__ptr_t *__handleptr, __malloc_size_t __size)); - - -#ifdef __cplusplus -} +#ifdef RCHECK +static void zmemset __P((genptr_t, int, size_t)); +static enum mcheck_status checkhdr __P((const struct hdr *)); +static void mabort __P((enum mcheck_status)); #endif -#endif /* malloc.h */ -/* Memory allocator `malloc'. - Copyright 1990, 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. - Written May 1989 by Mike Haertel. - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Library General Public License as -published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Library General Public License for more details. - -You should have received a copy of the GNU Library General Public -License along with this library; see the file COPYING.LIB. If -not, write to the Free Software Foundation, Inc., 675 Mass Ave, -Cambridge, MA 02139, USA. - - The author may be reached (Email) at the address mike@ai.mit.edu, - or (US mail) as Mike Haertel c/o Free Software Foundation. */ - -#ifndef _MALLOC_INTERNAL -#define _MALLOC_INTERNAL -#include <malloc.h> -#endif -#include <errno.h> - -/* How to really get more memory. */ -__ptr_t (*__morecore) __P ((ptrdiff_t __size)) = __default_morecore; - -/* Debugging hook for `malloc'. */ -__ptr_t (*__malloc_hook) __P ((__malloc_size_t __size)); - -/* Pointer to the base of the first block. */ -char *_heapbase; - -/* Block information table. Allocated with align/__free (not malloc/free). */ -malloc_info *_heapinfo; - -/* Number of info entries. */ -static __malloc_size_t heapsize; - -/* Search index in the info table. */ -__malloc_size_t _heapindex; - -/* Limit of valid info table indices. */ -__malloc_size_t _heaplimit; - -/* Free lists for each fragment size. */ -struct list _fraghead[BLOCKLOG]; - /* Instrumentation. */ -__malloc_size_t _chunks_used; -__malloc_size_t _bytes_used; -__malloc_size_t _chunks_free; -__malloc_size_t _bytes_free; - -/* Are you experienced? */ -int __malloc_initialized; - -__malloc_size_t __malloc_extra_blocks; - -void (*__malloc_initialize_hook) __P ((void)); -void (*__after_morecore_hook) __P ((void)); - +static size_t chunks_used; +static size_t bytes_used; +static size_t chunks_free; +static size_t bytes_free; +static int nmalloc, nfree, nrealloc; +static int nsbrk; +static size_t tsbrk; +static int negsbrk; +static size_t tnegsbrk; /* Aligned allocation. */ -static __ptr_t align __P ((__malloc_size_t)); -static __ptr_t +static genptr_t align (size) - __malloc_size_t size; + size_t size; { - __ptr_t result; + genptr_t result; unsigned long int adj; - result = (*__morecore) (size); + result = default_morecore (size); adj = (unsigned long int) ((unsigned long int) ((char *) result - (char *) NULL)) % BLOCKSIZE; if (adj != 0) { - __ptr_t new; + genptr_t new; adj = BLOCKSIZE - adj; - new = (*__morecore) (adj); + new = default_morecore (adj); result = (char *) result + adj; } - if (__after_morecore_hook) - (*__after_morecore_hook) (); - return result; } /* Get SIZE bytes, if we can get them starting at END. Return the address of the space we got. If we cannot get space at END, fail and return -1. */ -static __ptr_t get_contiguous_space __P ((__malloc_ptrdiff_t, __ptr_t)); -static __ptr_t +static genptr_t get_contiguous_space (size, position) - __malloc_ptrdiff_t size; - __ptr_t position; + ptrdiff_t size; + genptr_t position; { - __ptr_t before; - __ptr_t after; + genptr_t before; + genptr_t after; - before = (*__morecore) (0); + before = default_morecore (0); /* If we can tell in advance that the break is at the wrong place, fail now. */ if (before != position) return 0; /* Allocate SIZE bytes and get the address of them. */ - after = (*__morecore) (size); + after = default_morecore (size); if (!after) return 0; /* It was not contiguous--reject it. */ if (after != position) { - (*__morecore) (- size); + default_morecore (- size); return 0; } return after; } - /* This is called when `_heapinfo' and `heapsize' have just been set to describe a new info table. Set up the table to describe itself and account for it in the statistics. */ -static void register_heapinfo __P ((void)); -#ifdef __GNUC__ -__inline__ -#endif -static void +inline static void register_heapinfo () { - __malloc_size_t block, blocks; + size_t block, blocks; block = BLOCK (_heapinfo); blocks = BLOCKIFY (heapsize * sizeof (malloc_info)); /* Account for the _heapinfo block itself in the statistics. */ - _bytes_used += blocks * BLOCKSIZE; - ++_chunks_used; + bytes_used += blocks * BLOCKSIZE; + ++chunks_used; /* Describe the heapinfo block itself in the heapinfo. */ _heapinfo[block].busy.type = 0; @@ -467,15 +378,12 @@ register_heapinfo () } /* Set everything up and remember that we have. */ -int -__malloc_initialize () +static int +malloc_initialize () { - if (__malloc_initialized) + if (malloc_initialized) return 0; - if (__malloc_initialize_hook) - (*__malloc_initialize_hook) (); - heapsize = HEAP / BLOCKSIZE; _heapinfo = (malloc_info *) align (heapsize * sizeof (malloc_info)); if (_heapinfo == NULL) @@ -489,22 +397,43 @@ __malloc_initialize () register_heapinfo (); - __malloc_initialized = 1; + malloc_initialized = 1; return 1; } +/* Allocate INCREMENT more bytes of data space, + and return the start of data space, or NULL on errors. + If INCREMENT is negative, shrink data space. */ +static genptr_t +default_morecore (increment) + ptrdiff_t increment; +{ + genptr_t result; + + nsbrk++; + tsbrk += increment; + if (increment < 0) + { + negsbrk++; + tnegsbrk += -increment; + } + result = (genptr_t) sbrk (increment); + if ((long)result == -1L) + return NULL; + return result; +} + static int morecore_recursing; /* Get neatly aligned memory, initializing or growing the heap info table as necessary. */ -static __ptr_t morecore __P ((__malloc_size_t)); -static __ptr_t +static genptr_t morecore (size) - __malloc_size_t size; + size_t size; { - __ptr_t result; + genptr_t result; malloc_info *newinfo, *oldinfo; - __malloc_size_t newsize; + size_t newsize; if (morecore_recursing) /* Avoid recursion. The caller will know how to handle a null return. */ @@ -515,7 +444,7 @@ morecore (size) return NULL; /* Check if we need to grow the info table. */ - if ((__malloc_size_t) BLOCK ((char *) result + size) > heapsize) + if ((size_t) BLOCK ((char *) result + size) > heapsize) { /* Calculate the new _heapinfo table size. We do not account for the added blocks in the table itself, as we hope to place them in @@ -523,8 +452,8 @@ morecore (size) existing table. */ newsize = heapsize; do - newsize *= 2; - while ((__malloc_size_t) BLOCK ((char *) result + size) > newsize); + newsize <<= 1; + while ((size_t) BLOCK ((char *) result + size) > newsize); /* We must not reuse existing core for the new info table when called from realloc in the case of growing a large block, because the @@ -540,8 +469,7 @@ morecore (size) `morecore_recursing' flag and return null. */ int save = errno; /* Don't want to clobber errno with ENOMEM. */ morecore_recursing = 1; - newinfo = (malloc_info *) _realloc_internal - (_heapinfo, newsize * sizeof (malloc_info)); + newinfo = (malloc_info *) irealloc (_heapinfo, newsize * sizeof (malloc_info)); morecore_recursing = 0; if (newinfo == NULL) errno = save; @@ -550,8 +478,7 @@ morecore (size) /* We found some space in core, and realloc has put the old table's blocks on the free list. Now zero the new part of the table and install the new table location. */ - memset (&newinfo[heapsize], 0, - (newsize - heapsize) * sizeof (malloc_info)); + memset (&newinfo[heapsize], 0, (newsize - heapsize) * sizeof (malloc_info)); _heapinfo = newinfo; heapsize = newsize; goto got_heap; @@ -566,37 +493,34 @@ morecore (size) /* Did it fail? */ if (newinfo == NULL) { - (*__morecore) (-size); + default_morecore (-size); return NULL; } /* Is it big enough to record status for its own space? If so, we win. */ - if ((__malloc_size_t) BLOCK ((char *) newinfo - + newsize * sizeof (malloc_info)) - < newsize) + if ((size_t) BLOCK ((char *) newinfo + newsize * sizeof (malloc_info)) < newsize) break; /* Must try again. First give back most of what we just got. */ - (*__morecore) (- newsize * sizeof (malloc_info)); + default_morecore (- newsize * sizeof (malloc_info)); newsize *= 2; } /* Copy the old table to the beginning of the new, and zero the rest of the new table. */ memcpy (newinfo, _heapinfo, heapsize * sizeof (malloc_info)); - memset (&newinfo[heapsize], 0, - (newsize - heapsize) * sizeof (malloc_info)); + memset (&newinfo[heapsize], 0, (newsize - heapsize) * sizeof (malloc_info)); oldinfo = _heapinfo; _heapinfo = newinfo; heapsize = newsize; register_heapinfo (); - /* Reset _heaplimit so _free_internal never decides + /* Reset _heaplimit so ifree never decides it can relocate or resize the info table. */ _heaplimit = 0; - _free_internal (oldinfo); + ifree (oldinfo); /* The new heap limit includes the new table just allocated. */ _heaplimit = BLOCK ((char *) newinfo + heapsize * sizeof (malloc_info)); @@ -609,13 +533,13 @@ morecore (size) } /* Allocate memory from the heap. */ -__ptr_t -_malloc_internal (size) - __malloc_size_t size; +static genptr_t +imalloc (size) + size_t size; { - __ptr_t result; - __malloc_size_t block, blocks, lastblocks, start; - register __malloc_size_t i; + genptr_t result; + size_t block, blocks, lastblocks, start; + register size_t i; struct list *next; /* ANSI C allows `malloc (0)' to either return NULL, or to return a @@ -625,7 +549,7 @@ _malloc_internal (size) expects `malloc (0)' to return non-NULL and breaks otherwise. Be compatible. */ -#if 0 +#if 0 if (size == 0) return NULL; #endif @@ -643,7 +567,7 @@ _malloc_internal (size) { /* Small allocation to receive a fragment of a block. Determine the logarithm to base two of the fragment size. */ - register __malloc_size_t log = 1; + register size_t log = 1; --size; while ((size /= 2) != 0) ++log; @@ -656,7 +580,7 @@ _malloc_internal (size) /* There are free fragments of this size. Pop a fragment out of the fragment list and return it. Update the block's nfree and first counters. */ - result = (__ptr_t) next; + result = (genptr_t) next; next->prev->next = next->next; if (next->next != NULL) next->next->prev = next->prev; @@ -667,16 +591,16 @@ _malloc_internal (size) % BLOCKSIZE) >> log; /* Update the statistics. */ - ++_chunks_used; - _bytes_used += 1 << log; - --_chunks_free; - _bytes_free -= 1 << log; + ++chunks_used; + bytes_used += 1 << log; + --chunks_free; + bytes_free -= 1 << log; } else { /* No free fragments of the desired size, so get a new block and break it into fragments, returning the first. */ - result = malloc (BLOCKSIZE); + result = imalloc (BLOCKSIZE); if (result == NULL) return NULL; @@ -686,7 +610,7 @@ _malloc_internal (size) next->prev = &_fraghead[log]; _fraghead[log].next = next; - for (i = 2; i < (__malloc_size_t) (BLOCKSIZE >> log); ++i) + for (i = 2; i < (size_t) (BLOCKSIZE >> log); ++i) { next = (struct list *) ((char *) result + (i << log)); next->next = _fraghead[log].next; @@ -701,9 +625,9 @@ _malloc_internal (size) _heapinfo[block].busy.info.frag.nfree = i - 1; _heapinfo[block].busy.info.frag.first = i - 1; - _chunks_free += (BLOCKSIZE >> log) - 1; - _bytes_free += BLOCKSIZE - (1 << log); - _bytes_used -= BLOCKSIZE - (1 << log); + chunks_free += (BLOCKSIZE >> log) - 1; + bytes_free += BLOCKSIZE - (1 << log); + bytes_used -= BLOCKSIZE - (1 << log); } } else @@ -720,7 +644,7 @@ _malloc_internal (size) if (block == start) { /* Need to get more from the system. Get a little extra. */ - __malloc_size_t wantblocks = blocks + __malloc_extra_blocks; + size_t wantblocks = blocks + malloc_extra_blocks; block = _heapinfo[0].free.prev; lastblocks = _heapinfo[block].free.size; /* Check to see if the new core will be contiguous with the @@ -737,7 +661,7 @@ _malloc_internal (size) changed, if it got combined with a freed info table. */ block = _heapinfo[0].free.prev; _heapinfo[block].free.size += (wantblocks - lastblocks); - _bytes_free += (wantblocks - lastblocks) * BLOCKSIZE; + bytes_free += (wantblocks - lastblocks) * BLOCKSIZE; _heaplimit += wantblocks - lastblocks; continue; } @@ -751,7 +675,8 @@ _malloc_internal (size) _heapinfo[block].free.next = 0; _heapinfo[0].free.prev = block; _heapinfo[_heapinfo[block].free.prev].free.next = block; - ++_chunks_free; + ++chunks_free; + bytes_free += wantblocks * BLOCKSIZE; /* Now loop to use some of that block for this allocation. */ } } @@ -781,14 +706,14 @@ _malloc_internal (size) = _heapinfo[block].free.prev; _heapinfo[_heapinfo[block].free.prev].free.next = _heapindex = _heapinfo[block].free.next; - --_chunks_free; + --chunks_free; } _heapinfo[block].busy.type = 0; _heapinfo[block].busy.info.size = blocks; - ++_chunks_used; - _bytes_used += blocks * BLOCKSIZE; - _bytes_free -= blocks * BLOCKSIZE; + ++chunks_used; + bytes_used += blocks * BLOCKSIZE; + bytes_free -= blocks * BLOCKSIZE; /* Mark all the blocks of the object just allocated except for the first with a negative number so you can find the first block by @@ -800,113 +725,55 @@ _malloc_internal (size) return result; } -__ptr_t +genptr_t malloc (size) - __malloc_size_t size; -{ - if (!__malloc_initialized && !__malloc_initialize ()) - return NULL; - - return (__malloc_hook != NULL ? *__malloc_hook : _malloc_internal) (size); -} - -#ifndef _LIBC - -/* On some ANSI C systems, some libc functions call _malloc, _free - and _realloc. Make them use the GNU functions. */ - -__ptr_t -_malloc (size) - __malloc_size_t size; + size_t size; { - return malloc (size); -} - -void -_free (ptr) - __ptr_t ptr; -{ - free (ptr); -} - -__ptr_t -_realloc (ptr, size) - __ptr_t ptr; - __malloc_size_t size; -{ - return realloc (ptr, size); -} - +#ifdef RCHECK + struct hdr *hdr; #endif -/* Free a block of memory allocated by `malloc'. - Copyright 1990, 1991, 1992, 1994, 1995 Free Software Foundation, Inc. - Written May 1989 by Mike Haertel. -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Library General Public License as -published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Library General Public License for more details. - -You should have received a copy of the GNU Library General Public -License along with this library; see the file COPYING.LIB. If -not, write to the Free Software Foundation, Inc., 675 Mass Ave, -Cambridge, MA 02139, USA. + nmalloc++; - The author may be reached (Email) at the address mike@ai.mit.edu, - or (US mail) as Mike Haertel c/o Free Software Foundation. */ - -#ifndef _MALLOC_INTERNAL -#define _MALLOC_INTERNAL -#include <malloc.h> -#endif + if (malloc_initialized == 0 && malloc_initialize () == 0) + return NULL; +#ifdef RCHECK + hdr = (struct hdr *) imalloc (sizeof (struct hdr) + size + 1); + if (hdr == NULL) + return NULL; -/* Cope with systems lacking `memmove'. */ -#ifndef memmove -#if (defined (MEMMOVE_MISSING) || \ - !defined(_LIBC) && !defined(STDC_HEADERS) && !defined(USG)) -#ifdef emacs -#undef __malloc_safe_bcopy -#define __malloc_safe_bcopy safe_bcopy -#endif -/* This function is defined in realloc.c. */ -extern void __malloc_safe_bcopy __P ((__ptr_t, __ptr_t, __malloc_size_t)); -#define memmove(to, from, size) __malloc_safe_bcopy ((from), (to), (size)) -#endif + hdr->size = size; + hdr->magic = MAGICWORD; + ((char *) &hdr[1])[size] = MAGICBYTE; + zmemset ((genptr_t) (hdr + 1), MALLOCFLOOD, size); + return (genptr_t) (hdr + 1); +#else + return (imalloc (size)); #endif +} +/* Free a block of memory allocated by `malloc'. */ -/* Debugging hook for free. */ -void (*__free_hook) __P ((__ptr_t __ptr)); - -/* List of blocks allocated by memalign. */ -struct alignlist *_aligned_blocks = NULL; - -/* Return memory to the heap. - Like `free' but don't call a __free_hook if there is one. */ -void -_free_internal (ptr) - __ptr_t ptr; +/* Return memory to the heap. */ +static void +ifree (ptr) + genptr_t ptr; { int type; - __malloc_size_t block, blocks; - register __malloc_size_t i; + size_t block, blocks; + register size_t i; struct list *prev, *next; - __ptr_t curbrk; - const __malloc_size_t lesscore_threshold - /* Threshold of free space at which we will return some to the system. */ - = FINAL_FREE_BLOCKS + 2 * __malloc_extra_blocks; - + genptr_t curbrk; + size_t lesscore_threshold; register struct alignlist *l; if (ptr == NULL) return; + /* Threshold of free space at which we will return some to the system. */ + lesscore_threshold = FINAL_FREE_BLOCKS + 2 * malloc_extra_blocks; + for (l = _aligned_blocks; l != NULL; l = l->next) if (l->aligned == ptr) { @@ -922,9 +789,9 @@ _free_internal (ptr) { case 0: /* Get as many statistics as early as we can. */ - --_chunks_used; - _bytes_used -= _heapinfo[block].busy.info.size * BLOCKSIZE; - _bytes_free += _heapinfo[block].busy.info.size * BLOCKSIZE; + --chunks_used; + bytes_used -= _heapinfo[block].busy.info.size * BLOCKSIZE; + bytes_free += _heapinfo[block].busy.info.size * BLOCKSIZE; /* Find the free cluster previous to this one in the free list. Start searching at the last block referenced; this may benefit @@ -956,7 +823,7 @@ _free_internal (ptr) _heapinfo[block].free.prev = i; _heapinfo[i].free.next = block; _heapinfo[_heapinfo[block].free.next].free.prev = block; - ++_chunks_free; + ++chunks_free; } /* Now that the block is linked in, see if we can coalesce it @@ -969,14 +836,14 @@ _free_internal (ptr) _heapinfo[block].free.next = _heapinfo[_heapinfo[block].free.next].free.next; _heapinfo[_heapinfo[block].free.next].free.prev = block; - --_chunks_free; + --chunks_free; } /* How many trailing free blocks are there now? */ blocks = _heapinfo[block].free.size; /* Where is the current end of accessible core? */ - curbrk = (*__morecore) (0); + curbrk = default_morecore (0); if (_heaplimit != 0 && curbrk == ADDRESS (_heaplimit)) { @@ -984,12 +851,12 @@ _free_internal (ptr) It's possible that moving _heapinfo will allow us to return some space to the system. */ - __malloc_size_t info_block = BLOCK (_heapinfo); - __malloc_size_t info_blocks = _heapinfo[info_block].busy.info.size; - __malloc_size_t prev_block = _heapinfo[block].free.prev; - __malloc_size_t prev_blocks = _heapinfo[prev_block].free.size; - __malloc_size_t next_block = _heapinfo[block].free.next; - __malloc_size_t next_blocks = _heapinfo[next_block].free.size; + size_t info_block = BLOCK (_heapinfo); + size_t info_blocks = _heapinfo[info_block].busy.info.size; + size_t prev_block = _heapinfo[block].free.prev; + size_t prev_blocks = _heapinfo[prev_block].free.size; + size_t next_block = _heapinfo[block].free.next; + size_t next_blocks = _heapinfo[next_block].free.size; if (/* Win if this block being freed is last in core, the info table is just before it, the previous free block is just before the @@ -1012,14 +879,14 @@ _free_internal (ptr) ) { malloc_info *newinfo; - __malloc_size_t oldlimit = _heaplimit; + size_t oldlimit = _heaplimit; /* Free the old info table, clearing _heaplimit to avoid recursion into this code. We don't want to return the table's blocks to the system before we have copied them to the new location. */ _heaplimit = 0; - _free_internal (_heapinfo); + ifree (_heapinfo); _heaplimit = oldlimit; /* Tell malloc to search from the beginning of the heap for @@ -1027,7 +894,7 @@ _free_internal (ptr) _heapindex = 0; /* Allocate new space for the info table and move its data. */ - newinfo = (malloc_info *) _malloc_internal (info_blocks + newinfo = (malloc_info *) imalloc (info_blocks * BLOCKSIZE); memmove (newinfo, _heapinfo, info_blocks * BLOCKSIZE); _heapinfo = newinfo; @@ -1043,16 +910,16 @@ _free_internal (ptr) /* Now see if we can return stuff to the system. */ if (block + blocks == _heaplimit && blocks >= lesscore_threshold) { - register __malloc_size_t bytes = blocks * BLOCKSIZE; + register size_t bytes = blocks * BLOCKSIZE; _heaplimit -= blocks; - (*__morecore) (-bytes); + default_morecore (-bytes); _heapinfo[_heapinfo[block].free.prev].free.next = _heapinfo[block].free.next; _heapinfo[_heapinfo[block].free.next].free.prev = _heapinfo[block].free.prev; block = _heapinfo[block].free.prev; - --_chunks_free; - _bytes_free -= bytes; + --chunks_free; + bytes_free -= bytes; } } @@ -1062,10 +929,10 @@ _free_internal (ptr) default: /* Do some of the statistics. */ - --_chunks_used; - _bytes_used -= 1 << type; - ++_chunks_free; - _bytes_free += 1 << type; + --chunks_used; + bytes_used -= 1 << type; + ++chunks_free; + bytes_free += 1 << type; /* Get the address of the first free fragment in this block. */ prev = (struct list *) ((char *) ADDRESS (block) + @@ -1076,7 +943,7 @@ _free_internal (ptr) /* If all fragments of this block are free, remove them from the fragment list and free the whole block. */ next = prev; - for (i = 1; i < (__malloc_size_t) (BLOCKSIZE >> type); ++i) + for (i = 1; i < (size_t) (BLOCKSIZE >> type); ++i) next = next->next; prev->prev->next = next; if (next != NULL) @@ -1085,12 +952,12 @@ _free_internal (ptr) _heapinfo[block].busy.info.size = 1; /* Keep the statistics accurate. */ - ++_chunks_used; - _bytes_used += BLOCKSIZE; - _chunks_free -= BLOCKSIZE >> type; - _bytes_free -= BLOCKSIZE; + ++chunks_used; + bytes_used += BLOCKSIZE; + chunks_free -= BLOCKSIZE >> type; + bytes_free -= BLOCKSIZE; - free (ADDRESS (block)); + ifree (ADDRESS (block)); } else if (_heapinfo[block].busy.info.frag.nfree != 0) { @@ -1128,76 +995,46 @@ _free_internal (ptr) /* Return memory to the heap. */ void free (ptr) - __ptr_t ptr; + genptr_t ptr; { - if (__free_hook != NULL) - (*__free_hook) (ptr); - else - _free_internal (ptr); -} - -/* Define the `cfree' alias for `free'. */ -#ifdef weak_alias -weak_alias (free, cfree) -#else -void -cfree (ptr) - __ptr_t ptr; -{ - free (ptr); -} +#ifdef RCHECK + struct hdr *hdr; #endif -/* Change the size of a block allocated by `malloc'. - Copyright 1990, 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. - Written May 1989 by Mike Haertel. - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Library General Public License as -published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Library General Public License for more details. -You should have received a copy of the GNU Library General Public -License along with this library; see the file COPYING.LIB. If -not, write to the Free Software Foundation, Inc., 675 Mass Ave, -Cambridge, MA 02139, USA. + nfree++; - The author may be reached (Email) at the address mike@ai.mit.edu, - or (US mail) as Mike Haertel c/o Free Software Foundation. */ + if (ptr == 0) + return; -#ifndef _MALLOC_INTERNAL -#define _MALLOC_INTERNAL -#include <malloc.h> +#ifdef RCHECK + hdr = ((struct hdr *) ptr) - 1; + checkhdr (hdr); + hdr->magic = MAGICFREE; + zmemset (ptr, FREEFLOOD, hdr->size); + ifree (hdr); +#else + ifree (ptr); #endif +} +/* Change the size of a block allocated by `malloc'. */ - -/* Cope with systems lacking `memmove'. */ -#if (defined (MEMMOVE_MISSING) || \ - !defined(_LIBC) && !defined(STDC_HEADERS) && !defined(USG)) - -#ifdef emacs -#undef __malloc_safe_bcopy -#define __malloc_safe_bcopy safe_bcopy -#else - +#ifndef HAVE_MEMMOVE /* Snarfed directly from Emacs src/dispnew.c: XXX Should use system bcopy if it handles overlap. */ /* Like bcopy except never gets confused by overlap. */ -void -__malloc_safe_bcopy (afrom, ato, size) - __ptr_t afrom; - __ptr_t ato; - __malloc_size_t size; +static void +malloc_safe_bcopy (afrom, ato, size) + genptr_t afrom; + genptr_t ato; + size_t size; { - char *from = afrom, *to = ato; + char *from, *to; + from = afrom; + to = ato; if (size <= 0 || from == to) return; @@ -1245,20 +1082,7 @@ __malloc_safe_bcopy (afrom, ato, size) } } } -#endif /* emacs */ - -#ifndef memmove -extern void __malloc_safe_bcopy __P ((__ptr_t, __ptr_t, __malloc_size_t)); -#define memmove(to, from, size) __malloc_safe_bcopy ((from), (to), (size)) -#endif - -#endif - - -#define min(A, B) ((A) < (B) ? (A) : (B)) - -/* Debugging hook for realloc. */ -__ptr_t (*__realloc_hook) __P ((__ptr_t __ptr, __malloc_size_t __size)); +#endif /* !HAVE_MEMMOVE */ /* Resize the given region to the new size, returning a pointer to the (possibly moved) region. This is optimized for speed; @@ -1266,22 +1090,22 @@ __ptr_t (*__realloc_hook) __P ((__ptr_t __ptr, __malloc_size_t __size)); achieved by unconditionally allocating and copying to a new region. This module has incestuous knowledge of the internals of both free and malloc. */ -__ptr_t -_realloc_internal (ptr, size) - __ptr_t ptr; - __malloc_size_t size; +static genptr_t +irealloc (ptr, size) + genptr_t ptr; + size_t size; { - __ptr_t result; + genptr_t result; int type; - __malloc_size_t block, blocks, oldlimit; + size_t block, blocks, oldlimit; if (size == 0) { - _free_internal (ptr); - return _malloc_internal (0); + ifree (ptr); + return imalloc (0); } else if (ptr == NULL) - return _malloc_internal (size); + return imalloc (size); block = BLOCK (ptr); @@ -1292,11 +1116,11 @@ _realloc_internal (ptr, size) /* Maybe reallocate a large block to a small fragment. */ if (size <= BLOCKSIZE / 2) { - result = _malloc_internal (size); + result = imalloc (size); if (result != NULL) { memcpy (result, ptr, size); - _free_internal (ptr); + ifree (ptr); return result; } } @@ -1314,9 +1138,9 @@ _realloc_internal (ptr, size) _heapinfo[block].busy.info.size = blocks; /* We have just created a new chunk by splitting a chunk in two. Now we will free this chunk; increment the statistics counter - so it doesn't become wrong when _free_internal decrements it. */ - ++_chunks_used; - _free_internal (ADDRESS (block + blocks)); + so it doesn't become wrong when ifree decrements it. */ + ++chunks_used; + ifree (ADDRESS (block + blocks)); result = ptr; } else if (blocks == _heapinfo[block].busy.info.size) @@ -1331,8 +1155,8 @@ _realloc_internal (ptr, size) /* Prevent free from actually returning memory to the system. */ oldlimit = _heaplimit; _heaplimit = 0; - _free_internal (ptr); - result = _malloc_internal (size); + ifree (ptr); + result = imalloc (size); if (_heaplimit == 0) _heaplimit = oldlimit; if (result == NULL) @@ -1341,13 +1165,13 @@ _realloc_internal (ptr, size) the thing we just freed. Unfortunately it might have been coalesced with its neighbors. */ if (_heapindex == block) - (void) _malloc_internal (blocks * BLOCKSIZE); + (void) imalloc (blocks * BLOCKSIZE); else { - __ptr_t previous - = _malloc_internal ((block - _heapindex) * BLOCKSIZE); - (void) _malloc_internal (blocks * BLOCKSIZE); - _free_internal (previous); + genptr_t previous; + previous = imalloc ((block - _heapindex) * BLOCKSIZE); + (void) imalloc (blocks * BLOCKSIZE); + ifree (previous); } return NULL; } @@ -1359,19 +1183,19 @@ _realloc_internal (ptr, size) default: /* Old size is a fragment; type is logarithm to base two of the fragment size. */ - if (size > (__malloc_size_t) (1 << (type - 1)) && - size <= (__malloc_size_t) (1 << type)) + if (size > (size_t) (1 << (type - 1)) && + size <= (size_t) (1 << type)) /* The new size is the same kind of fragment. */ result = ptr; else { /* The new size is different; allocate a new space, and copy the lesser of the new size and the old. */ - result = _malloc_internal (size); + result = imalloc (size); if (result == NULL) return NULL; - memcpy (result, ptr, min (size, (__malloc_size_t) 1 << type)); - _free_internal (ptr); + memcpy (result, ptr, min (size, (size_t) 1 << type)); + ifree (ptr); } break; } @@ -1379,148 +1203,75 @@ _realloc_internal (ptr, size) return result; } -__ptr_t +genptr_t realloc (ptr, size) - __ptr_t ptr; - __malloc_size_t size; + genptr_t ptr; + size_t size; { - if (!__malloc_initialized && !__malloc_initialize ()) +#ifdef RCHECK + struct hdr *hdr; + size_t osize; +#endif + + if (malloc_initialized == 0 && malloc_initialize () == 0) return NULL; - return (__realloc_hook != NULL ? *__realloc_hook : _realloc_internal) - (ptr, size); -} -/* Copyright (C) 1991, 1992, 1994 Free Software Foundation, Inc. + nrealloc++; -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Library General Public License as -published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version. +#ifdef RCHECK + hdr = ((struct hdr *) ptr) - 1; + osize = hdr->size; -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Library General Public License for more details. - -You should have received a copy of the GNU Library General Public -License along with this library; see the file COPYING.LIB. If -not, write to the Free Software Foundation, Inc., 675 Mass Ave, -Cambridge, MA 02139, USA. - - The author may be reached (Email) at the address mike@ai.mit.edu, - or (US mail) as Mike Haertel c/o Free Software Foundation. */ + checkhdr (hdr); + if (size < osize) + zmemset ((char *) ptr + size, FREEFLOOD, osize - size); + hdr = (struct hdr *) irealloc ((genptr_t) hdr, sizeof (struct hdr) + size + 1); + if (hdr == NULL) + return NULL; -#ifndef _MALLOC_INTERNAL -#define _MALLOC_INTERNAL -#include <malloc.h> + hdr->size = size; + hdr->magic = MAGICWORD; + ((char *) &hdr[1])[size] = MAGICBYTE; + if (size > osize) + zmemset ((char *) (hdr + 1) + osize, MALLOCFLOOD, size - osize); + return (genptr_t) (hdr + 1); +#else + return (irealloc (ptr, size)); #endif +} /* Allocate an array of NMEMB elements each SIZE bytes long. The entire array is initialized to zeros. */ -__ptr_t +genptr_t calloc (nmemb, size) - register __malloc_size_t nmemb; - register __malloc_size_t size; + register size_t nmemb; + register size_t size; { - register __ptr_t result = malloc (nmemb * size); + register genptr_t result; + result = malloc (nmemb * size); if (result != NULL) (void) memset (result, 0, nmemb * size); return result; } -/* Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. -This file is part of the GNU C Library. -The GNU C Library is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -The GNU C Library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with the GNU C Library; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#ifndef _MALLOC_INTERNAL -#define _MALLOC_INTERNAL -#include <malloc.h> -#endif - -#ifndef __GNU_LIBRARY__ -#define __sbrk sbrk -#endif - -#ifdef __GNU_LIBRARY__ -/* It is best not to declare this and cast its result on foreign operating - systems with potentially hostile include files. */ - -#include <stddef.h> -extern __ptr_t __sbrk __P ((ptrdiff_t increment)); -#endif - -#ifndef NULL -#define NULL 0 -#endif - -/* Allocate INCREMENT more bytes of data space, - and return the start of data space, or NULL on errors. - If INCREMENT is negative, shrink data space. */ -__ptr_t -__default_morecore (increment) - __malloc_ptrdiff_t increment; +/* Define the `cfree' alias for `free'. */ +void +cfree (ptr) + genptr_t ptr; { - __ptr_t result = (__ptr_t) __sbrk (increment); - if (result == (__ptr_t) -1) - return NULL; - return result; + free (ptr); } -/* Copyright (C) 1991, 92, 93, 94, 95, 96 Free Software Foundation, Inc. -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Library General Public License as -published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Library General Public License for more details. - -You should have received a copy of the GNU Library General Public -License along with this library; see the file COPYING.LIB. If -not, write to the Free Software Foundation, Inc., 675 Mass Ave, -Cambridge, MA 02139, USA. */ - -#ifndef _MALLOC_INTERNAL -#define _MALLOC_INTERNAL -#include <malloc.h> -#endif - -#if __DJGPP__ - 0 == 1 - -/* There is some problem with memalign in DJGPP v1 and we are supposed - to omit it. Noone told me why, they just told me to do it. */ - -#else - -__ptr_t (*__memalign_hook) __P ((size_t __size, size_t __alignment)); - -__ptr_t +genptr_t memalign (alignment, size) - __malloc_size_t alignment; - __malloc_size_t size; + size_t alignment; + size_t size; { - __ptr_t result; + genptr_t result; unsigned long int adj, lastadj; - if (__memalign_hook) - return (*__memalign_hook) (alignment, size); - /* Allocate a block with enough extra space to pad the block with up to (ALIGNMENT - 1) bytes if necessary. */ result = malloc (size + alignment - 1); @@ -1560,7 +1311,7 @@ memalign (alignment, size) break; if (l == NULL) { - l = (struct alignlist *) malloc (sizeof (struct alignlist)); + l = (struct alignlist *) imalloc (sizeof (struct alignlist)); if (l == NULL) { free (result); @@ -1576,4 +1327,160 @@ memalign (alignment, size) return result; } -#endif /* Not DJGPP v1 */ +/* On some ANSI C systems, some libc functions call _malloc, _free + and _realloc. Make them use the GNU functions. */ + +genptr_t +_malloc (size) + size_t size; +{ + return malloc (size); +} + +void +_free (ptr) + genptr_t ptr; +{ + free (ptr); +} + +genptr_t +_realloc (ptr, size) + genptr_t ptr; + size_t size; +{ + return realloc (ptr, size); +} + +struct mstats +mstats () +{ + struct mstats result; + + result.bytes_total = (char *) default_morecore (0) - _heapbase; + result.chunks_used = chunks_used; + result.bytes_used = bytes_used; + result.chunks_free = chunks_free; + result.bytes_free = bytes_free; + result.nmalloc = nmalloc; + result.nrealloc = nrealloc; + result.nfree = nfree; + result.nsbrk = nsbrk; + result.tsbrk = tsbrk; + result.negsbrk = negsbrk; + result.tnegsbrk = tnegsbrk; + + return result; +} + +#ifdef RCHECK +/* Standard debugging hooks for `malloc'. */ + +static void +zmemset (ptr, val, size) + genptr_t ptr; + int val; + size_t size; +{ + char *cp = ptr; + + while (size--) + *cp++ = val; +} + +static enum mcheck_status +checkhdr (hdr) + const struct hdr *hdr; +{ + enum mcheck_status status; + + switch (hdr->magic) + { + default: + status = MCHECK_HEAD; + break; + case MAGICFREE: + status = MCHECK_FREE; + break; + case MAGICWORD: + if (((char *) &hdr[1])[hdr->size] != MAGICBYTE) + status = MCHECK_TAIL; + else + status = MCHECK_OK; + break; + } + if (status != MCHECK_OK) + mabort (status); + return status; +} + +#ifndef botch +botch (msg) + char *msg; +{ + fprintf (stderr, "mcheck: %s\n", msg); + fflush (stderr); + abort (); +} +#endif + +static void +mabort (status) + enum mcheck_status status; +{ + const char *msg; + + switch (status) + { + case MCHECK_OK: + msg = "memory is consistent, library is buggy"; + break; + case MCHECK_HEAD: + msg = "memory clobbered before allocated block"; + break; + case MCHECK_TAIL: + msg = "memory clobbered past end of allocated block"; + break; + case MCHECK_FREE: + msg = "block freed twice"; + break; + default: + msg = "bogus mcheck_status, library is buggy"; + break; + } + + botch (msg); +} + +enum mcheck_status +mprobe (ptr) + genptr_t ptr; +{ + return checkhdr ((struct hdr *)ptr); +} + +#ifndef STDIO_H_INCLUDED +# include <stdio.h> +#endif + +void +print_malloc_stats (s) + char *s; +{ + struct mstats ms; + + ms = mstats (); + fprintf (stderr, "Memory allocation statistics: %s\n", s ? s : ""); + fprintf (stderr, "\nTotal chunks in use: %d, total chunks free: %d\n", + ms.chunks_used, ms.chunks_free); + fprintf (stderr, "Total bytes in use: %u, total bytes free: %u\n", + ms.bytes_used, ms.bytes_free); + fprintf (stderr, "Total bytes (from heapbase): %d\n", ms.bytes_total); + fprintf (stderr, "Total mallocs: %d, total frees: %d, total reallocs: %d\n", + ms.nmalloc, ms.nfree, ms.nrealloc); + fprintf (stderr, "Total sbrks: %d, total bytes via sbrk: %d\n", + ms.nsbrk, ms.tsbrk); + fprintf (stderr, "Total negative sbrks: %d, total bytes returned to kernel: %d\n", + ms.negsbrk, ms.tnegsbrk); +} +#endif /* RCHECK */ diff --git a/lib/malloc/malloc.c b/lib/malloc/malloc.c index a8b232a1..c42ca3cc 100644 --- a/lib/malloc/malloc.c +++ b/lib/malloc/malloc.c @@ -1,6 +1,6 @@ -/* dynamic memory allocation for GNU. */ +/* malloc.c - dynamic memory allocation for bash. */ -/* Copyright (C) 1985, 1987 Free Software Foundation, Inc. +/* Copyright (C) 1985, 1987, 1997 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -41,21 +41,17 @@ what you give them. Help stamp out software-hoarding! */ * Jan 85, RMS: calls malloc_warning to issue warning on nearly full. * No longer Emacs-specific; can serve as all-purpose malloc for GNU. * You should call malloc_init to reinitialize after loading dumped Emacs. - * Call malloc_stats to get info on memory stats if MSTATS turned on. + * Call malloc_stats to get info on memory stats if MALLOC_STATS turned on. * realloc knows how to return same block given, just changing its size, * if the power of 2 is correct. */ +#define MALLOC_STATS /* for the time being */ /* * nextf[i] is the pointer to the next free block of size 2^(i+3). The * smallest allocatable block is 8 bytes. The overhead information will * go in the first int of the block, and the returned pointer will point * to the second. - * -#ifdef MSTATS - * nmalloc[i] is the difference between the number of mallocs and frees - * for a given block size. -#endif */ /* Define this to have free() write 0xcf into memory as it's freed, to @@ -65,38 +61,38 @@ what you give them. Help stamp out software-hoarding! */ # define MEMSCRAMBLE #endif -#if defined (emacs) || defined (HAVE_CONFIG_H) +#if defined (HAVE_CONFIG_H) # include <config.h> -#endif /* emacs */ +#endif /* HAVE_CONFIG_H */ + +#if defined (SHELL) +# include "bashtypes.h" +#else +# include <sys/types.h> +#endif #if defined (HAVE_UNISTD_H) # include <unistd.h> #endif /* Determine which kind of system this is. */ -#if defined (SHELL) -# include "bashtypes.h" +#include <signal.h> + +#if defined (HAVE_STRING_H) +# include <string.h> #else -# include <sys/types.h> +# include <strings.h> #endif -#include <signal.h> + +#if defined (MALLOC_STATS) || !defined (botch) +# include <stdio.h> +#endif /* MALLOC_STATS || !botch */ /* Define getpagesize () if the system does not. */ #ifndef HAVE_GETPAGESIZE # include "getpagesize.h" #endif -#if defined (HAVE_RESOURCE) -# include <sys/time.h> -# include <sys/resource.h> -#endif /* HAVE_RESOURCE */ - -/* Check for the needed symbols. If they aren't present, this - system's <sys/resource.h> isn't very useful to us. */ -#if !defined (RLIMIT_DATA) -# undef HAVE_RESOURCE -#endif - #if __GNUC__ > 1 # define FASTCOPY(s, d, n) __builtin_memcpy (d, s, n) #else /* !__GNUC__ */ @@ -115,7 +111,7 @@ what you give them. Help stamp out software-hoarding! */ # define NULL 0 #endif -#define start_of_data() &etext +#define NBUCKETS 30 #define ISALLOC ((char) 0xf7) /* magic byte that implies allocation */ #define ISFREE ((char) 0x54) /* magic byte that implies free block */ @@ -124,147 +120,275 @@ what you give them. Help stamp out software-hoarding! */ memalign, with the rest of the word being the distance to the true beginning of the block. */ -extern char etext; #if !defined (SBRK_DECLARED) extern char *sbrk (); #endif /* !SBRK_DECLARED */ -/* These two are for user programs to look at, when they are interested. */ -unsigned int malloc_sbrk_used; /* amount of data space used now */ -unsigned int malloc_sbrk_unused; /* amount more we can have */ - -/* start of data space; can be changed by calling init_malloc */ -static char *data_space_start; - -static void get_lim_data (); - -#ifdef MSTATS -static int nmalloc[30]; -static int nmal, nfre; -#endif /* MSTATS */ - -/* If range checking is not turned on, all we have is a flag indicating - whether memory is allocated, an index in nextf[], and a size field; to - realloc() memory we copy either size bytes or 1<<(index+3) bytes depending - on whether the former can hold the exact size (given the value of - 'index'). If range checking is on, we always need to know how much space - is allocated, so the 'size' field is never used. */ - -struct mhead { - char mh_alloc; /* ISALLOC or ISFREE */ - char mh_index; /* index in nextf[] */ -/* Remainder are valid only when block is allocated */ - unsigned short mh_size; /* size, if < 0x10000 */ -#ifdef RCHECK - unsigned int mh_nbytes; /* number of bytes allocated */ - int mh_magic4; /* should be == MAGIC4 */ -#endif /* RCHECK */ +#ifdef MALLOC_STATS +/* + * NMALLOC[i] is the difference between the number of mallocs and frees + * for a given block size. TMALLOC[i] is the total number of mallocs for + * a given block size. NMORECORE[i] is the total number of calls to + * morecore(i). NMAL and NFRE are counts of the number of calls to malloc() + * and free(), respectively. NREALLOC is the total number of calls to + * realloc(); NRCOPY is the number of times realloc() had to allocate new + * memory and copy to it. NRECURSE is a count of the number of recursive + * calls to malloc() for the same bucket size, which can be caused by calls + * to malloc() from a signal handler. NSBRK is the number of calls to sbrk() + * (whether by morecore() or for alignment); TSBRK is the total number of + * bytes requested from the kernel with sbrk(). BYTESUSED is the total + * number of bytes consumed by blocks currently in use; BYTESFREE is the + * total number of bytes currently on all of the free lists. NBSPLIT is + * the number of times a larger block was split to satisfy a smaller request. + * NBCOALESCE is the number of times two adjacent smaller blocks off the free + * list were combined to satisfy a larger request. + */ +struct _malstats { + int nmalloc[NBUCKETS]; + int tmalloc[NBUCKETS]; + int nmorecore[NBUCKETS]; + int nmal; + int nfre; + int nrealloc; + int nrcopy; + int nrecurse; + int nsbrk; + int32_t tsbrk; + int32_t bytesused; + int32_t bytesfree; + int nbsplit; + int nbcoalesce; +}; + +static struct _malstats _mstats; + +/* Return statistics describing allocation of blocks of size BLOCKSIZE. + NFREE is the number of free blocks for this allocation size. NUSED + is the number of blocks in use. NMAL is the number of requests for + blocks of size BLOCKSIZE. NMORECORE is the number of times we had + to call MORECORE to repopulate the free list for this bucket. */ +struct bucket_stats { + u_int32_t blocksize; + int nfree; + int nused; + int nmal; + int nmorecore; +}; +#endif /* MALLOC_STATS */ + +/* We have a flag indicating whether memory is allocated, an index in + nextf[], a size field, and a sentinel value to determine whether or + not a caller wrote before the start of allocated memory; to realloc() + memory we either copy mh_nbytes or just change mh_nbytes if there is + enough room in the block for the new size. Range checking is always + done. */ +union mhead { + union mhead *mh_align; + struct { + char mi_alloc; /* ISALLOC or ISFREE */ /* 1 */ + char mi_index; /* index in nextf[] */ /* 1 */ + /* Remainder are valid only when block is allocated */ + u_int32_t mi_nbytes; /* # of bytes allocated */ /* 4 */ + unsigned short mi_magic2;/* should be == MAGIC2 */ /* 2 */ + } minfo; }; +#define mh_alloc minfo.mi_alloc +#define mh_index minfo.mi_index +#define mh_nbytes minfo.mi_nbytes +#define mh_magic2 minfo.mi_magic2 /* Access free-list pointer of a block. - It is stored at block + 4. - This is not a field in the mhead structure - because we want sizeof (struct mhead) - to describe the overhead for when the block is in use, - and we do not want the free-list pointer to count in that. */ + It is stored at block + sizeof (char *). + This is not a field in the mhead structure + because we want sizeof (struct mhead) + to describe the overhead for when the block is in use, + and we do not want the free-list pointer to count in that. */ #define CHAIN(a) \ - (*(struct mhead **) (sizeof (char *) + (char *) (a))) + (*(union mhead **) (sizeof (char *) + (char *) (a))) -#ifdef RCHECK -# include <stdio.h> -# if !defined (botch) -# define botch(x) abort () -# else -extern void botch(); -# endif /* botch */ +#if defined (botch) +extern void botch (); +#else +static void +botch (s) + char *s; +{ + fprintf (stderr, "\r\nmalloc: assertion botched: %s\r\n", s); + (void)fflush (stderr); + abort (); +} +#endif /* !botch */ -# if !defined (__STRING) -# if defined (__STDC__) -# define __STRING(x) #x -# else -# define __STRING(x) "x" -# endif +#if !defined (__STRING) +# if defined (__STDC__) +# define __STRING(x) #x +# else +# define __STRING(x) "x" # endif +#endif /* !__STRING */ - /* To implement range checking, we write magic values in at the beginning - and end of each allocated block, and make sure they are undisturbed - whenever a free or a realloc occurs. */ - - /* Written in each of the 4 bytes following the block's real space */ -# define MAGIC1 0x55 - /* Written in the 4 bytes before the block's real space */ -# define MAGIC4 0x55555555 -# define ASSERT(p) if (!(p)) botch(__STRING(p)); else -# define EXTRA 4 /* 4 bytes extra for MAGIC1s */ -#else /* !RCHECK */ -# define ASSERT(p) -# define EXTRA 0 -#endif /* RCHECK */ +/* To implement range checking, we write magic values in at the beginning + and end of each allocated block, and make sure they are undisturbed + whenever a free or a realloc occurs. */ + +/* Written in each of the 4 bytes following the block's real space */ +#define MAGIC1 0x55 +/* Written in the 2 bytes before the block's real space */ +#define MAGIC2 0x5555 +#define ASSERT(p) do { if (!(p)) botch(__STRING(p)); } while (0) +#define MSLOP 4 /* 4 bytes extra for MAGIC1s */ + +/* Minimum and maximum bucket indices for block splitting (and to bound + the search for a block to split). */ +#define SPLIT_MIN 3 +#define SPLIT_MID 9 +#define SPLIT_MAX 12 + +/* Minimum and maximum bucket indices for block coalescing. */ +#define COMBINE_MIN 6 +#define COMBINE_MAX (pagebucket - 1) + +#define MIN_COMBINE_FREE 4 /* nextf[i] is free list of blocks of size 2**(i + 3) */ -static struct mhead *nextf[30]; +static union mhead *nextf[NBUCKETS]; /* busy[i] is nonzero while allocation of block size i is in progress. */ -static char busy[30]; +static char busy[NBUCKETS]; -/* Number of bytes of writable memory we can expect to be able to get */ -static unsigned int lim_data; +static int pagesz; /* system page size. */ +static int pagebucket; /* bucket for requests a page in size */ -/* Level number of warnings already issued. - 0 -- no warnings issued. - 1 -- 75% warning already issued. - 2 -- 85% warning already issued. -*/ -static int warnlevel; +#if 0 +/* Coalesce two adjacent free blocks off the free list for size NU - 1, + as long as there are at least MIN_COMBINE_FREE free blocks and we + can find two adjacent free blocks. nextf[NU -1] is assumed to not + be busy; the caller (morecore()) checks for this. */ +static void +bcoalesce (nu) + register int nu; +{ + register union mhead *mp, *mp1, *mp2; + register int nfree, nbuck; + unsigned long siz; -/* Function to call to issue a warning; - 0 means don't issue them. */ -static void (*warnfunction) (); + nbuck = nu - 1; + if (nextf[nbuck] == 0) + return; -/* nonzero once initial bunch of free blocks made */ -static int gotpool; + nfree = 1; + mp1 = nextf[nbuck]; + mp = CHAIN (mp1); + mp2 = (union mhead *)0; + while (CHAIN (mp)) + { + mp2 = mp1; + mp1 = mp; + mp = CHAIN (mp); + nfree++; + /* We may not want to run all the way through the free list here; + if we do not, we need to check a threshold value here and break + if nfree exceeds it. */ + } + if (nfree < MIN_COMBINE_FREE) + return; + /* OK, now we have mp1 pointing to the block we want to add to nextf[NU]. + CHAIN(mp2) must equal mp1. Check that mp1 and mp are adjacent. */ + if (CHAIN(mp2) != mp1) + botch ("bcoalesce: CHAIN(mp2) != mp1"); + siz = 1 << (nbuck + 3); + if (CHAIN (mp1) != (union mhead *)((char *)mp1 + siz)) + return; /* not adjacent */ + +#ifdef MALLOC_STATS + _mstats.nbcoalesce++; +#endif -char *_malloc_base; + /* Since they are adjacent, remove them from the free list */ + CHAIN (mp2) = CHAIN (mp); -static void getpool (); + /* And add the combined two blocks to nextf[NU]. */ + mp1->mh_alloc = ISFREE; + mp1->mh_index = nu; + CHAIN (mp1) = nextf[nu]; + nextf[nu] = mp1; +} +#endif -/* Cause reinitialization based on job parameters; - also declare where the end of pure storage is. */ -void -malloc_init (start, warnfun) - char *start; - void (*warnfun) (); +/* Split a block at index > NU (but less than SPLIT_MAX) into a set of + blocks of the correct size, and attach them to nextf[NU]. nextf[NU] + is assumed to be empty. Must be called with signals blocked (e.g., + by morecore()). */ +static void +bsplit (nu) + register int nu; { - if (start) - data_space_start = start; - lim_data = 0; - warnlevel = 0; - warnfunction = warnfun; -} + register union mhead *mp; + int nbuck, nblks; + unsigned long siz; -/* Return the maximum size to which MEM can be realloc'd - without actually requiring copying. */ + if (nu >= SPLIT_MID) + { + for (nbuck = SPLIT_MAX; nbuck > nu; nbuck--) + { + if (busy[nbuck] || nextf[nbuck] == 0) + continue; + break; + } + } + else + { + for (nbuck = nu + 1; nbuck <= SPLIT_MAX; nbuck++) + { + if (busy[nbuck] || nextf[nbuck] == 0) + continue; + break; + } + } -int -malloc_usable_size (mem) - char *mem; -{ - int blocksize = 8 << (((struct mhead *) mem) - 1) -> mh_index; + if (nbuck > SPLIT_MAX || nbuck <= nu) + return; + + /* XXX might want to split only if nextf[nbuck] has >= 2 blocks free + and nbuck is below some threshold. */ + +#ifdef MALLOC_STATS + _mstats.nbsplit++; +#endif + + /* Figure out how many blocks we'll get. */ + siz = (1 << (nu + 3)); + nblks = (1 << (nbuck + 3)) / siz; - return blocksize - sizeof (struct mhead) - EXTRA; + /* Remove the block from the chain of larger blocks. */ + mp = nextf[nbuck]; + nextf[nbuck] = CHAIN (mp); + + /* Split the block and put it on the requested chain. */ + nextf[nu] = mp; + while (1) + { + mp->mh_alloc = ISFREE; + mp->mh_index = nu; + if (--nblks <= 0) break; + CHAIN (mp) = (union mhead *)((char *)mp + siz); + mp = (union mhead *)((char *)mp + siz); + } + CHAIN (mp) = 0; } static void morecore (nu) /* ask system for more memory */ register int nu; /* size index to get more of */ { - register char *cp; + register union mhead *mp; register int nblks; - register unsigned int siz; + register long siz; + long sbrk_amt; /* amount to get via sbrk() */ /* Block all signals in case we are executed from a signal handler. */ #if defined (HAVE_BSD_SIGNALS) @@ -279,82 +403,88 @@ morecore (nu) /* ask system for more memory */ # endif /* HAVE_POSIX_SIGNALS */ #endif /* HAVE_BSD_SIGNALS */ - if (!data_space_start) + siz = 1 << (nu + 3); /* size of desired block for nextf[nu] */ + + if (siz < 0) + return; /* oops */ + +#ifdef MALLOC_STATS + _mstats.nmorecore[nu]++; +#endif + + /* Try to split a larger block here, if we're within the range of sizes + to split. */ + if (nu >= SPLIT_MIN && nu < SPLIT_MAX) + { + bsplit (nu); + if (nextf[nu] != 0) + goto morecore_done; + } + +#if 0 + /* Try to coalesce two adjacent blocks from the free list on nextf[nu - 1], + if we can, and we're withing the range of the block coalescing limits. */ + if (nu >= COMBINE_MIN && nu < COMBINE_MAX && busy[nu - 1] == 0 && nextf[nu - 1]) + { + bcoalesce (nu); + if (nextf[nu] != 0) + goto morecore_done; + } +#endif + + /* Take at least a page, and figure out how many blocks of the requested + size we're getting. */ + if (siz <= pagesz) { - data_space_start = start_of_data (); + sbrk_amt = pagesz; + nblks = sbrk_amt / siz; } + else + { + /* We always want to request an integral multiple of the page size + from the kernel, so let's compute whether or not `siz' is such + an amount. If it is, we can just request it. If not, we want + the smallest integral multiple of pagesize that is larger than + `siz' and will satisfy the request. */ + sbrk_amt = siz % pagesz; + if (sbrk_amt == 0) + sbrk_amt = siz; + else + sbrk_amt = siz + pagesz - sbrk_amt; + nblks = 1; + } + +#ifdef MALLOC_STATS + _mstats.nsbrk++; + _mstats.tsbrk += sbrk_amt; +#endif + + mp = (union mhead *) sbrk (sbrk_amt); - if (lim_data == 0) - get_lim_data (); - - /* On initial startup, get two blocks of each size up to 1k bytes */ - if (!gotpool) - { getpool (); getpool (); gotpool = 1; } - - /* Find current end of memory and issue warning if getting near max */ - - cp = sbrk (0); - siz = cp - data_space_start; - malloc_sbrk_used = siz; - malloc_sbrk_unused = lim_data - siz; - - if (warnfunction) - switch (warnlevel) - { - case 0: - if (siz > (lim_data / 4) * 3) - { - warnlevel++; - (*warnfunction) ("Warning: past 75% of memory limit"); - } - break; - case 1: - if (siz > (lim_data / 20) * 17) - { - warnlevel++; - (*warnfunction) ("Warning: past 85% of memory limit"); - } - break; - case 2: - if (siz > (lim_data / 20) * 19) - { - warnlevel++; - (*warnfunction) ("Warning: past 95% of memory limit"); - } - break; - } - - if ((int) cp & 0x3ff) /* land on 1K boundaries */ - sbrk (1024 - ((int) cp & 0x3ff)); - - /* Take at least 2k, and figure out how many blocks of the desired size - we're about to get */ - nblks = 1; - if ((siz = nu) < 8) - nblks = 1 << ((siz = 8) - nu); - - if ((cp = sbrk (1 << (siz + 3))) == (char *) -1) - return; /* no more room! */ - - if ((int) cp & 7) - { /* shouldn't happen, but just in case */ - cp = (char *) (((int) cp + 8) & ~7); + /* Totally out of memory. */ + if ((long)mp == -1) + return; + + /* shouldn't happen, but just in case -- require 8-byte alignment */ + if ((long)mp & 7) + { + mp = (union mhead *) (((long)mp + 8) & ~7); nblks--; } - /* save new header and link the nblks blocks together */ - nextf[nu] = (struct mhead *) cp; - siz = 1 << (nu + 3); + /* save new header and link the nblks blocks together */ + nextf[nu] = mp; while (1) { - ((struct mhead *) cp) -> mh_alloc = ISFREE; - ((struct mhead *) cp) -> mh_index = nu; + mp->mh_alloc = ISFREE; + mp->mh_index = nu; if (--nblks <= 0) break; - CHAIN ((struct mhead *) cp) = (struct mhead *) (cp + siz); - cp += siz; + CHAIN (mp) = (union mhead *)((char *)mp + siz); + mp = (union mhead *)((char *)mp + siz); } - CHAIN ((struct mhead *) cp) = 0; + CHAIN (mp) = 0; +morecore_done: #if defined (HAVE_BSD_SIGNALS) sigsetmask (oldmask); #else @@ -364,44 +494,6 @@ morecore (nu) /* ask system for more memory */ #endif /* HAVE_BSD_SIGNALS */ } -static void -getpool () -{ - register int nu; - register char *cp = sbrk (0); - - if ((int) cp & 0x3ff) /* land on 1K boundaries */ - sbrk (1024 - ((int) cp & 0x3ff)); - - /* Record address of start of space allocated by malloc. */ - if (_malloc_base == 0) - _malloc_base = cp; - - /* Get 2k of storage */ - - cp = sbrk (04000); - if (cp == (char *) -1) - return; - - /* Divide it into an initial 8-word block - plus one block of size 2**nu for nu = 3 ... 10. */ - - CHAIN (cp) = nextf[0]; - nextf[0] = (struct mhead *) cp; - ((struct mhead *) cp) -> mh_alloc = ISFREE; - ((struct mhead *) cp) -> mh_index = 0; - cp += 8; - - for (nu = 0; nu < 7; nu++) - { - CHAIN (cp) = nextf[nu]; - nextf[nu] = (struct mhead *) cp; - ((struct mhead *) cp) -> mh_alloc = ISFREE; - ((struct mhead *) cp) -> mh_index = nu; - cp += 8 << nu; - } -} - #if defined (MEMSCRAMBLE) || !defined (NO_CALLOC) static char * zmemset (s, c, n) @@ -418,75 +510,130 @@ zmemset (s, c, n) } #endif /* MEMSCRAMBLE || !NO_CALLOC */ +static void +malloc_debug_dummy () +{ + ; +} + char * malloc (n) /* get a block */ - unsigned int n; + size_t n; { - register struct mhead *p; - register unsigned int nbytes; - register int nunits = 0; + register union mhead *p; + register long nbytes; + register int nunits; + /* Get the system page size and align break pointer so everything will + be page-aligned. The page size must be at least 1K -- anything + smaller is increased. */ + if (pagesz == 0) + { + register long sbrk_needed; + + pagesz = getpagesize (); + if (pagesz < 1024) + pagesz = 1024; + /* OK, how much do we need to allocate to make things page-aligned? + This partial page is wasted space. Once we figure out how much + to advance the break pointer, go ahead and do it. */ + sbrk_needed = pagesz - ((long)sbrk (0) & (pagesz - 1)); /* sbrk(0) % pagesz */ + if (sbrk_needed < 0) + sbrk_needed += pagesz; + /* Now allocate the wasted space. */ + if (sbrk_needed) + { +#ifdef MALLOC_STATS + _mstats.nsbrk++; + _mstats.tsbrk += sbrk_needed; +#endif + if ((long)sbrk (sbrk_needed) == -1) + return (NULL); + } + nunits = 0; + nbytes = 8; + while (pagesz > nbytes) + { + nbytes <<= 1; + nunits++; + } + pagebucket = nunits; + } + /* Figure out how many bytes are required, rounding up to the nearest - multiple of 4, then figure out which nextf[] area to use */ - nbytes = (n + sizeof *p + EXTRA + 3) & ~3; - { - register unsigned int shiftr = (nbytes - 1) >> 2; + multiple of 4, then figure out which nextf[] area to use. Try to + be smart about where to start searching -- if the number of bytes + needed is greater than the page size, we can start at pagebucket. */ + nbytes = (n + sizeof *p + MSLOP + 3) & ~3; + nunits = 0; + if (nbytes <= (pagesz >> 1)) + { + register unsigned int shiftr; - while (shiftr >>= 1) - nunits++; - } + shiftr = (nbytes - 1) >> 2; /* == (nbytes - 1) / 4 */ + while (shiftr >>= 1) /* == (nbytes - 1) / {8,16,32,...} */ + nunits++; + } + else + { + register u_int32_t amt; + + nunits = pagebucket; + amt = pagesz; + while (nbytes > amt) + { + amt <<= 1; + nunits++; + } + } /* In case this is reentrant use of malloc from signal handler, pick a block size that no other malloc level is currently trying to allocate. That's the easiest harmless way not to interfere with the other level of execution. */ +#ifdef MALLOC_STATS + if (busy[nunits]) _mstats.nrecurse++; +#endif while (busy[nunits]) nunits++; busy[nunits] = 1; /* If there are no blocks of the appropriate size, go get some */ - /* COULD SPLIT UP A LARGER BLOCK HERE ... ACT */ if (nextf[nunits] == 0) morecore (nunits); /* Get one block off the list, and set the new list head */ - if ((p = nextf[nunits]) == 0) + if ((p = nextf[nunits]) == NULL) { busy[nunits] = 0; - return 0; + return NULL; } nextf[nunits] = CHAIN (p); busy[nunits] = 0; /* Check for free block clobbered */ - /* If not for this check, we would gobble a clobbered free chain ptr */ - /* and bomb out on the NEXT allocate of this size block */ - if (p -> mh_alloc != ISFREE || p -> mh_index != nunits) -#ifdef RCHECK - botch ("block on free list clobbered"); -#else /* not RCHECK */ - abort (); -#endif /* not RCHECK */ + /* If not for this check, we would gobble a clobbered free chain ptr + and bomb out on the NEXT allocate of this size block */ + if (p->mh_alloc != ISFREE || p->mh_index != nunits) + botch ("malloc: block on free list clobbered"); /* Fill in the info, and if range checking, set up the magic numbers */ - p -> mh_alloc = ISALLOC; -#ifdef RCHECK - p -> mh_nbytes = n; - p -> mh_magic4 = MAGIC4; + p->mh_alloc = ISALLOC; + p->mh_nbytes = n; + p->mh_magic2 = MAGIC2; { register char *m = (char *) (p + 1) + n; *m++ = MAGIC1, *m++ = MAGIC1, *m++ = MAGIC1, *m = MAGIC1; } -#else /* not RCHECK */ - p -> mh_size = n; -#endif /* not RCHECK */ + #ifdef MEMSCRAMBLE zmemset ((char *)(p + 1), 0xdf, n); /* scramble previous contents */ #endif -#ifdef MSTATS - nmalloc[nunits]++; - nmal++; -#endif /* MSTATS */ +#ifdef MALLOC_STATS + _mstats.nmalloc[nunits]++; + _mstats.tmalloc[nunits]++; + _mstats.nmal++; +#endif /* MALLOC_STATS */ return (char *) (p + 1); } @@ -494,143 +641,123 @@ void free (mem) char *mem; { - register struct mhead *p; - { - register char *ap = mem; + register union mhead *p; + register char *ap; + register int nunits; + + if ((ap = mem) == 0) + return; - if (ap == 0) - return; + p = (union mhead *) ap - 1; - p = (struct mhead *) ap - 1; + if (p->mh_alloc == ISMEMALIGN) + { + ap -= p->mh_nbytes; + p = (union mhead *) ap - 1; + } + + if (p->mh_alloc != ISALLOC) + { + if (p->mh_alloc == ISFREE) + botch ("free: called with already freed block argument"); + else + botch ("free: called with unallocated block argument"); + } + + ASSERT (p->mh_magic2 == MAGIC2); + ap += p->mh_nbytes; + ASSERT (*ap++ == MAGIC1); ASSERT (*ap++ == MAGIC1); + ASSERT (*ap++ == MAGIC1); ASSERT (*ap == MAGIC1); - if (p -> mh_alloc == ISMEMALIGN) - { -#ifdef RCHECK - ap -= p->mh_nbytes; -#else - ap -= p->mh_size; /* XXX */ -#endif - p = (struct mhead *) ap - 1; - } - -#ifndef RCHECK - if (p -> mh_alloc != ISALLOC) - abort (); - -#else /* RCHECK */ - if (p -> mh_alloc != ISALLOC) - { - if (p -> mh_alloc == ISFREE) - botch ("free: Called with already freed block argument\n"); - else - botch ("free: Called with unallocated block argument\n"); - } - - ASSERT (p -> mh_magic4 == MAGIC4); - ap += p -> mh_nbytes; - ASSERT (*ap++ == MAGIC1); ASSERT (*ap++ == MAGIC1); - ASSERT (*ap++ == MAGIC1); ASSERT (*ap == MAGIC1); -#endif /* RCHECK */ - } #ifdef MEMSCRAMBLE - { - register int n; - -#ifdef RCHECK - n = p->mh_nbytes; -#else /* not RCHECK */ - n = p->mh_size; -#endif /* not RCHECK */ - zmemset (mem, 0xcf, n); - } + zmemset (mem, 0xcf, p->mh_nbytes); #endif - { - register int nunits = p -> mh_index; - - ASSERT (nunits <= 29); - p -> mh_alloc = ISFREE; - - /* Protect against signal handlers calling malloc. */ - busy[nunits] = 1; - /* Put this block on the free list. */ - CHAIN (p) = nextf[nunits]; - nextf[nunits] = p; - busy[nunits] = 0; - -#ifdef MSTATS - nmalloc[nunits]--; - nfre++; -#endif /* MSTATS */ - } + + nunits = p->mh_index; + + ASSERT (nunits < NBUCKETS); + p->mh_alloc = ISFREE; + + /* Protect against signal handlers calling malloc. */ + busy[nunits] = 1; + /* Put this block on the free list. */ + CHAIN (p) = nextf[nunits]; + nextf[nunits] = p; + busy[nunits] = 0; + +#ifdef MALLOC_STATS + _mstats.nmalloc[nunits]--; + _mstats.nfre++; +#endif /* MALLOC_STATS */ } char * realloc (mem, n) char *mem; - register unsigned int n; + register size_t n; { - register struct mhead *p; - register unsigned int tocopy; + register union mhead *p; + register u_int32_t tocopy; register unsigned int nbytes; register int nunits; + register char *m; + +#ifdef MALLOC_STATS + _mstats.nrealloc++; +#endif - if ((p = (struct mhead *) mem) == 0) + if (n == 0) + { + free (mem); + return (NULL); + } + if ((p = (union mhead *) mem) == 0) return malloc (n); p--; - nunits = p -> mh_index; - ASSERT (p -> mh_alloc == ISALLOC); -#ifdef RCHECK - ASSERT (p -> mh_magic4 == MAGIC4); - { - register char *m = mem + (tocopy = p -> mh_nbytes); - ASSERT (*m++ == MAGIC1); ASSERT (*m++ == MAGIC1); - ASSERT (*m++ == MAGIC1); ASSERT (*m == MAGIC1); - } -#else /* not RCHECK */ - if (p -> mh_index >= 13) - tocopy = (1 << (p -> mh_index + 3)) - sizeof *p; - else - tocopy = p -> mh_size; -#endif /* not RCHECK */ + nunits = p->mh_index; + ASSERT (p->mh_alloc == ISALLOC); + ASSERT (p->mh_magic2 == MAGIC2); + + m = mem + (tocopy = p->mh_nbytes); + ASSERT (*m++ == MAGIC1); ASSERT (*m++ == MAGIC1); + ASSERT (*m++ == MAGIC1); ASSERT (*m == MAGIC1); /* See if desired size rounds to same power of 2 as actual size. */ - nbytes = (n + sizeof *p + EXTRA + 7) & ~7; + nbytes = (n + sizeof *p + MSLOP + 7) & ~7; /* If ok, use the same block, just marking its size as changed. */ if (nbytes > (4 << nunits) && nbytes <= (8 << nunits)) { -#ifdef RCHECK - register char *m = mem + tocopy; + m = mem + tocopy; *m++ = 0; *m++ = 0; *m++ = 0; *m++ = 0; - p-> mh_nbytes = n; + p->mh_nbytes = n; m = mem + n; *m++ = MAGIC1; *m++ = MAGIC1; *m++ = MAGIC1; *m++ = MAGIC1; -#else /* not RCHECK */ - p -> mh_size = n; -#endif /* not RCHECK */ return mem; } +#ifdef MALLOC_STATS + _mstats.nrcopy++; +#endif + if (n < tocopy) tocopy = n; - { - register char *new; - if ((new = malloc (n)) == 0) - return 0; - FASTCOPY (mem, new, tocopy); - free (mem); - return new; - } + if ((m = malloc (n)) == 0) + return 0; + FASTCOPY (mem, m, tocopy); + free (mem); + return m; } char * memalign (alignment, size) - unsigned int alignment, size; + unsigned int alignment; + size_t size; { register char *ptr; register char *aligned; - register struct mhead *p; + register union mhead *p; ptr = malloc (size + alignment); @@ -644,9 +771,9 @@ memalign (alignment, size) /* Store a suitable indication of how to free the block, so that free can find the true beginning of it. */ - p = (struct mhead *) aligned - 1; - p -> mh_size = aligned - ptr; - p -> mh_alloc = ISMEMALIGN; + p = (union mhead *) aligned - 1; + p->mh_nbytes = aligned - ptr; + p->mh_alloc = ISMEMALIGN; return aligned; } @@ -688,72 +815,80 @@ cfree (p) } #endif /* !NO_CALLOC */ -#ifdef MSTATS -/* Return statistics describing allocation of blocks of size 2**n. */ - -struct mstats_value - { - int blocksize; - int nfree; - int nused; - }; +#ifdef MALLOC_STATS -struct mstats_value -malloc_stats (size) +struct bucket_stats +malloc_bucket_stats (size) int size; { - struct mstats_value v; - register int i; - register struct mhead *p; + struct bucket_stats v; + register union mhead *p; v.nfree = 0; - if (size < 0 || size >= 30) + if (size < 0 || size >= NBUCKETS) { v.blocksize = 0; - v.nused = 0; + v.nused = v.nmal = 0; return v; } v.blocksize = 1 << (size + 3); - v.nused = nmalloc[size]; + v.nused = _mstats.nmalloc[size]; + v.nmal = _mstats.tmalloc[size]; + v.nmorecore = _mstats.nmorecore[size]; for (p = nextf[size]; p; p = CHAIN (p)) v.nfree++; return v; } -#endif /* MSTATS */ -/* - * This function returns the total number of bytes that the process - * will be allowed to allocate via the sbrk(2) system call. On - * BSD systems this is the total space allocatable to stack and - * data. On USG systems this is the data space only. - */ - -#if !defined (HAVE_RESOURCE) -extern long ulimit (); +/* Return a copy of _MSTATS, with two additional fields filled in: + BYTESFREE is the total number of bytes on free lists. BYTESUSED + is the total number of bytes in use. These two fields are fairly + expensive to compute, so we do it only when asked to. */ +struct _malstats +malloc_stats () +{ + struct _malstats result; + struct bucket_stats v; + register int i; -static void -get_lim_data () -{ - lim_data = ulimit (3, 0); - lim_data -= (long) data_space_start; + result = _mstats; + result.bytesused = result.bytesfree = 0; + for (i = 0; i < NBUCKETS; i++) + { + v = malloc_bucket_stats (i); + result.bytesfree += v.nfree * v.blocksize; + result.bytesused += v.nused * v.blocksize; + } + return (result); } -#else /* HAVE_RESOURCE */ -static void -get_lim_data () +void +print_malloc_stats (s) + char *s; { - struct rlimit XXrlimit; + register int i; + int totused, totfree; + struct bucket_stats v; - getrlimit (RLIMIT_DATA, &XXrlimit); -#ifdef RLIM_INFINITY - lim_data = XXrlimit.rlim_cur & RLIM_INFINITY; /* soft limit */ -#else - lim_data = XXrlimit.rlim_cur; /* soft limit */ -#endif + fprintf (stderr, "Memory allocation statistics: %s\n\tsize\tfree\tin use\ttotal\tmorecore\n", s ? s : ""); + for (i = totused = totfree = 0; i < NBUCKETS; i++) + { + v = malloc_bucket_stats (i); + fprintf (stderr, "%12lu\t%4d\t%6d\t%5d\t%8d\n", v.blocksize, v.nfree, v.nused, v.nmal, v.nmorecore); + totfree += v.nfree * v.blocksize; + totused += v.nused * v.blocksize; + } + fprintf (stderr, "\nTotal bytes in use: %d, total bytes free: %d\n", + totused, totfree); + fprintf (stderr, "Total mallocs: %d, total frees: %d, total reallocs: %d (%d copies)\n", + _mstats.nmal, _mstats.nfre, _mstats.nrealloc, _mstats.nrcopy); + fprintf (stderr, "Total sbrks: %d, total bytes via sbrk: %d\n", + _mstats.nsbrk, _mstats.tsbrk); + fprintf (stderr, "Total blocks split: %d, total block coalesces: %d\n", + _mstats.nbsplit, _mstats.nbcoalesce); } - -#endif /* HAVE_RESOURCE */ +#endif /* MALLOC_STATS */ diff --git a/lib/malloc/ogmalloc.c b/lib/malloc/ogmalloc.c new file mode 100644 index 00000000..8690b126 --- /dev/null +++ b/lib/malloc/ogmalloc.c @@ -0,0 +1,1579 @@ +/* DO NOT EDIT THIS FILE -- it is automagically generated. -*- C -*- */ + +#define _MALLOC_INTERNAL + +/* The malloc headers and source files from the C library follow here. */ + +/* Declarations for `malloc' and friends. + Copyright 1990, 91, 92, 93, 95, 96 Free Software Foundation, Inc. + Written May 1989 by Mike Haertel. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. + + The author may be reached (Email) at the address mike@ai.mit.edu, + or (US mail) as Mike Haertel c/o Free Software Foundation. */ + +#ifndef _MALLOC_H + +#define _MALLOC_H 1 + +#ifdef _MALLOC_INTERNAL + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#if defined(_LIBC) || defined(STDC_HEADERS) || defined(USG) +#include <string.h> +#else +#ifndef memset +#define memset(s, zero, n) bzero ((s), (n)) +#endif +#ifndef memcpy +#define memcpy(d, s, n) bcopy ((s), (d), (n)) +#endif +#endif + +#if defined (__GNU_LIBRARY__) || (defined (__STDC__) && __STDC__) +#include <limits.h> +#else +#ifndef CHAR_BIT +#define CHAR_BIT 8 +#endif +#endif + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#endif /* _MALLOC_INTERNAL. */ + + +#ifdef __cplusplus +extern "C" +{ +#endif + +#if defined (__cplusplus) || (defined (__STDC__) && __STDC__) +#undef __P +#define __P(args) args +#undef __ptr_t +#define __ptr_t void * +#else /* Not C++ or ANSI C. */ +#undef __P +#define __P(args) () +#undef const +#define const +#undef __ptr_t +#define __ptr_t char * +#endif /* C++ or ANSI C. */ + +#if defined (__STDC__) && __STDC__ +#include <stddef.h> +#define __malloc_size_t size_t +#define __malloc_ptrdiff_t ptrdiff_t +#else +#define __malloc_size_t unsigned int +#define __malloc_ptrdiff_t int +#endif + +#ifndef NULL +#define NULL 0 +#endif + + +/* Allocate SIZE bytes of memory. */ +extern __ptr_t malloc __P ((__malloc_size_t __size)); +/* Re-allocate the previously allocated block + in __ptr_t, making the new block SIZE bytes long. */ +extern __ptr_t realloc __P ((__ptr_t __ptr, __malloc_size_t __size)); +/* Allocate NMEMB elements of SIZE bytes each, all initialized to 0. */ +extern __ptr_t calloc __P ((__malloc_size_t __nmemb, __malloc_size_t __size)); +/* Free a block allocated by `malloc', `realloc' or `calloc'. */ +extern void free __P ((__ptr_t __ptr)); + +/* Allocate SIZE bytes allocated to ALIGNMENT bytes. */ +#if ! (defined (_MALLOC_INTERNAL) && __DJGPP__ - 0 == 1) /* Avoid conflict. */ +extern __ptr_t memalign __P ((__malloc_size_t __alignment, + __malloc_size_t __size)); +#endif + +/* Allocate SIZE bytes on a page boundary. */ +#if ! (defined (_MALLOC_INTERNAL) && defined (emacs)) /* Avoid conflict. */ +extern __ptr_t valloc __P ((__malloc_size_t __size)); +#endif + + +#ifdef _MALLOC_INTERNAL + +/* The allocator divides the heap into blocks of fixed size; large + requests receive one or more whole blocks, and small requests + receive a fragment of a block. Fragment sizes are powers of two, + and all fragments of a block are the same size. When all the + fragments in a block have been freed, the block itself is freed. */ +#define INT_BIT (CHAR_BIT * sizeof(int)) +#define BLOCKLOG (INT_BIT > 16 ? 12 : 9) +#define BLOCKSIZE (1 << BLOCKLOG) +#define BLOCKIFY(SIZE) (((SIZE) + BLOCKSIZE - 1) / BLOCKSIZE) + +/* Determine the amount of memory spanned by the initial heap table + (not an absolute limit). */ +#define HEAP (INT_BIT > 16 ? 4194304 : 65536) + +/* Number of contiguous free blocks allowed to build up at the end of + memory before they will be returned to the system. */ +#define FINAL_FREE_BLOCKS 8 + +/* Data structure giving per-block information. */ +typedef union + { + /* Heap information for a busy block. */ + struct + { + /* Zero for a large (multiblock) object, or positive giving the + logarithm to the base two of the fragment size. */ + int type; + union + { + struct + { + __malloc_size_t nfree; /* Free frags in a fragmented block. */ + __malloc_size_t first; /* First free fragment of the block. */ + } frag; + /* For a large object, in its first block, this has the number + of blocks in the object. In the other blocks, this has a + negative number which says how far back the first block is. */ + __malloc_ptrdiff_t size; + } info; + } busy; + /* Heap information for a free block + (that may be the first of a free cluster). */ + struct + { + __malloc_size_t size; /* Size (in blocks) of a free cluster. */ + __malloc_size_t next; /* Index of next free cluster. */ + __malloc_size_t prev; /* Index of previous free cluster. */ + } free; + } malloc_info; + +/* Pointer to first block of the heap. */ +extern char *_heapbase; + +/* Table indexed by block number giving per-block information. */ +extern malloc_info *_heapinfo; + +/* Address to block number and vice versa. */ +#define BLOCK(A) (((char *) (A) - _heapbase) / BLOCKSIZE + 1) +#define ADDRESS(B) ((__ptr_t) (((B) - 1) * BLOCKSIZE + _heapbase)) + +/* Current search index for the heap table. */ +extern __malloc_size_t _heapindex; + +/* Limit of valid info table indices. */ +extern __malloc_size_t _heaplimit; + +/* Doubly linked lists of free fragments. */ +struct list + { + struct list *next; + struct list *prev; + }; + +/* Free list headers for each fragment size. */ +extern struct list _fraghead[]; + +/* List of blocks allocated with `memalign' (or `valloc'). */ +struct alignlist + { + struct alignlist *next; + __ptr_t aligned; /* The address that memaligned returned. */ + __ptr_t exact; /* The address that malloc returned. */ + }; +extern struct alignlist *_aligned_blocks; + +/* Instrumentation. */ +extern __malloc_size_t _chunks_used; +extern __malloc_size_t _bytes_used; +extern __malloc_size_t _chunks_free; +extern __malloc_size_t _bytes_free; + +/* Internal versions of `malloc', `realloc', and `free' + used when these functions need to call each other. + They are the same but don't call the hooks. */ +extern __ptr_t _malloc_internal __P ((__malloc_size_t __size)); +extern __ptr_t _realloc_internal __P ((__ptr_t __ptr, __malloc_size_t __size)); +extern void _free_internal __P ((__ptr_t __ptr)); + +#endif /* _MALLOC_INTERNAL. */ + +/* Given an address in the middle of a malloc'd object, + return the address of the beginning of the object. */ +extern __ptr_t malloc_find_object_address __P ((__ptr_t __ptr)); + +/* Underlying allocation function; successive calls should + return contiguous pieces of memory. */ +extern __ptr_t (*__morecore) __P ((__malloc_ptrdiff_t __size)); + +/* Default value of `__morecore'. */ +extern __ptr_t __default_morecore __P ((__malloc_ptrdiff_t __size)); + +/* If not NULL, this function is called after each time + `__morecore' is called to increase the data size. */ +extern void (*__after_morecore_hook) __P ((void)); + +/* Number of extra blocks to get each time we ask for more core. + This reduces the frequency of calling `(*__morecore)'. */ +extern __malloc_size_t __malloc_extra_blocks; + +/* Nonzero if `malloc' has been called and done its initialization. */ +extern int __malloc_initialized; +/* Function called to initialize malloc data structures. */ +extern int __malloc_initialize __P ((void)); + +/* Hooks for debugging versions. */ +extern void (*__malloc_initialize_hook) __P ((void)); +extern void (*__free_hook) __P ((__ptr_t __ptr)); +extern __ptr_t (*__malloc_hook) __P ((__malloc_size_t __size)); +extern __ptr_t (*__realloc_hook) __P ((__ptr_t __ptr, __malloc_size_t __size)); +extern __ptr_t (*__memalign_hook) __P ((__malloc_size_t __size, + __malloc_size_t __alignment)); + +/* Return values for `mprobe': these are the kinds of inconsistencies that + `mcheck' enables detection of. */ +enum mcheck_status + { + MCHECK_DISABLED = -1, /* Consistency checking is not turned on. */ + MCHECK_OK, /* Block is fine. */ + MCHECK_FREE, /* Block freed twice. */ + MCHECK_HEAD, /* Memory before the block was clobbered. */ + MCHECK_TAIL /* Memory after the block was clobbered. */ + }; + +/* Activate a standard collection of debugging hooks. This must be called + before `malloc' is ever called. ABORTFUNC is called with an error code + (see enum above) when an inconsistency is detected. If ABORTFUNC is + null, the standard function prints on stderr and then calls `abort'. */ +extern int mcheck __P ((void (*__abortfunc) __P ((enum mcheck_status)))); + +/* Check for aberrations in a particular malloc'd block. You must have + called `mcheck' already. These are the same checks that `mcheck' does + when you free or reallocate a block. */ +extern enum mcheck_status mprobe __P ((__ptr_t __ptr)); + +/* Activate a standard collection of tracing hooks. */ +extern void mtrace __P ((void)); +extern void muntrace __P ((void)); + +/* Statistics available to the user. */ +struct mstats + { + __malloc_size_t bytes_total; /* Total size of the heap. */ + __malloc_size_t chunks_used; /* Chunks allocated by the user. */ + __malloc_size_t bytes_used; /* Byte total of user-allocated chunks. */ + __malloc_size_t chunks_free; /* Chunks in the free list. */ + __malloc_size_t bytes_free; /* Byte total of chunks in the free list. */ + }; + +/* Pick up the current statistics. */ +extern struct mstats mstats __P ((void)); + +/* Call WARNFUN with a warning message when memory usage is high. */ +extern void memory_warnings __P ((__ptr_t __start, + void (*__warnfun) __P ((const char *)))); + + +/* Relocating allocator. */ + +/* Allocate SIZE bytes, and store the address in *HANDLEPTR. */ +extern __ptr_t r_alloc __P ((__ptr_t *__handleptr, __malloc_size_t __size)); + +/* Free the storage allocated in HANDLEPTR. */ +extern void r_alloc_free __P ((__ptr_t *__handleptr)); + +/* Adjust the block at HANDLEPTR to be SIZE bytes long. */ +extern __ptr_t r_re_alloc __P ((__ptr_t *__handleptr, __malloc_size_t __size)); + + +#ifdef __cplusplus +} +#endif + +#endif /* malloc.h */ +/* Memory allocator `malloc'. + Copyright 1990, 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. + Written May 1989 by Mike Haertel. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. + + The author may be reached (Email) at the address mike@ai.mit.edu, + or (US mail) as Mike Haertel c/o Free Software Foundation. */ + +#ifndef _MALLOC_INTERNAL +#define _MALLOC_INTERNAL +#include <malloc.h> +#endif +#include <errno.h> + +/* How to really get more memory. */ +__ptr_t (*__morecore) __P ((ptrdiff_t __size)) = __default_morecore; + +/* Debugging hook for `malloc'. */ +__ptr_t (*__malloc_hook) __P ((__malloc_size_t __size)); + +/* Pointer to the base of the first block. */ +char *_heapbase; + +/* Block information table. Allocated with align/__free (not malloc/free). */ +malloc_info *_heapinfo; + +/* Number of info entries. */ +static __malloc_size_t heapsize; + +/* Search index in the info table. */ +__malloc_size_t _heapindex; + +/* Limit of valid info table indices. */ +__malloc_size_t _heaplimit; + +/* Free lists for each fragment size. */ +struct list _fraghead[BLOCKLOG]; + +/* Instrumentation. */ +__malloc_size_t _chunks_used; +__malloc_size_t _bytes_used; +__malloc_size_t _chunks_free; +__malloc_size_t _bytes_free; + +/* Are you experienced? */ +int __malloc_initialized; + +__malloc_size_t __malloc_extra_blocks; + +void (*__malloc_initialize_hook) __P ((void)); +void (*__after_morecore_hook) __P ((void)); + + +/* Aligned allocation. */ +static __ptr_t align __P ((__malloc_size_t)); +static __ptr_t +align (size) + __malloc_size_t size; +{ + __ptr_t result; + unsigned long int adj; + + result = (*__morecore) (size); + adj = (unsigned long int) ((unsigned long int) ((char *) result - + (char *) NULL)) % BLOCKSIZE; + if (adj != 0) + { + __ptr_t new; + adj = BLOCKSIZE - adj; + new = (*__morecore) (adj); + result = (char *) result + adj; + } + + if (__after_morecore_hook) + (*__after_morecore_hook) (); + + return result; +} + +/* Get SIZE bytes, if we can get them starting at END. + Return the address of the space we got. + If we cannot get space at END, fail and return -1. */ +static __ptr_t get_contiguous_space __P ((__malloc_ptrdiff_t, __ptr_t)); +static __ptr_t +get_contiguous_space (size, position) + __malloc_ptrdiff_t size; + __ptr_t position; +{ + __ptr_t before; + __ptr_t after; + + before = (*__morecore) (0); + /* If we can tell in advance that the break is at the wrong place, + fail now. */ + if (before != position) + return 0; + + /* Allocate SIZE bytes and get the address of them. */ + after = (*__morecore) (size); + if (!after) + return 0; + + /* It was not contiguous--reject it. */ + if (after != position) + { + (*__morecore) (- size); + return 0; + } + + return after; +} + + +/* This is called when `_heapinfo' and `heapsize' have just + been set to describe a new info table. Set up the table + to describe itself and account for it in the statistics. */ +static void register_heapinfo __P ((void)); +#ifdef __GNUC__ +__inline__ +#endif +static void +register_heapinfo () +{ + __malloc_size_t block, blocks; + + block = BLOCK (_heapinfo); + blocks = BLOCKIFY (heapsize * sizeof (malloc_info)); + + /* Account for the _heapinfo block itself in the statistics. */ + _bytes_used += blocks * BLOCKSIZE; + ++_chunks_used; + + /* Describe the heapinfo block itself in the heapinfo. */ + _heapinfo[block].busy.type = 0; + _heapinfo[block].busy.info.size = blocks; + /* Leave back-pointers for malloc_find_address. */ + while (--blocks > 0) + _heapinfo[block + blocks].busy.info.size = -blocks; +} + +/* Set everything up and remember that we have. */ +int +__malloc_initialize () +{ + if (__malloc_initialized) + return 0; + + if (__malloc_initialize_hook) + (*__malloc_initialize_hook) (); + + heapsize = HEAP / BLOCKSIZE; + _heapinfo = (malloc_info *) align (heapsize * sizeof (malloc_info)); + if (_heapinfo == NULL) + return 0; + memset (_heapinfo, 0, heapsize * sizeof (malloc_info)); + _heapinfo[0].free.size = 0; + _heapinfo[0].free.next = _heapinfo[0].free.prev = 0; + _heapindex = 0; + _heapbase = (char *) _heapinfo; + _heaplimit = BLOCK (_heapbase + heapsize * sizeof (malloc_info)); + + register_heapinfo (); + + __malloc_initialized = 1; + return 1; +} + +static int morecore_recursing; + +/* Get neatly aligned memory, initializing or + growing the heap info table as necessary. */ +static __ptr_t morecore __P ((__malloc_size_t)); +static __ptr_t +morecore (size) + __malloc_size_t size; +{ + __ptr_t result; + malloc_info *newinfo, *oldinfo; + __malloc_size_t newsize; + + if (morecore_recursing) + /* Avoid recursion. The caller will know how to handle a null return. */ + return NULL; + + result = align (size); + if (result == NULL) + return NULL; + + /* Check if we need to grow the info table. */ + if ((__malloc_size_t) BLOCK ((char *) result + size) > heapsize) + { + /* Calculate the new _heapinfo table size. We do not account for the + added blocks in the table itself, as we hope to place them in + existing free space, which is already covered by part of the + existing table. */ + newsize = heapsize; + do + newsize *= 2; + while ((__malloc_size_t) BLOCK ((char *) result + size) > newsize); + + /* We must not reuse existing core for the new info table when called + from realloc in the case of growing a large block, because the + block being grown is momentarily marked as free. In this case + _heaplimit is zero so we know not to reuse space for internal + allocation. */ + if (_heaplimit != 0) + { + /* First try to allocate the new info table in core we already + have, in the usual way using realloc. If realloc cannot + extend it in place or relocate it to existing sufficient core, + we will get called again, and the code above will notice the + `morecore_recursing' flag and return null. */ + int save = errno; /* Don't want to clobber errno with ENOMEM. */ + morecore_recursing = 1; + newinfo = (malloc_info *) _realloc_internal + (_heapinfo, newsize * sizeof (malloc_info)); + morecore_recursing = 0; + if (newinfo == NULL) + errno = save; + else + { + /* We found some space in core, and realloc has put the old + table's blocks on the free list. Now zero the new part + of the table and install the new table location. */ + memset (&newinfo[heapsize], 0, + (newsize - heapsize) * sizeof (malloc_info)); + _heapinfo = newinfo; + heapsize = newsize; + goto got_heap; + } + } + + /* Allocate new space for the malloc info table. */ + while (1) + { + newinfo = (malloc_info *) align (newsize * sizeof (malloc_info)); + + /* Did it fail? */ + if (newinfo == NULL) + { + (*__morecore) (-size); + return NULL; + } + + /* Is it big enough to record status for its own space? + If so, we win. */ + if ((__malloc_size_t) BLOCK ((char *) newinfo + + newsize * sizeof (malloc_info)) + < newsize) + break; + + /* Must try again. First give back most of what we just got. */ + (*__morecore) (- newsize * sizeof (malloc_info)); + newsize *= 2; + } + + /* Copy the old table to the beginning of the new, + and zero the rest of the new table. */ + memcpy (newinfo, _heapinfo, heapsize * sizeof (malloc_info)); + memset (&newinfo[heapsize], 0, + (newsize - heapsize) * sizeof (malloc_info)); + oldinfo = _heapinfo; + _heapinfo = newinfo; + heapsize = newsize; + + register_heapinfo (); + + /* Reset _heaplimit so _free_internal never decides + it can relocate or resize the info table. */ + _heaplimit = 0; + _free_internal (oldinfo); + + /* The new heap limit includes the new table just allocated. */ + _heaplimit = BLOCK ((char *) newinfo + heapsize * sizeof (malloc_info)); + return result; + } + + got_heap: + _heaplimit = BLOCK ((char *) result + size); + return result; +} + +/* Allocate memory from the heap. */ +__ptr_t +_malloc_internal (size) + __malloc_size_t size; +{ + __ptr_t result; + __malloc_size_t block, blocks, lastblocks, start; + register __malloc_size_t i; + struct list *next; + + /* ANSI C allows `malloc (0)' to either return NULL, or to return a + valid address you can realloc and free (though not dereference). + + It turns out that some extant code (sunrpc, at least Ultrix's version) + expects `malloc (0)' to return non-NULL and breaks otherwise. + Be compatible. */ + +#if 0 + if (size == 0) + return NULL; +#endif + + if (size < sizeof (struct list)) + size = sizeof (struct list); + +#ifdef SUNOS_LOCALTIME_BUG + if (size < 16) + size = 16; +#endif + + /* Determine the allocation policy based on the request size. */ + if (size <= BLOCKSIZE / 2) + { + /* Small allocation to receive a fragment of a block. + Determine the logarithm to base two of the fragment size. */ + register __malloc_size_t log = 1; + --size; + while ((size /= 2) != 0) + ++log; + + /* Look in the fragment lists for a + free fragment of the desired size. */ + next = _fraghead[log].next; + if (next != NULL) + { + /* There are free fragments of this size. + Pop a fragment out of the fragment list and return it. + Update the block's nfree and first counters. */ + result = (__ptr_t) next; + next->prev->next = next->next; + if (next->next != NULL) + next->next->prev = next->prev; + block = BLOCK (result); + if (--_heapinfo[block].busy.info.frag.nfree != 0) + _heapinfo[block].busy.info.frag.first = (unsigned long int) + ((unsigned long int) ((char *) next->next - (char *) NULL) + % BLOCKSIZE) >> log; + + /* Update the statistics. */ + ++_chunks_used; + _bytes_used += 1 << log; + --_chunks_free; + _bytes_free -= 1 << log; + } + else + { + /* No free fragments of the desired size, so get a new block + and break it into fragments, returning the first. */ + result = malloc (BLOCKSIZE); + if (result == NULL) + return NULL; + + /* Link all fragments but the first into the free list. */ + next = (struct list *) ((char *) result + (1 << log)); + next->next = NULL; + next->prev = &_fraghead[log]; + _fraghead[log].next = next; + + for (i = 2; i < (__malloc_size_t) (BLOCKSIZE >> log); ++i) + { + next = (struct list *) ((char *) result + (i << log)); + next->next = _fraghead[log].next; + next->prev = &_fraghead[log]; + next->prev->next = next; + next->next->prev = next; + } + + /* Initialize the nfree and first counters for this block. */ + block = BLOCK (result); + _heapinfo[block].busy.type = log; + _heapinfo[block].busy.info.frag.nfree = i - 1; + _heapinfo[block].busy.info.frag.first = i - 1; + + _chunks_free += (BLOCKSIZE >> log) - 1; + _bytes_free += BLOCKSIZE - (1 << log); + _bytes_used -= BLOCKSIZE - (1 << log); + } + } + else + { + /* Large allocation to receive one or more blocks. + Search the free list in a circle starting at the last place visited. + If we loop completely around without finding a large enough + space we will have to get more memory from the system. */ + blocks = BLOCKIFY (size); + start = block = _heapindex; + while (_heapinfo[block].free.size < blocks) + { + block = _heapinfo[block].free.next; + if (block == start) + { + /* Need to get more from the system. Get a little extra. */ + __malloc_size_t wantblocks = blocks + __malloc_extra_blocks; + block = _heapinfo[0].free.prev; + lastblocks = _heapinfo[block].free.size; + /* Check to see if the new core will be contiguous with the + final free block; if so we don't need to get as much. */ + if (_heaplimit != 0 && block + lastblocks == _heaplimit && + /* We can't do this if we will have to make the heap info + table bigger to accomodate the new space. */ + block + wantblocks <= heapsize && + get_contiguous_space ((wantblocks - lastblocks) * BLOCKSIZE, + ADDRESS (block + lastblocks))) + { + /* We got it contiguously. Which block we are extending + (the `final free block' referred to above) might have + changed, if it got combined with a freed info table. */ + block = _heapinfo[0].free.prev; + _heapinfo[block].free.size += (wantblocks - lastblocks); + _bytes_free += (wantblocks - lastblocks) * BLOCKSIZE; + _heaplimit += wantblocks - lastblocks; + continue; + } + result = morecore (wantblocks * BLOCKSIZE); + if (result == NULL) + return NULL; + block = BLOCK (result); + /* Put the new block at the end of the free list. */ + _heapinfo[block].free.size = wantblocks; + _heapinfo[block].free.prev = _heapinfo[0].free.prev; + _heapinfo[block].free.next = 0; + _heapinfo[0].free.prev = block; + _heapinfo[_heapinfo[block].free.prev].free.next = block; + ++_chunks_free; + /* Now loop to use some of that block for this allocation. */ + } + } + + /* At this point we have found a suitable free list entry. + Figure out how to remove what we need from the list. */ + result = ADDRESS (block); + if (_heapinfo[block].free.size > blocks) + { + /* The block we found has a bit left over, + so relink the tail end back into the free list. */ + _heapinfo[block + blocks].free.size + = _heapinfo[block].free.size - blocks; + _heapinfo[block + blocks].free.next + = _heapinfo[block].free.next; + _heapinfo[block + blocks].free.prev + = _heapinfo[block].free.prev; + _heapinfo[_heapinfo[block].free.prev].free.next + = _heapinfo[_heapinfo[block].free.next].free.prev + = _heapindex = block + blocks; + } + else + { + /* The block exactly matches our requirements, + so just remove it from the list. */ + _heapinfo[_heapinfo[block].free.next].free.prev + = _heapinfo[block].free.prev; + _heapinfo[_heapinfo[block].free.prev].free.next + = _heapindex = _heapinfo[block].free.next; + --_chunks_free; + } + + _heapinfo[block].busy.type = 0; + _heapinfo[block].busy.info.size = blocks; + ++_chunks_used; + _bytes_used += blocks * BLOCKSIZE; + _bytes_free -= blocks * BLOCKSIZE; + + /* Mark all the blocks of the object just allocated except for the + first with a negative number so you can find the first block by + adding that adjustment. */ + while (--blocks > 0) + _heapinfo[block + blocks].busy.info.size = -blocks; + } + + return result; +} + +__ptr_t +malloc (size) + __malloc_size_t size; +{ + if (!__malloc_initialized && !__malloc_initialize ()) + return NULL; + + return (__malloc_hook != NULL ? *__malloc_hook : _malloc_internal) (size); +} + +#ifndef _LIBC + +/* On some ANSI C systems, some libc functions call _malloc, _free + and _realloc. Make them use the GNU functions. */ + +__ptr_t +_malloc (size) + __malloc_size_t size; +{ + return malloc (size); +} + +void +_free (ptr) + __ptr_t ptr; +{ + free (ptr); +} + +__ptr_t +_realloc (ptr, size) + __ptr_t ptr; + __malloc_size_t size; +{ + return realloc (ptr, size); +} + +#endif +/* Free a block of memory allocated by `malloc'. + Copyright 1990, 1991, 1992, 1994, 1995 Free Software Foundation, Inc. + Written May 1989 by Mike Haertel. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. + + The author may be reached (Email) at the address mike@ai.mit.edu, + or (US mail) as Mike Haertel c/o Free Software Foundation. */ + +#ifndef _MALLOC_INTERNAL +#define _MALLOC_INTERNAL +#include <malloc.h> +#endif + + +/* Cope with systems lacking `memmove'. */ +#ifndef memmove +#if (defined (MEMMOVE_MISSING) || \ + !defined(_LIBC) && !defined(STDC_HEADERS) && !defined(USG)) +#ifdef emacs +#undef __malloc_safe_bcopy +#define __malloc_safe_bcopy safe_bcopy +#endif +/* This function is defined in realloc.c. */ +extern void __malloc_safe_bcopy __P ((__ptr_t, __ptr_t, __malloc_size_t)); +#define memmove(to, from, size) __malloc_safe_bcopy ((from), (to), (size)) +#endif +#endif + + +/* Debugging hook for free. */ +void (*__free_hook) __P ((__ptr_t __ptr)); + +/* List of blocks allocated by memalign. */ +struct alignlist *_aligned_blocks = NULL; + +/* Return memory to the heap. + Like `free' but don't call a __free_hook if there is one. */ +void +_free_internal (ptr) + __ptr_t ptr; +{ + int type; + __malloc_size_t block, blocks; + register __malloc_size_t i; + struct list *prev, *next; + __ptr_t curbrk; + const __malloc_size_t lesscore_threshold + /* Threshold of free space at which we will return some to the system. */ + = FINAL_FREE_BLOCKS + 2 * __malloc_extra_blocks; + + register struct alignlist *l; + + if (ptr == NULL) + return; + + for (l = _aligned_blocks; l != NULL; l = l->next) + if (l->aligned == ptr) + { + l->aligned = NULL; /* Mark the slot in the list as free. */ + ptr = l->exact; + break; + } + + block = BLOCK (ptr); + + type = _heapinfo[block].busy.type; + switch (type) + { + case 0: + /* Get as many statistics as early as we can. */ + --_chunks_used; + _bytes_used -= _heapinfo[block].busy.info.size * BLOCKSIZE; + _bytes_free += _heapinfo[block].busy.info.size * BLOCKSIZE; + + /* Find the free cluster previous to this one in the free list. + Start searching at the last block referenced; this may benefit + programs with locality of allocation. */ + i = _heapindex; + if (i > block) + while (i > block) + i = _heapinfo[i].free.prev; + else + { + do + i = _heapinfo[i].free.next; + while (i > 0 && i < block); + i = _heapinfo[i].free.prev; + } + + /* Determine how to link this block into the free list. */ + if (block == i + _heapinfo[i].free.size) + { + /* Coalesce this block with its predecessor. */ + _heapinfo[i].free.size += _heapinfo[block].busy.info.size; + block = i; + } + else + { + /* Really link this block back into the free list. */ + _heapinfo[block].free.size = _heapinfo[block].busy.info.size; + _heapinfo[block].free.next = _heapinfo[i].free.next; + _heapinfo[block].free.prev = i; + _heapinfo[i].free.next = block; + _heapinfo[_heapinfo[block].free.next].free.prev = block; + ++_chunks_free; + } + + /* Now that the block is linked in, see if we can coalesce it + with its successor (by deleting its successor from the list + and adding in its size). */ + if (block + _heapinfo[block].free.size == _heapinfo[block].free.next) + { + _heapinfo[block].free.size + += _heapinfo[_heapinfo[block].free.next].free.size; + _heapinfo[block].free.next + = _heapinfo[_heapinfo[block].free.next].free.next; + _heapinfo[_heapinfo[block].free.next].free.prev = block; + --_chunks_free; + } + + /* How many trailing free blocks are there now? */ + blocks = _heapinfo[block].free.size; + + /* Where is the current end of accessible core? */ + curbrk = (*__morecore) (0); + + if (_heaplimit != 0 && curbrk == ADDRESS (_heaplimit)) + { + /* The end of the malloc heap is at the end of accessible core. + It's possible that moving _heapinfo will allow us to + return some space to the system. */ + + __malloc_size_t info_block = BLOCK (_heapinfo); + __malloc_size_t info_blocks = _heapinfo[info_block].busy.info.size; + __malloc_size_t prev_block = _heapinfo[block].free.prev; + __malloc_size_t prev_blocks = _heapinfo[prev_block].free.size; + __malloc_size_t next_block = _heapinfo[block].free.next; + __malloc_size_t next_blocks = _heapinfo[next_block].free.size; + + if (/* Win if this block being freed is last in core, the info table + is just before it, the previous free block is just before the + info table, and the two free blocks together form a useful + amount to return to the system. */ + (block + blocks == _heaplimit && + info_block + info_blocks == block && + prev_block != 0 && prev_block + prev_blocks == info_block && + blocks + prev_blocks >= lesscore_threshold) || + /* Nope, not the case. We can also win if this block being + freed is just before the info table, and the table extends + to the end of core or is followed only by a free block, + and the total free space is worth returning to the system. */ + (block + blocks == info_block && + ((info_block + info_blocks == _heaplimit && + blocks >= lesscore_threshold) || + (info_block + info_blocks == next_block && + next_block + next_blocks == _heaplimit && + blocks + next_blocks >= lesscore_threshold))) + ) + { + malloc_info *newinfo; + __malloc_size_t oldlimit = _heaplimit; + + /* Free the old info table, clearing _heaplimit to avoid + recursion into this code. We don't want to return the + table's blocks to the system before we have copied them to + the new location. */ + _heaplimit = 0; + _free_internal (_heapinfo); + _heaplimit = oldlimit; + + /* Tell malloc to search from the beginning of the heap for + free blocks, so it doesn't reuse the ones just freed. */ + _heapindex = 0; + + /* Allocate new space for the info table and move its data. */ + newinfo = (malloc_info *) _malloc_internal (info_blocks + * BLOCKSIZE); + memmove (newinfo, _heapinfo, info_blocks * BLOCKSIZE); + _heapinfo = newinfo; + + /* We should now have coalesced the free block with the + blocks freed from the old info table. Examine the entire + trailing free block to decide below whether to return some + to the system. */ + block = _heapinfo[0].free.prev; + blocks = _heapinfo[block].free.size; + } + + /* Now see if we can return stuff to the system. */ + if (block + blocks == _heaplimit && blocks >= lesscore_threshold) + { + register __malloc_size_t bytes = blocks * BLOCKSIZE; + _heaplimit -= blocks; + (*__morecore) (-bytes); + _heapinfo[_heapinfo[block].free.prev].free.next + = _heapinfo[block].free.next; + _heapinfo[_heapinfo[block].free.next].free.prev + = _heapinfo[block].free.prev; + block = _heapinfo[block].free.prev; + --_chunks_free; + _bytes_free -= bytes; + } + } + + /* Set the next search to begin at this block. */ + _heapindex = block; + break; + + default: + /* Do some of the statistics. */ + --_chunks_used; + _bytes_used -= 1 << type; + ++_chunks_free; + _bytes_free += 1 << type; + + /* Get the address of the first free fragment in this block. */ + prev = (struct list *) ((char *) ADDRESS (block) + + (_heapinfo[block].busy.info.frag.first << type)); + + if (_heapinfo[block].busy.info.frag.nfree == (BLOCKSIZE >> type) - 1) + { + /* If all fragments of this block are free, remove them + from the fragment list and free the whole block. */ + next = prev; + for (i = 1; i < (__malloc_size_t) (BLOCKSIZE >> type); ++i) + next = next->next; + prev->prev->next = next; + if (next != NULL) + next->prev = prev->prev; + _heapinfo[block].busy.type = 0; + _heapinfo[block].busy.info.size = 1; + + /* Keep the statistics accurate. */ + ++_chunks_used; + _bytes_used += BLOCKSIZE; + _chunks_free -= BLOCKSIZE >> type; + _bytes_free -= BLOCKSIZE; + + free (ADDRESS (block)); + } + else if (_heapinfo[block].busy.info.frag.nfree != 0) + { + /* If some fragments of this block are free, link this + fragment into the fragment list after the first free + fragment of this block. */ + next = (struct list *) ptr; + next->next = prev->next; + next->prev = prev; + prev->next = next; + if (next->next != NULL) + next->next->prev = next; + ++_heapinfo[block].busy.info.frag.nfree; + } + else + { + /* No fragments of this block are free, so link this + fragment into the fragment list and announce that + it is the first free fragment of this block. */ + prev = (struct list *) ptr; + _heapinfo[block].busy.info.frag.nfree = 1; + _heapinfo[block].busy.info.frag.first = (unsigned long int) + ((unsigned long int) ((char *) ptr - (char *) NULL) + % BLOCKSIZE >> type); + prev->next = _fraghead[type].next; + prev->prev = &_fraghead[type]; + prev->prev->next = prev; + if (prev->next != NULL) + prev->next->prev = prev; + } + break; + } +} + +/* Return memory to the heap. */ +void +free (ptr) + __ptr_t ptr; +{ + if (__free_hook != NULL) + (*__free_hook) (ptr); + else + _free_internal (ptr); +} + +/* Define the `cfree' alias for `free'. */ +#ifdef weak_alias +weak_alias (free, cfree) +#else +void +cfree (ptr) + __ptr_t ptr; +{ + free (ptr); +} +#endif +/* Change the size of a block allocated by `malloc'. + Copyright 1990, 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. + Written May 1989 by Mike Haertel. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. + + The author may be reached (Email) at the address mike@ai.mit.edu, + or (US mail) as Mike Haertel c/o Free Software Foundation. */ + +#ifndef _MALLOC_INTERNAL +#define _MALLOC_INTERNAL +#include <malloc.h> +#endif + + + +/* Cope with systems lacking `memmove'. */ +#if (defined (MEMMOVE_MISSING) || \ + !defined(_LIBC) && !defined(STDC_HEADERS) && !defined(USG)) + +#ifdef emacs +#undef __malloc_safe_bcopy +#define __malloc_safe_bcopy safe_bcopy +#else + +/* Snarfed directly from Emacs src/dispnew.c: + XXX Should use system bcopy if it handles overlap. */ + +/* Like bcopy except never gets confused by overlap. */ + +void +__malloc_safe_bcopy (afrom, ato, size) + __ptr_t afrom; + __ptr_t ato; + __malloc_size_t size; +{ + char *from = afrom, *to = ato; + + if (size <= 0 || from == to) + return; + + /* If the source and destination don't overlap, then bcopy can + handle it. If they do overlap, but the destination is lower in + memory than the source, we'll assume bcopy can handle that. */ + if (to < from || from + size <= to) + bcopy (from, to, size); + + /* Otherwise, we'll copy from the end. */ + else + { + register char *endf = from + size; + register char *endt = to + size; + + /* If TO - FROM is large, then we should break the copy into + nonoverlapping chunks of TO - FROM bytes each. However, if + TO - FROM is small, then the bcopy function call overhead + makes this not worth it. The crossover point could be about + anywhere. Since I don't think the obvious copy loop is too + bad, I'm trying to err in its favor. */ + if (to - from < 64) + { + do + *--endt = *--endf; + while (endf != from); + } + else + { + for (;;) + { + endt -= (to - from); + endf -= (to - from); + + if (endt < to) + break; + + bcopy (endf, endt, to - from); + } + + /* If SIZE wasn't a multiple of TO - FROM, there will be a + little left over. The amount left over is + (endt + (to - from)) - to, which is endt - from. */ + bcopy (from, to, endt - from); + } + } +} +#endif /* emacs */ + +#ifndef memmove +extern void __malloc_safe_bcopy __P ((__ptr_t, __ptr_t, __malloc_size_t)); +#define memmove(to, from, size) __malloc_safe_bcopy ((from), (to), (size)) +#endif + +#endif + + +#define min(A, B) ((A) < (B) ? (A) : (B)) + +/* Debugging hook for realloc. */ +__ptr_t (*__realloc_hook) __P ((__ptr_t __ptr, __malloc_size_t __size)); + +/* Resize the given region to the new size, returning a pointer + to the (possibly moved) region. This is optimized for speed; + some benchmarks seem to indicate that greater compactness is + achieved by unconditionally allocating and copying to a + new region. This module has incestuous knowledge of the + internals of both free and malloc. */ +__ptr_t +_realloc_internal (ptr, size) + __ptr_t ptr; + __malloc_size_t size; +{ + __ptr_t result; + int type; + __malloc_size_t block, blocks, oldlimit; + + if (size == 0) + { + _free_internal (ptr); + return _malloc_internal (0); + } + else if (ptr == NULL) + return _malloc_internal (size); + + block = BLOCK (ptr); + + type = _heapinfo[block].busy.type; + switch (type) + { + case 0: + /* Maybe reallocate a large block to a small fragment. */ + if (size <= BLOCKSIZE / 2) + { + result = _malloc_internal (size); + if (result != NULL) + { + memcpy (result, ptr, size); + _free_internal (ptr); + return result; + } + } + + /* The new size is a large allocation as well; + see if we can hold it in place. */ + blocks = BLOCKIFY (size); + if (blocks < _heapinfo[block].busy.info.size) + { + /* The new size is smaller; return + excess memory to the free list. */ + _heapinfo[block + blocks].busy.type = 0; + _heapinfo[block + blocks].busy.info.size + = _heapinfo[block].busy.info.size - blocks; + _heapinfo[block].busy.info.size = blocks; + /* We have just created a new chunk by splitting a chunk in two. + Now we will free this chunk; increment the statistics counter + so it doesn't become wrong when _free_internal decrements it. */ + ++_chunks_used; + _free_internal (ADDRESS (block + blocks)); + result = ptr; + } + else if (blocks == _heapinfo[block].busy.info.size) + /* No size change necessary. */ + result = ptr; + else + { + /* Won't fit, so allocate a new region that will. + Free the old region first in case there is sufficient + adjacent free space to grow without moving. */ + blocks = _heapinfo[block].busy.info.size; + /* Prevent free from actually returning memory to the system. */ + oldlimit = _heaplimit; + _heaplimit = 0; + _free_internal (ptr); + result = _malloc_internal (size); + if (_heaplimit == 0) + _heaplimit = oldlimit; + if (result == NULL) + { + /* Now we're really in trouble. We have to unfree + the thing we just freed. Unfortunately it might + have been coalesced with its neighbors. */ + if (_heapindex == block) + (void) _malloc_internal (blocks * BLOCKSIZE); + else + { + __ptr_t previous + = _malloc_internal ((block - _heapindex) * BLOCKSIZE); + (void) _malloc_internal (blocks * BLOCKSIZE); + _free_internal (previous); + } + return NULL; + } + if (ptr != result) + memmove (result, ptr, blocks * BLOCKSIZE); + } + break; + + default: + /* Old size is a fragment; type is logarithm + to base two of the fragment size. */ + if (size > (__malloc_size_t) (1 << (type - 1)) && + size <= (__malloc_size_t) (1 << type)) + /* The new size is the same kind of fragment. */ + result = ptr; + else + { + /* The new size is different; allocate a new space, + and copy the lesser of the new size and the old. */ + result = _malloc_internal (size); + if (result == NULL) + return NULL; + memcpy (result, ptr, min (size, (__malloc_size_t) 1 << type)); + _free_internal (ptr); + } + break; + } + + return result; +} + +__ptr_t +realloc (ptr, size) + __ptr_t ptr; + __malloc_size_t size; +{ + if (!__malloc_initialized && !__malloc_initialize ()) + return NULL; + + return (__realloc_hook != NULL ? *__realloc_hook : _realloc_internal) + (ptr, size); +} +/* Copyright (C) 1991, 1992, 1994 Free Software Foundation, Inc. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. + + The author may be reached (Email) at the address mike@ai.mit.edu, + or (US mail) as Mike Haertel c/o Free Software Foundation. */ + +#ifndef _MALLOC_INTERNAL +#define _MALLOC_INTERNAL +#include <malloc.h> +#endif + +/* Allocate an array of NMEMB elements each SIZE bytes long. + The entire array is initialized to zeros. */ +__ptr_t +calloc (nmemb, size) + register __malloc_size_t nmemb; + register __malloc_size_t size; +{ + register __ptr_t result = malloc (nmemb * size); + + if (result != NULL) + (void) memset (result, 0, nmemb * size); + + return result; +} +/* Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the GNU C Library; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef _MALLOC_INTERNAL +#define _MALLOC_INTERNAL +#include <malloc.h> +#endif + +#ifndef __GNU_LIBRARY__ +#define __sbrk sbrk +#endif + +#ifdef __GNU_LIBRARY__ +/* It is best not to declare this and cast its result on foreign operating + systems with potentially hostile include files. */ + +#include <stddef.h> +extern __ptr_t __sbrk __P ((ptrdiff_t increment)); +#endif + +#ifndef NULL +#define NULL 0 +#endif + +/* Allocate INCREMENT more bytes of data space, + and return the start of data space, or NULL on errors. + If INCREMENT is negative, shrink data space. */ +__ptr_t +__default_morecore (increment) + __malloc_ptrdiff_t increment; +{ + __ptr_t result = (__ptr_t) __sbrk (increment); + if (result == (__ptr_t) -1) + return NULL; + return result; +} +/* Copyright (C) 1991, 92, 93, 94, 95, 96 Free Software Foundation, Inc. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#ifndef _MALLOC_INTERNAL +#define _MALLOC_INTERNAL +#include <malloc.h> +#endif + +#if __DJGPP__ - 0 == 1 + +/* There is some problem with memalign in DJGPP v1 and we are supposed + to omit it. Noone told me why, they just told me to do it. */ + +#else + +__ptr_t (*__memalign_hook) __P ((size_t __size, size_t __alignment)); + +__ptr_t +memalign (alignment, size) + __malloc_size_t alignment; + __malloc_size_t size; +{ + __ptr_t result; + unsigned long int adj, lastadj; + + if (__memalign_hook) + return (*__memalign_hook) (alignment, size); + + /* Allocate a block with enough extra space to pad the block with up to + (ALIGNMENT - 1) bytes if necessary. */ + result = malloc (size + alignment - 1); + if (result == NULL) + return NULL; + + /* Figure out how much we will need to pad this particular block + to achieve the required alignment. */ + adj = (unsigned long int) ((char *) result - (char *) NULL) % alignment; + + do + { + /* Reallocate the block with only as much excess as it needs. */ + free (result); + result = malloc (adj + size); + if (result == NULL) /* Impossible unless interrupted. */ + return NULL; + + lastadj = adj; + adj = (unsigned long int) ((char *) result - (char *) NULL) % alignment; + /* It's conceivable we might have been so unlucky as to get a + different block with weaker alignment. If so, this block is too + short to contain SIZE after alignment correction. So we must + try again and get another block, slightly larger. */ + } while (adj > lastadj); + + if (adj != 0) + { + /* Record this block in the list of aligned blocks, so that `free' + can identify the pointer it is passed, which will be in the middle + of an allocated block. */ + + struct alignlist *l; + for (l = _aligned_blocks; l != NULL; l = l->next) + if (l->aligned == NULL) + /* This slot is free. Use it. */ + break; + if (l == NULL) + { + l = (struct alignlist *) malloc (sizeof (struct alignlist)); + if (l == NULL) + { + free (result); + return NULL; + } + l->next = _aligned_blocks; + _aligned_blocks = l; + } + l->exact = result; + result = l->aligned = (char *) result + alignment - adj; + } + + return result; +} + +#endif /* Not DJGPP v1 */ diff --git a/lib/malloc/omalloc.c b/lib/malloc/omalloc.c new file mode 100644 index 00000000..a8b232a1 --- /dev/null +++ b/lib/malloc/omalloc.c @@ -0,0 +1,759 @@ +/* dynamic memory allocation for GNU. */ + +/* Copyright (C) 1985, 1987 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 1, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +In other words, you are welcome to use, share and improve this program. +You are forbidden to forbid anyone else to use, share and improve +what you give them. Help stamp out software-hoarding! */ + +/* + * @(#)nmalloc.c 1 (Caltech) 2/21/82 + * + * U of M Modified: 20 Jun 1983 ACT: strange hacks for Emacs + * + * Nov 1983, Mike@BRL, Added support for 4.1C/4.2 BSD. + * + * This is a very fast storage allocator. It allocates blocks of a small + * number of different sizes, and keeps free lists of each size. Blocks + * that don't exactly fit are passed up to the next larger size. In this + * implementation, the available sizes are (2^n)-4 (or -16) bytes long. + * This is designed for use in a program that uses vast quantities of + * memory, but bombs when it runs out. To make it a little better, it + * warns the user when he starts to get near the end. + * + * June 84, ACT: modified rcheck code to check the range given to malloc, + * rather than the range determined by the 2-power used. + * + * Jan 85, RMS: calls malloc_warning to issue warning on nearly full. + * No longer Emacs-specific; can serve as all-purpose malloc for GNU. + * You should call malloc_init to reinitialize after loading dumped Emacs. + * Call malloc_stats to get info on memory stats if MSTATS turned on. + * realloc knows how to return same block given, just changing its size, + * if the power of 2 is correct. + */ + +/* + * nextf[i] is the pointer to the next free block of size 2^(i+3). The + * smallest allocatable block is 8 bytes. The overhead information will + * go in the first int of the block, and the returned pointer will point + * to the second. + * +#ifdef MSTATS + * nmalloc[i] is the difference between the number of mallocs and frees + * for a given block size. +#endif + */ + +/* Define this to have free() write 0xcf into memory as it's freed, to + uncover callers that refer to freed memory. */ +/* SCO 3.2v4 getcwd and possibly other libc routines fail with MEMSCRAMBLE */ +#if !defined (NO_MEMSCRAMBLE) +# define MEMSCRAMBLE +#endif + +#if defined (emacs) || defined (HAVE_CONFIG_H) +# include <config.h> +#endif /* emacs */ + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#endif + +/* Determine which kind of system this is. */ +#if defined (SHELL) +# include "bashtypes.h" +#else +# include <sys/types.h> +#endif +#include <signal.h> + +/* Define getpagesize () if the system does not. */ +#ifndef HAVE_GETPAGESIZE +# include "getpagesize.h" +#endif + +#if defined (HAVE_RESOURCE) +# include <sys/time.h> +# include <sys/resource.h> +#endif /* HAVE_RESOURCE */ + +/* Check for the needed symbols. If they aren't present, this + system's <sys/resource.h> isn't very useful to us. */ +#if !defined (RLIMIT_DATA) +# undef HAVE_RESOURCE +#endif + +#if __GNUC__ > 1 +# define FASTCOPY(s, d, n) __builtin_memcpy (d, s, n) +#else /* !__GNUC__ */ +# if !defined (HAVE_BCOPY) +# if !defined (HAVE_MEMMOVE) +# define FASTCOPY(s, d, n) memcpy (d, s, n) +# else +# define FASTCOPY(s, d, n) memmove (d, s, n) +# endif /* !HAVE_MEMMOVE */ +# else /* HAVE_BCOPY */ +# define FASTCOPY(s, d, n) bcopy (s, d, n) +# endif /* HAVE_BCOPY */ +#endif /* !__GNUC__ */ + +#if !defined (NULL) +# define NULL 0 +#endif + +#define start_of_data() &etext + +#define ISALLOC ((char) 0xf7) /* magic byte that implies allocation */ +#define ISFREE ((char) 0x54) /* magic byte that implies free block */ + /* this is for error checking only */ +#define ISMEMALIGN ((char) 0xd6) /* Stored before the value returned by + memalign, with the rest of the word + being the distance to the true + beginning of the block. */ +extern char etext; + +#if !defined (SBRK_DECLARED) +extern char *sbrk (); +#endif /* !SBRK_DECLARED */ + +/* These two are for user programs to look at, when they are interested. */ +unsigned int malloc_sbrk_used; /* amount of data space used now */ +unsigned int malloc_sbrk_unused; /* amount more we can have */ + +/* start of data space; can be changed by calling init_malloc */ +static char *data_space_start; + +static void get_lim_data (); + +#ifdef MSTATS +static int nmalloc[30]; +static int nmal, nfre; +#endif /* MSTATS */ + +/* If range checking is not turned on, all we have is a flag indicating + whether memory is allocated, an index in nextf[], and a size field; to + realloc() memory we copy either size bytes or 1<<(index+3) bytes depending + on whether the former can hold the exact size (given the value of + 'index'). If range checking is on, we always need to know how much space + is allocated, so the 'size' field is never used. */ + +struct mhead { + char mh_alloc; /* ISALLOC or ISFREE */ + char mh_index; /* index in nextf[] */ +/* Remainder are valid only when block is allocated */ + unsigned short mh_size; /* size, if < 0x10000 */ +#ifdef RCHECK + unsigned int mh_nbytes; /* number of bytes allocated */ + int mh_magic4; /* should be == MAGIC4 */ +#endif /* RCHECK */ +}; + +/* Access free-list pointer of a block. + It is stored at block + 4. + This is not a field in the mhead structure + because we want sizeof (struct mhead) + to describe the overhead for when the block is in use, + and we do not want the free-list pointer to count in that. */ + +#define CHAIN(a) \ + (*(struct mhead **) (sizeof (char *) + (char *) (a))) + +#ifdef RCHECK +# include <stdio.h> +# if !defined (botch) +# define botch(x) abort () +# else +extern void botch(); +# endif /* botch */ + +# if !defined (__STRING) +# if defined (__STDC__) +# define __STRING(x) #x +# else +# define __STRING(x) "x" +# endif +# endif + + /* To implement range checking, we write magic values in at the beginning + and end of each allocated block, and make sure they are undisturbed + whenever a free or a realloc occurs. */ + + /* Written in each of the 4 bytes following the block's real space */ +# define MAGIC1 0x55 + /* Written in the 4 bytes before the block's real space */ +# define MAGIC4 0x55555555 +# define ASSERT(p) if (!(p)) botch(__STRING(p)); else +# define EXTRA 4 /* 4 bytes extra for MAGIC1s */ +#else /* !RCHECK */ +# define ASSERT(p) +# define EXTRA 0 +#endif /* RCHECK */ + +/* nextf[i] is free list of blocks of size 2**(i + 3) */ + +static struct mhead *nextf[30]; + +/* busy[i] is nonzero while allocation of block size i is in progress. */ + +static char busy[30]; + +/* Number of bytes of writable memory we can expect to be able to get */ +static unsigned int lim_data; + +/* Level number of warnings already issued. + 0 -- no warnings issued. + 1 -- 75% warning already issued. + 2 -- 85% warning already issued. +*/ +static int warnlevel; + +/* Function to call to issue a warning; + 0 means don't issue them. */ +static void (*warnfunction) (); + +/* nonzero once initial bunch of free blocks made */ +static int gotpool; + +char *_malloc_base; + +static void getpool (); + +/* Cause reinitialization based on job parameters; + also declare where the end of pure storage is. */ +void +malloc_init (start, warnfun) + char *start; + void (*warnfun) (); +{ + if (start) + data_space_start = start; + lim_data = 0; + warnlevel = 0; + warnfunction = warnfun; +} + +/* Return the maximum size to which MEM can be realloc'd + without actually requiring copying. */ + +int +malloc_usable_size (mem) + char *mem; +{ + int blocksize = 8 << (((struct mhead *) mem) - 1) -> mh_index; + + return blocksize - sizeof (struct mhead) - EXTRA; +} + +static void +morecore (nu) /* ask system for more memory */ + register int nu; /* size index to get more of */ +{ + register char *cp; + register int nblks; + register unsigned int siz; + + /* Block all signals in case we are executed from a signal handler. */ +#if defined (HAVE_BSD_SIGNALS) + int oldmask; + oldmask = sigsetmask (-1); +#else +# if defined (HAVE_POSIX_SIGNALS) + sigset_t set, oset; + sigfillset (&set); + sigemptyset (&oset); + sigprocmask (SIG_BLOCK, &set, &oset); +# endif /* HAVE_POSIX_SIGNALS */ +#endif /* HAVE_BSD_SIGNALS */ + + if (!data_space_start) + { + data_space_start = start_of_data (); + } + + if (lim_data == 0) + get_lim_data (); + + /* On initial startup, get two blocks of each size up to 1k bytes */ + if (!gotpool) + { getpool (); getpool (); gotpool = 1; } + + /* Find current end of memory and issue warning if getting near max */ + + cp = sbrk (0); + siz = cp - data_space_start; + malloc_sbrk_used = siz; + malloc_sbrk_unused = lim_data - siz; + + if (warnfunction) + switch (warnlevel) + { + case 0: + if (siz > (lim_data / 4) * 3) + { + warnlevel++; + (*warnfunction) ("Warning: past 75% of memory limit"); + } + break; + case 1: + if (siz > (lim_data / 20) * 17) + { + warnlevel++; + (*warnfunction) ("Warning: past 85% of memory limit"); + } + break; + case 2: + if (siz > (lim_data / 20) * 19) + { + warnlevel++; + (*warnfunction) ("Warning: past 95% of memory limit"); + } + break; + } + + if ((int) cp & 0x3ff) /* land on 1K boundaries */ + sbrk (1024 - ((int) cp & 0x3ff)); + + /* Take at least 2k, and figure out how many blocks of the desired size + we're about to get */ + nblks = 1; + if ((siz = nu) < 8) + nblks = 1 << ((siz = 8) - nu); + + if ((cp = sbrk (1 << (siz + 3))) == (char *) -1) + return; /* no more room! */ + + if ((int) cp & 7) + { /* shouldn't happen, but just in case */ + cp = (char *) (((int) cp + 8) & ~7); + nblks--; + } + + /* save new header and link the nblks blocks together */ + nextf[nu] = (struct mhead *) cp; + siz = 1 << (nu + 3); + while (1) + { + ((struct mhead *) cp) -> mh_alloc = ISFREE; + ((struct mhead *) cp) -> mh_index = nu; + if (--nblks <= 0) break; + CHAIN ((struct mhead *) cp) = (struct mhead *) (cp + siz); + cp += siz; + } + CHAIN ((struct mhead *) cp) = 0; + +#if defined (HAVE_BSD_SIGNALS) + sigsetmask (oldmask); +#else +# if defined (HAVE_POSIX_SIGNALS) + sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL); +# endif +#endif /* HAVE_BSD_SIGNALS */ +} + +static void +getpool () +{ + register int nu; + register char *cp = sbrk (0); + + if ((int) cp & 0x3ff) /* land on 1K boundaries */ + sbrk (1024 - ((int) cp & 0x3ff)); + + /* Record address of start of space allocated by malloc. */ + if (_malloc_base == 0) + _malloc_base = cp; + + /* Get 2k of storage */ + + cp = sbrk (04000); + if (cp == (char *) -1) + return; + + /* Divide it into an initial 8-word block + plus one block of size 2**nu for nu = 3 ... 10. */ + + CHAIN (cp) = nextf[0]; + nextf[0] = (struct mhead *) cp; + ((struct mhead *) cp) -> mh_alloc = ISFREE; + ((struct mhead *) cp) -> mh_index = 0; + cp += 8; + + for (nu = 0; nu < 7; nu++) + { + CHAIN (cp) = nextf[nu]; + nextf[nu] = (struct mhead *) cp; + ((struct mhead *) cp) -> mh_alloc = ISFREE; + ((struct mhead *) cp) -> mh_index = nu; + cp += 8 << nu; + } +} + +#if defined (MEMSCRAMBLE) || !defined (NO_CALLOC) +static char * +zmemset (s, c, n) + char *s; + int c; + register int n; +{ + register char *sp; + + sp = s; + while (--n >= 0) + *sp++ = c; + return (s); +} +#endif /* MEMSCRAMBLE || !NO_CALLOC */ + +char * +malloc (n) /* get a block */ + unsigned int n; +{ + register struct mhead *p; + register unsigned int nbytes; + register int nunits = 0; + + /* Figure out how many bytes are required, rounding up to the nearest + multiple of 4, then figure out which nextf[] area to use */ + nbytes = (n + sizeof *p + EXTRA + 3) & ~3; + { + register unsigned int shiftr = (nbytes - 1) >> 2; + + while (shiftr >>= 1) + nunits++; + } + + /* In case this is reentrant use of malloc from signal handler, + pick a block size that no other malloc level is currently + trying to allocate. That's the easiest harmless way not to + interfere with the other level of execution. */ + while (busy[nunits]) nunits++; + busy[nunits] = 1; + + /* If there are no blocks of the appropriate size, go get some */ + /* COULD SPLIT UP A LARGER BLOCK HERE ... ACT */ + if (nextf[nunits] == 0) + morecore (nunits); + + /* Get one block off the list, and set the new list head */ + if ((p = nextf[nunits]) == 0) + { + busy[nunits] = 0; + return 0; + } + nextf[nunits] = CHAIN (p); + busy[nunits] = 0; + + /* Check for free block clobbered */ + /* If not for this check, we would gobble a clobbered free chain ptr */ + /* and bomb out on the NEXT allocate of this size block */ + if (p -> mh_alloc != ISFREE || p -> mh_index != nunits) +#ifdef RCHECK + botch ("block on free list clobbered"); +#else /* not RCHECK */ + abort (); +#endif /* not RCHECK */ + + /* Fill in the info, and if range checking, set up the magic numbers */ + p -> mh_alloc = ISALLOC; +#ifdef RCHECK + p -> mh_nbytes = n; + p -> mh_magic4 = MAGIC4; + { + register char *m = (char *) (p + 1) + n; + + *m++ = MAGIC1, *m++ = MAGIC1, *m++ = MAGIC1, *m = MAGIC1; + } +#else /* not RCHECK */ + p -> mh_size = n; +#endif /* not RCHECK */ +#ifdef MEMSCRAMBLE + zmemset ((char *)(p + 1), 0xdf, n); /* scramble previous contents */ +#endif +#ifdef MSTATS + nmalloc[nunits]++; + nmal++; +#endif /* MSTATS */ + return (char *) (p + 1); +} + +void +free (mem) + char *mem; +{ + register struct mhead *p; + { + register char *ap = mem; + + if (ap == 0) + return; + + p = (struct mhead *) ap - 1; + + if (p -> mh_alloc == ISMEMALIGN) + { +#ifdef RCHECK + ap -= p->mh_nbytes; +#else + ap -= p->mh_size; /* XXX */ +#endif + p = (struct mhead *) ap - 1; + } + +#ifndef RCHECK + if (p -> mh_alloc != ISALLOC) + abort (); + +#else /* RCHECK */ + if (p -> mh_alloc != ISALLOC) + { + if (p -> mh_alloc == ISFREE) + botch ("free: Called with already freed block argument\n"); + else + botch ("free: Called with unallocated block argument\n"); + } + + ASSERT (p -> mh_magic4 == MAGIC4); + ap += p -> mh_nbytes; + ASSERT (*ap++ == MAGIC1); ASSERT (*ap++ == MAGIC1); + ASSERT (*ap++ == MAGIC1); ASSERT (*ap == MAGIC1); +#endif /* RCHECK */ + } +#ifdef MEMSCRAMBLE + { + register int n; + +#ifdef RCHECK + n = p->mh_nbytes; +#else /* not RCHECK */ + n = p->mh_size; +#endif /* not RCHECK */ + zmemset (mem, 0xcf, n); + } +#endif + { + register int nunits = p -> mh_index; + + ASSERT (nunits <= 29); + p -> mh_alloc = ISFREE; + + /* Protect against signal handlers calling malloc. */ + busy[nunits] = 1; + /* Put this block on the free list. */ + CHAIN (p) = nextf[nunits]; + nextf[nunits] = p; + busy[nunits] = 0; + +#ifdef MSTATS + nmalloc[nunits]--; + nfre++; +#endif /* MSTATS */ + } +} + +char * +realloc (mem, n) + char *mem; + register unsigned int n; +{ + register struct mhead *p; + register unsigned int tocopy; + register unsigned int nbytes; + register int nunits; + + if ((p = (struct mhead *) mem) == 0) + return malloc (n); + p--; + nunits = p -> mh_index; + ASSERT (p -> mh_alloc == ISALLOC); +#ifdef RCHECK + ASSERT (p -> mh_magic4 == MAGIC4); + { + register char *m = mem + (tocopy = p -> mh_nbytes); + ASSERT (*m++ == MAGIC1); ASSERT (*m++ == MAGIC1); + ASSERT (*m++ == MAGIC1); ASSERT (*m == MAGIC1); + } +#else /* not RCHECK */ + if (p -> mh_index >= 13) + tocopy = (1 << (p -> mh_index + 3)) - sizeof *p; + else + tocopy = p -> mh_size; +#endif /* not RCHECK */ + + /* See if desired size rounds to same power of 2 as actual size. */ + nbytes = (n + sizeof *p + EXTRA + 7) & ~7; + + /* If ok, use the same block, just marking its size as changed. */ + if (nbytes > (4 << nunits) && nbytes <= (8 << nunits)) + { +#ifdef RCHECK + register char *m = mem + tocopy; + *m++ = 0; *m++ = 0; *m++ = 0; *m++ = 0; + p-> mh_nbytes = n; + m = mem + n; + *m++ = MAGIC1; *m++ = MAGIC1; *m++ = MAGIC1; *m++ = MAGIC1; +#else /* not RCHECK */ + p -> mh_size = n; +#endif /* not RCHECK */ + return mem; + } + + if (n < tocopy) + tocopy = n; + { + register char *new; + + if ((new = malloc (n)) == 0) + return 0; + FASTCOPY (mem, new, tocopy); + free (mem); + return new; + } +} + +char * +memalign (alignment, size) + unsigned int alignment, size; +{ + register char *ptr; + register char *aligned; + register struct mhead *p; + + ptr = malloc (size + alignment); + + if (ptr == 0) + return 0; + /* If entire block has the desired alignment, just accept it. */ + if (((int) ptr & (alignment - 1)) == 0) + return ptr; + /* Otherwise, get address of byte in the block that has that alignment. */ + aligned = (char *) (((int) ptr + alignment - 1) & -alignment); + + /* Store a suitable indication of how to free the block, + so that free can find the true beginning of it. */ + p = (struct mhead *) aligned - 1; + p -> mh_size = aligned - ptr; + p -> mh_alloc = ISMEMALIGN; + return aligned; +} + +#if !defined (HPUX) +/* This runs into trouble with getpagesize on HPUX, and Multimax machines. + Patching out seems cleaner than the ugly fix needed. */ +#if defined (__STDC__) +void * +#else +char * +#endif +valloc (size) + size_t size; +{ + return memalign (getpagesize (), size); +} +#endif /* !HPUX */ + +#ifndef NO_CALLOC +char * +calloc (n, s) + size_t n, s; +{ + size_t total; + char *result; + + total = n * s; + result = malloc (total); + if (result) + zmemset (result, 0, total); + return result; +} + +void +cfree (p) + char *p; +{ + free (p); +} +#endif /* !NO_CALLOC */ + +#ifdef MSTATS +/* Return statistics describing allocation of blocks of size 2**n. */ + +struct mstats_value + { + int blocksize; + int nfree; + int nused; + }; + +struct mstats_value +malloc_stats (size) + int size; +{ + struct mstats_value v; + register int i; + register struct mhead *p; + + v.nfree = 0; + + if (size < 0 || size >= 30) + { + v.blocksize = 0; + v.nused = 0; + return v; + } + + v.blocksize = 1 << (size + 3); + v.nused = nmalloc[size]; + + for (p = nextf[size]; p; p = CHAIN (p)) + v.nfree++; + + return v; +} +#endif /* MSTATS */ + +/* + * This function returns the total number of bytes that the process + * will be allowed to allocate via the sbrk(2) system call. On + * BSD systems this is the total space allocatable to stack and + * data. On USG systems this is the data space only. + */ + +#if !defined (HAVE_RESOURCE) +extern long ulimit (); + +static void +get_lim_data () +{ + lim_data = ulimit (3, 0); + lim_data -= (long) data_space_start; +} + +#else /* HAVE_RESOURCE */ +static void +get_lim_data () +{ + struct rlimit XXrlimit; + + getrlimit (RLIMIT_DATA, &XXrlimit); +#ifdef RLIM_INFINITY + lim_data = XXrlimit.rlim_cur & RLIM_INFINITY; /* soft limit */ +#else + lim_data = XXrlimit.rlim_cur; /* soft limit */ +#endif +} + +#endif /* HAVE_RESOURCE */ |