diff options
| author | Poul-Henning Kamp <phk@FreeBSD.org> | 1997-07-24 08:25:25 +0000 |
|---|---|---|
| committer | Poul-Henning Kamp <phk@FreeBSD.org> | 1997-07-24 08:25:25 +0000 |
| commit | 749e16e2f8b7902f47b4248cf09b831be847da8f (patch) | |
| tree | 37e1565de78d98c617b78ea9654db40b887563ad | |
| parent | 6a602e1006d6e08e8ce19e995f98fb3902c9ad7b (diff) | |
Notes
| -rw-r--r-- | lib/libc/stdlib/Makefile.inc | 6 | ||||
| -rw-r--r-- | lib/libc/stdlib/calloc.3 | 71 | ||||
| -rw-r--r-- | lib/libc/stdlib/malloc.3 | 493 | ||||
| -rw-r--r-- | lib/libc/stdlib/malloc.c | 272 |
4 files changed, 434 insertions, 408 deletions
diff --git a/lib/libc/stdlib/Makefile.inc b/lib/libc/stdlib/Makefile.inc index f44e4ca298a1..c6a09cb08bb2 100644 --- a/lib/libc/stdlib/Makefile.inc +++ b/lib/libc/stdlib/Makefile.inc @@ -1,5 +1,5 @@ # from @(#)Makefile.inc 8.3 (Berkeley) 2/4/95 -# $Id: Makefile.inc,v 1.9 1997/06/22 17:54:24 phk Exp $ +# $Id: Makefile.inc,v 1.4.2.1 1997/06/24 03:51:37 julian Exp $ # machine-independent stdlib sources .PATH: ${.CURDIR}/../libc/${MACHINE}/stdlib ${.CURDIR}/../libc/stdlib @@ -17,7 +17,7 @@ SRCS+= abort.c atexit.c atof.c atoi.c atol.c bsearch.c calloc.c div.c \ .if ${LIB} == "c" MAN3+= stdlib/abort.3 stdlib/abs.3 stdlib/alloca.3 stdlib/atexit.3 \ stdlib/atof.3 stdlib/atoi.3 stdlib/atol.3 stdlib/bsearch.3 \ - stdlib/calloc.3 stdlib/div.3 stdlib/exit.3 \ + stdlib/div.3 stdlib/exit.3 \ stdlib/getenv.3 stdlib/getopt.3 stdlib/getsubopt.3 stdlib/labs.3 \ stdlib/ldiv.3 stdlib/malloc.3 stdlib/memory.3 stdlib/qsort.3 \ stdlib/radixsort.3 stdlib/rand.3 stdlib/random.3 \ @@ -30,5 +30,5 @@ MLINKS+=rand.3 srand.3 MLINKS+=random.3 initstate.3 random.3 setstate.3 random.3 srandom.3 MLINKS+=strtol.3 strtoq.3 MLINKS+=strtoul.3 strtouq.3 -MLINKS+=malloc.3 free.3 malloc.3 realloc.3 +MLINKS+=malloc.3 free.3 malloc.3 realloc.3 malloc.3 calloc.3 .endif diff --git a/lib/libc/stdlib/calloc.3 b/lib/libc/stdlib/calloc.3 deleted file mode 100644 index aa1038fd4268..000000000000 --- a/lib/libc/stdlib/calloc.3 +++ /dev/null @@ -1,71 +0,0 @@ -.\" Copyright (c) 1991, 1993 -.\" The Regents of the University of California. All rights reserved. -.\" -.\" This code is derived from software contributed to Berkeley by -.\" the American National Standards Committee X3, on Information -.\" Processing Systems. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" 3. All advertising materials mentioning features or use of this software -.\" must display the following acknowledgement: -.\" This product includes software developed by the University of -.\" California, Berkeley and its contributors. -.\" 4. Neither the name of the University nor the names of its contributors -.\" may be used to endorse or promote products derived from this software -.\" without specific prior written permission. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" -.\" @(#)calloc.3 8.1 (Berkeley) 6/4/93 -.\" $Id: calloc.3,v 1.4 1997/02/22 15:03:08 peter Exp $ -.\" -.Dd June 4, 1993 -.Dt CALLOC 3 -.Os -.Sh NAME -.Nm calloc -.Nd allocate clean memory (zero initialized space) -.Sh SYNOPSIS -.Fd #include <stdlib.h> -.Ft void * -.Fn calloc "size_t nmemb" "size_t size" -.Sh DESCRIPTION -The -.Fn calloc -function allocates space for an array of -.Fa nmemb -objects, each of whose size is -.Fa size . -The space is initialized to all bits zero. -.Sh RETURN VALUES -The -.Fn calloc -function returns -a pointer to the -the allocated space if successful; otherwise a null pointer is returned. -.Sh SEE ALSO -.Xr free 3 , -.Xr malloc 3 , -.Xr realloc 3 -.Sh STANDARDS -The -.Fn calloc -function conforms to -.St -ansiC . diff --git a/lib/libc/stdlib/malloc.3 b/lib/libc/stdlib/malloc.3 index bb6626ba2eae..5041412c4b36 100644 --- a/lib/libc/stdlib/malloc.3 +++ b/lib/libc/stdlib/malloc.3 @@ -34,261 +34,390 @@ .\" SUCH DAMAGE. .\" .\" @(#)malloc.3 8.1 (Berkeley) 6/4/93 -.\" $Id: malloc.3,v 1.6 1996/09/23 19:26:38 phk Exp $ +.\" $Id: malloc.3,v 1.13 1997/07/01 18:39:36 phk Exp $ .\" .Dd August 27, 1996 .Dt MALLOC 3 .Os FreeBSD 2 .Sh NAME -.Nm malloc -.Nd general memory allocation function -.Pp -.Nm free -.Nd free up memory allocated with malloc, calloc or realloc -.Pp -.Nm realloc -.Nd reallocation of memory function +.Nm malloc, calloc, realloc, free +.Nd general purpose memory allocation functions .Sh SYNOPSIS .Fd #include <stdlib.h> .Ft void * .Fn malloc "size_t size" -.Ft void -.Fn free "void *ptr" +.Ft void * +.Fn calloc "size_t number" "size_t size" .Ft void * .Fn realloc "void *ptr" "size_t size" +.Ft void +.Fn free "void *ptr" .Ft char * -.Va malloc_options +.Va malloc_options; .Sh DESCRIPTION The .Fn malloc -function allocates uninitialized space for an object whose -size is specified by -.Fa size . -The -.Fn malloc -function maintains multiple lists of free blocks according to size, allocating -space from the appropriate list. -.Pp -The allocated space is -suitably aligned (after possible pointer -coercion) for storage of any type of object. If the space is of +function allocates +.Fa size +bytes of memory. +The allocated space is suitably aligned (after possible pointer coercion) +for storage of any type of object. +If the space is at least .Em pagesize -or larger, the memory returned will be page-aligned. +bytes in length (see +.Xr getpagesize (3)), +the returned memory will be page boundary aligned as well. +If +.Fn malloc +fails, a NULL pointer is returned. .Pp The -.Fn free -function causes the space pointed to by -.Fa ptr -to be deallocated, that is, at least made available for further allocation, -but if possible, it will passed back to the kernel with -.Xr sbrk 2 . -If -.Fa ptr -is a null pointer, no action occurs. +.Fn calloc +function allocates space for +.Fa number +objects, +each +.Fa size +bytes in length. +The result is identical to calling +.Fn malloc +with an argument of +.Dq "number * size" , +with the exception that the allocated memory is initialized to nul bytes. .Pp The .Fn realloc -function changes the size of the object pointed to by +function changes the size of the previously allocated memory referenced by .Fa ptr -to the size specified by -.Fa size . -The contents of the object are unchanged up to the lesser -of the new and old sizes. -If the new size is larger, the value of the newly allocated portion -of the object is indeterminate. +to +.Fa size +bytes. +The contents of the memory are unchanged up to the lesser of the new and +old sizes. +If the new size is larger, +the value of the newly allocated portion of the memory is undefined. +If the requested memory cannot be allocated, NULL is returned and +the memory referenced by +.Fa ptr +is valid and unchanged. If .Fa ptr -is a null pointer, the +is NULL, the .Fn realloc -function behaves like the -.Fn malloc -function for the specified size. -If the space cannot be allocated, the object -pointed to by +function behaves identically to +.Fn malloc +for the specified size. +.Pp +The +.Fn free +function causes the allocated memory referenced by .Fa ptr -is unchanged. +to be made available for future allocations. If -.Fa size -is zero and .Fa ptr -is not a null pointer, the object it points to is freed. +is NULL, no action occurs. +.Sh TUNING +Once, when the first call is made to one of these memory allocation +routines, various flags will be set or reset, which affect the +workings of this allocation implementation. .Pp -Malloc will first look for a symbolic link called -.Pa /etc/malloc.conf -and next check the environment for a variable called -.Ev MALLOC_OPTIONS -and finally for the global variable -.Va malloc_options -and scan them for flags in that order. -Flags are single letters, uppercase means on, lowercase means off. +The ``name'' of the file referenced by the symbolic link named +.Pa /etc/malloc.conf , +the value of the environment variable +.Ev MALLOC_OPTIONS , +and the string pointed to by the global variable +.Va malloc_options +will be interpreted, in that order, character by character as flags. +.Pp +Most flags are single letters, +where uppercase indicates that the behavior is set, or on, +and lowercase means that the behavior is not set, or off. .Bl -tag -width indent .It A -``abort'' malloc will coredump the process, rather than tolerate failure. -This is a very handy debugging aid, since the core file will represent the -time of failure, -rather than when the NULL pointer was accessed. - -.It D -``dump'' malloc will dump statistics in a file called ``malloc.out'' at exit. - +All warnings (except for the warning about unknown +flags being set), and failure to allocate memory become fatal. +The process will call +.Fn abort 3 +in these cases. .It J -``junk'' fill some junk into the area allocated. -Currently junk is bytes of 0xd0, this is pronounced ``Duh'' :-) - +Each byte of new memory allocated by +.Fn malloc +or +.Fn realloc +as well as all memory returned by +.Fn free +or +.Fn realloc +will be initialized to 0xd0. +This options also sets the +.Dq R +option. +This is intended for debugging and will impact performance negatively. .It H -``hint'' pass a hint to the kernel about pages we don't use. If the -machine is paging a lot this may help a bit. - +Pass a hint to the kernel about pages unused by the allocation functions. +This may help performance if the system is paging excessively. .It R -``realloc'' always reallocate when +Cause the .Fn realloc -is called, even if the initial allocation was big enough. +function to always reallocate memory even if the initial allocation was +sufficiently large. This can substantially aid in compacting memory. - .It U -``utrace'' generate entries for ktrace(1) for all operations. -Consult the source for this one. - +Generate +.Dq utrace +entries for +.Xr ktrace 1 , +for all operations. +Consult the source for details on this option. +.It V +Attempting to allocate zero bytes will return a NULL pointer instead of +a valid pointer. +(The default behavior is to make a minimal allocation and return a +pointer to it.) +This option is provided for System V compatibility. +This option is incompatible with the +.Dq X +option. +.It X +Rather than return failure for any allocation function, +display a diagnostic message on stderr and cause the program to drop +core (using +.Fn abort 3 ). +This option should be set at compile time by including the following in +the source code: +.Bd -literal -offset indent +extern char *malloc_options; +malloc_options = "X"; +.Ed .It Z -``zero'' fill some junk into the area allocated (see ``J''), -except for the exact length the user asked for, which is zeroed. - +This option implicitly sets the +.Dq J +and +.Dq R +options, and then zeros out the bytes that were requested. +This is intended for debugging and will impact performance negatively. .It < -``Half the cache size'' Reduce the size of the cache by a factor of two. - +Reduce the size of the cache by a factor of two. +The default cache size is 16 pages. +This option can be specified multiple times. .It > -``Double the cache size'' Double the size of the cache by a factor of two. +Double the size of the cache by a factor of two. +The default cache size is 16 pages. +This option can be specified multiple times. .El .Pp -So to set a systemwide reduction of cache size and coredumps on problems -one would: -.Li ln -s 'A<' /etc/malloc.conf +The +.Dq J +and +.Dq Z +options are intended for testing and debugging. +An application which changes its behavior when these options are used +is flawed. +.Sh EXAMPLES +To set a systemwide reduction of cache size, and to dump core whenever +a problem occurs: .Pp -The ``J'' and ``Z'' is mostly for testing and debugging, -if a program changes behavior if either of these options are used, -it is buggy. +.Bd -literal -offset indent +ln -s 'A<' /etc/malloc.conf +.Ed .Pp -The default cache size is 16 pages. +To specify in the source that a program does no return value checking +on calls to these functions: +.Bd -literal -offset indent +extern char *malloc_options; +malloc_options = "X"; +.Ed .Sh ENVIRONMENT -See above. +The following environment variables affect the execution of the allocation +functions: +.Bl -tag -width MMM +.It Ev MALLOC_OPTIONS +If the environmental variable +.Ev MALLOC_OPTIONS +is set, the characters it contains will be interpreted as flags to the +allocation functions. .Sh RETURN VALUES The .Fn malloc -function returns -a pointer to the allocated space if successful; otherwise -a null pointer is returned. +and +.Fn calloc +functions return a pointer to the allocated memory if successful; otherwise +a NULL pointer is returned. .Pp The -.Fn free -function returns no value. +.Fn realloc +function returns a pointer, possibly identical to +.Fa ptr , +to the allocated memory +if successful; otherwise a NULL pointer is returned, in which case the +memory referenced by +.Fa ptr +is still available and intact. .Pp The -.Fn realloc -function returns either a null pointer or a pointer -to the possibly moved allocated space. -.Sh MESSAGES -If -.Fn malloc , .Fn free -or -.Fn realloc -detects an error or warning condition, -a message will be printed to filedescriptor -2 (not using stdio). -Errors will always result in the process being -.Xr abort 2 'ed, -If the ``A'' option has been specified, also warnings will -.Xr abort 2 -the process. +function returns no value. +.Sh "DEBUGGING MALLOC PROBLEMS" .Pp -Here is a brief description of the error messages and what they mean: +The major difference between this implementation and other allocation +implementations is that the free pages are not accessed unless allocated, +and are aggressively returned to the kernel for reuse. +.Bd -filled -offset indent +Most allocation implementations will store a data structure containing a +linked list in the free chunks of memory, +used to tie all the free memory together. +That can be suboptimal, +as every time the free-list is traversed, +the otherwise unused, and likely paged out, +pages are faulted into primary memory. +On systems which are paging, +this can result in a factor of five increase in the number of page-faults +done by a process. +.Ed .Pp -``(ES): mumble mumble mumble'': -malloc have been compiled with -DEXTRA_SANITY and something looks -fishy in there. Consult sources and or wizards. +A side effect of this architecture is that many minor transgressions on +the interface which would traditionally not be detected are in fact +detected. As a result, programs that have been running happily for +years may suddenly start to complain loudly, when linked with this +allocation implementation. .Pp -``allocation failed'' -if the ``A'' option is specified it is an error for -.Fn malloc -or -.Fn realloc -to return NULL. +The first and most important thing to do is to set the +.Dq A +option. +This option forces a coredump (if possible) at the first sign of trouble, +rather than the normal policy of trying to continue if at all possible. .Pp -``mmap(2) failed, check limits.'' -This is a rather weird condition that is most likely to mean that -the system is seriously overloaded or that your ulimits are sick. +It is probably also a good idea to recompile the program with suitable +options and symbols for debugger support. .Pp -``freelist is destroyed.'' -mallocs internal freelist has been stomped on. +If the program starts to give unusual results, coredump or generally behave +differently without emitting any of the messages listed in the next +section, it is likely because it depends on the storage being filled with +nul bytes. Try running it with +.Dq Z +option set; +if that improves the situation, this diagnosis has been confirmed. +If the program still misbehaves, +the likely problem is accessing memory outside the allocated area, +more likely after than before the allocated area. .Pp -Here is a brief description of the warning messages and what they mean: +Alternatively, if the symptoms are not easy to reproduce, setting the +.Dq J +option may help provoke the problem. .Pp -``chunk/page is already free.'' -A pointer to a free chunk is attempted freed again. +In truly difficult cases, the +.Dq U +option, if supported by the kernel, can provide a detailed trace of +all calls made to these functions. .Pp -``junk pointer, too high to make sense.'' -The pointer doesn't make sense. It's above the area of memory that -malloc knows something about. -This could be a pointer from some -.Xr mmap 2 'ed -memory. -.Pp -``junk pointer, too low to make sense.'' -The pointer doesn't make sense. It's below the area of memory that -malloc knows something about. -This pointer probably came from your data or bss segments. -.Pp -``malloc() has never been called.'' -Nothing has ever been allocated, yet something is being freed or -realloc'ed. +Unfortunately this implementation does not provide much detail about +the problems it detects, the performance impact for storing such information +would be prohibitive. +There are a number of allocation implementations available on the 'Net +which focus on detecting and pinpointing problems by trading performance +for extra sanity checks and detailed diagnostics. +.Sh "DIAGNOSTIC MESSAGES +If +.Fn malloc , +.Fn calloc , +.Fn realloc +or +.Fn free +detect an error or warning condition, +a message will be printed to file descriptor STDERR_FILENO. +Errors will result in the process dumping core. +If the +.Dq A +option is set, all warnings are treated as errors. .Pp -``modified (chunk-/page-) pointer.'' -The pointer passed to free or realloc has been modified. +The following is a brief description of possible error messages and +their meanings: .Pp -``pointer to wrong page.'' -The pointer that malloc is trying to free is not pointing to -a sensible page. +.Bl -tag -width indent +.It "(ES): mumble mumble mumble +The allocation functions were compiled with +.Dq EXTRA_SANITY +defined, and an error was found during the additional error checking. +Consult the source code for further information. +.It "allocation failed +If the +.Dq A +option is specified it is a fatal error for an allocation function to fail. +.It "mmap(2) failed, check limits +This most likely means that the system is dangerously overloaded or that +the process' limits are incorrectly specified. +.It "freelist is destroyed +The internal free-list has been corrupted. +.El .Pp -``recursive call.'' -You have tried to call recursively into these functions. -I can only imagine this as happening if you call one of these -functions from a signal function, which happens to be called -while you're already in here. -Well, sorry to say: that's not supported. -If this is a problem for you I'd like to hear about it. It -would be possible to add a sigblock() around this package, -but it would have a performance penalty that is not acceptable -as the default. +.Bl -tag -width indent +The following is a brief description of possible warning messages and +their meanings: .Pp -``unknown char in MALLOC_OPTIONS'' -we found something we didn't understand. +.It "chunk/page is already free +The process attempted to +.Fn free +memory which had already been freed. +.It "junk pointer ... +A pointer specified to one of the allocation functions points outside the +bounds of the memory of which they are aware. +.It "malloc() has never been called +No memory has been allocated, +yet something is being freed or +realloc'ed. +.It "modified (chunk-/page-) pointer +The pointer passed to +.Fn free +or +.Fn realloc +has been modified. +.It "pointer to wrong page +The pointer that +.Fn malloc +or +.Fn calloc +is trying to free does not reference a possible page. +.It "recursive call +A process has attempted to call an allocation function recursively. +This is not permitted. In particular, signal handlers should not +attempt to allocate memory. +.It "out of memory +The +.Dq X +option was specified and an allocation of memory failed. +.It "unknown char in MALLOC_OPTIONS +An unknown option was specified. +Even with the +.Dq A +option set, this warning is still only a warning. .Sh SEE ALSO .Xr brk 2 , .Xr alloca 3 , -.Xr calloc 3 , .Xr getpagesize 3 , .Xr memory 3 .Pa /usr/share/doc/papers/malloc.ascii.gz .Sh STANDARDS The -.Fn malloc -function conforms to +.Fn malloc , +.Fn calloc , +.Fn realloc +and +.Fn free +functions conform to .St -ansiC . -.Sh HISTORY -The present implementation of malloc started out as a filesystem on a drum -attached to a 20bit binary challenged computer built with discrete germanium -transistors, and it has since graduated to handle primary storage rather than -secondary. +.Sh BUGS +The messages printed in case of problems provide no detail about the +actual values. .Pp -The main difference from other malloc implementations are believed to be that -the free pages are not accessed until allocated. -Most malloc implementations will store a data structure containing a, -possibly double-, linked list in the free chunks of memory, used to tie -all the free memory together. -That is a quite suboptimal thing to do. -Every time the free-list is traversed, all the otherwise unused, and very -likely paged out, pages get faulted into primary memory, just to see what -lies after them in the list. +It can be argued that returning a null pointer when asked to +allocate zero bytes is a silly response to a silly question. .Pp -On systems which are paging, this can make a factor five in difference on the -page-faults of a process. +This implementation was authored by Poul-Henning Kamp. +Please report any problems to him at +.Li <phk@FreeBSD.org> . +.Sh HISTORY +The present allocation implementation started out as a filesystem for a +drum attached to a 20bit binary challenged computer which was built +with discrete germanium transistors. It has since graduated to +handle primary storage rather than secondary. +It first appeared in its new shape and ability in FreeBSD release 2.2. diff --git a/lib/libc/stdlib/malloc.c b/lib/libc/stdlib/malloc.c index 0b06473fed02..dc601ea78e96 100644 --- a/lib/libc/stdlib/malloc.c +++ b/lib/libc/stdlib/malloc.c @@ -6,7 +6,7 @@ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp * ---------------------------------------------------------------------------- * - * $Id: malloc.c,v 1.18.2.1 1996/12/30 01:35:15 alex Exp $ + * $Id: malloc.c,v 1.28 1997/07/02 19:33:23 phk Exp $ * */ @@ -22,15 +22,6 @@ #endif /* - * Defining MALLOC_STATS will enable you to call malloc_dump() and set - * the [dD] options in the MALLOC_OPTIONS environment variable. - * It has no run-time performance hit. - */ -#ifndef MALLOC_STATS -#undef MALLOC_STATS -#endif - -/* * What to use for Junk. This is the byte value we use to fill with * when the 'J' option is enabled. */ @@ -41,7 +32,7 @@ * * malloc_pageshift pagesize = 1 << malloc_pageshift * It's probably best if this is the native - * page size, but it shouldn't have to be. + * page size, but it doesn't have to be. * * malloc_minsize minimum size of an allocation in bytes. * If this is too small it's too much work @@ -51,27 +42,52 @@ * */ -#if defined(__i386__) && defined(__FreeBSD__) -# define malloc_pageshift 12U +#if defined(__FreeBSD__) +# if defined(__i386__) +# define malloc_pageshift 12U +# define malloc_minsize 16U +# endif +# define HAS_UTRACE +# if defined(_THREAD_SAFE) +# include <pthread.h> +# include "pthread_private.h" +# define THREAD_LOCK() pthread_mutex_lock(&malloc_lock) +# define THREAD_UNLOCK() pthread_mutex_unlock(&malloc_lock) + static struct pthread_mutex _malloc_lock = PTHREAD_MUTEX_INITIALIZER; + static pthread_mutex_t malloc_lock = &_malloc_lock; +# endif +#endif /* __FreeBSD__ */ + +#if defined(__sparc__) && defined(sun) +# define malloc_pageshirt 12U # define malloc_minsize 16U -#endif /* __i386__ && __FreeBSD__ */ +# define MAP_ANON (0) + static int fdzero; +# define MMAP_FD fdzero +# define INIT_MMAP() \ + { if ((fdzero=open("/dev/zero", O_RDWR, 0000)) == -1) \ + wrterror("open of /dev/zero"); } +# define MADV_FREE MADV_DONTNEED +#endif /* __sparc__ */ /* Insert your combination here... */ #if defined(__FOOCPU__) && defined(__BAROS__) # define malloc_pageshift 12U # define malloc_minsize 16U -#endif /* __i386__ && __FreeBSD__ */ +#endif /* __FOOCPU__ && __BAROS__ */ + /* * No user serviceable parts behind this point. */ +#include <sys/types.h> +#include <sys/mman.h> +#include <errno.h> +#include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> -#include <errno.h> -#include <sys/types.h> -#include <sys/mman.h> /* * This structure describes a page worth of chunks. @@ -96,7 +112,7 @@ struct pgfree { struct pgfree *prev; /* prev run of free pages */ void *page; /* pointer to free pages */ void *end; /* pointer to end of free pages */ - u_long size; /* number of bytes free */ + size_t size; /* number of bytes free */ }; /* @@ -122,10 +138,6 @@ struct pgfree { #define malloc_minsize 16U #endif -#ifndef malloc_pageshift -#error "malloc_pageshift undefined" -#endif - #if !defined(malloc_pagesize) #define malloc_pagesize (1U<<malloc_pageshift) #endif @@ -144,9 +156,28 @@ struct pgfree { #define pageround(foo) (((foo) + (malloc_pagemask))&(~(malloc_pagemask))) #define ptr2index(foo) (((u_long)(foo) >> malloc_pageshift)-malloc_origo) +#ifndef THREAD_LOCK +#define THREAD_LOCK() +#endif + +#ifndef THREAD_UNLOCK +#define THREAD_UNLOCK() +#endif + +#ifndef MMAP_FD +#define MMAP_FD (-1) +#endif + +#ifndef INIT_MMAP +#define INIT_MMAP() +#endif + /* Set when initialization has been done */ static unsigned malloc_started; +/* Recusion flag for public interface. */ +static int malloc_active; + /* Number of free pages we cache */ static unsigned malloc_cache = 16; @@ -171,25 +202,29 @@ static int malloc_abort; /* Are we trying to die ? */ static int suicide; -/* dump statistics */ -static int malloc_stats; - /* always realloc ? */ static int malloc_realloc; /* pass the kernel a hint on free pages ? */ static int malloc_hint; +/* xmalloc behaviour ? */ +static int malloc_xmalloc; + +/* sysv behaviour for malloc(0) ? */ +static int malloc_sysv; + /* zero fill ? */ static int malloc_zero; /* junk fill ? */ static int malloc_junk; +#ifdef HAS_UTRACE + /* utrace ? */ static int malloc_utrace; -#ifdef __FreeBSD__ struct ut { void *p; size_t s; void *r; }; void utrace __P((struct ut *, int)); @@ -197,9 +232,9 @@ void utrace __P((struct ut *, int)); #define UTRACE(a, b, c) \ if (malloc_utrace) \ {struct ut u; u.p=a; u.s = b; u.r=c; utrace(&u, sizeof u);} -#else /* !__FreeBSD__ */ +#else /* !HAS_UTRACE */ #define UTRACE(a,b,c) -#endif +#endif /* HAS_UTRACE */ /* my last break. */ static void *malloc_brk; @@ -213,6 +248,11 @@ char *malloc_options; /* Name of the current public function */ static char *malloc_func; +/* Macro for mmap */ +#define MMAP(size) \ + mmap((caddr_t)0, (size), PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, \ + MMAP_FD, 0); + /* * Necessary function declarations */ @@ -221,79 +261,17 @@ static void *imalloc(size_t size); static void ifree(void *ptr); static void *irealloc(void *ptr, size_t size); -#ifdef MALLOC_STATS -void -malloc_dump(FILE *fd) -{ - struct pginfo **pd; - struct pgfree *pf; - int j; - - pd = page_dir; - - /* print out all the pages */ - for(j=0;j<=last_index;j++) { - fprintf(fd, "%08lx %5d ", (j+malloc_origo) << malloc_pageshift, j); - if (pd[j] == MALLOC_NOT_MINE) { - for(j++;j<=last_index && pd[j] == MALLOC_NOT_MINE;j++) - ; - j--; - fprintf(fd, ".. %5d not mine\n", j); - } else if (pd[j] == MALLOC_FREE) { - for(j++;j<=last_index && pd[j] == MALLOC_FREE;j++) - ; - j--; - fprintf(fd, ".. %5d free\n", j); - } else if (pd[j] == MALLOC_FIRST) { - for(j++;j<=last_index && pd[j] == MALLOC_FOLLOW;j++) - ; - j--; - fprintf(fd, ".. %5d in use\n", j); - } else if (pd[j] < MALLOC_MAGIC) { - fprintf(fd, "(%p)\n", pd[j]); - } else { - fprintf(fd, "%p %d (of %d) x %d @ %p --> %p\n", - pd[j], pd[j]->free, pd[j]->total, - pd[j]->size, pd[j]->page, pd[j]->next); - } - } - - for(pf=free_list.next; pf; pf=pf->next) { - fprintf(fd, "Free: @%p [%p...%p[ %ld ->%p <-%p\n", - pf, pf->page, pf->end, pf->size, pf->prev, pf->next); - if (pf == pf->next) { - fprintf(fd, "Free_list loops.\n"); - break; - } - } - - /* print out various info */ - fprintf(fd, "Minsize\t%d\n", malloc_minsize); - fprintf(fd, "Maxsize\t%d\n", malloc_maxsize); - fprintf(fd, "Pagesize\t%d\n", malloc_pagesize); - fprintf(fd, "Pageshift\t%d\n", malloc_pageshift); - fprintf(fd, "FirstPage\t%ld\n", malloc_origo); - fprintf(fd, "LastPage\t%ld %lx\n", last_index+malloc_pageshift, - (last_index + malloc_pageshift) << malloc_pageshift); - fprintf(fd, "Break\t%ld\n", (u_long)sbrk(0) >> malloc_pageshift); -} -#endif /* MALLOC_STATS */ - extern char *__progname; static void wrterror(char *p) { char *q = " error: "; + write(STDERR_FILENO, __progname, strlen(__progname)); + write(STDERR_FILENO, malloc_func, strlen(malloc_func)); + write(STDERR_FILENO, q, strlen(q)); + write(STDERR_FILENO, p, strlen(p)); suicide = 1; - write(2, __progname, strlen(__progname)); - write(2, malloc_func, strlen(malloc_func)); - write(2, q, strlen(q)); - write(2, p, strlen(p)); -#ifdef MALLOC_STATS - if (malloc_stats) - malloc_dump(stderr); -#endif /* MALLOC_STATS */ abort(); } @@ -303,25 +281,11 @@ wrtwarning(char *p) char *q = " warning: "; if (malloc_abort) wrterror(p); - write(2, __progname, strlen(__progname)); - write(2, malloc_func, strlen(malloc_func)); - write(2, q, strlen(q)); - write(2, p, strlen(p)); -} - -#ifdef MALLOC_STATS -static void -malloc_exit() -{ - FILE *fd = fopen("malloc.out", "a"); - char *q = "malloc() warning: Couldn't dump stats.\n"; - if (fd) { - malloc_dump(fd); - fclose(fd); - } else - write(2, q, strlen(q)); + write(STDERR_FILENO, __progname, strlen(__progname)); + write(STDERR_FILENO, malloc_func, strlen(malloc_func)); + write(STDERR_FILENO, q, strlen(q)); + write(STDERR_FILENO, p, strlen(p)); } -#endif /* MALLOC_STATS */ /* @@ -384,8 +348,7 @@ extend_pgdir(u_long index) */ /* Get new pages */ - new = (struct pginfo**) mmap(0, i * malloc_pagesize, PROT_READ|PROT_WRITE, - MAP_ANON|MAP_PRIVATE, -1, 0); + new = (struct pginfo**) MMAP(i * malloc_pagesize); if (new == (struct pginfo **)-1) return 0; @@ -414,6 +377,7 @@ malloc_init () char *p, b[64]; int i, j; + INIT_MMAP(); #ifdef EXTRA_SANITY malloc_junk = 1; @@ -437,16 +401,20 @@ malloc_init () case '<': malloc_cache >>= 1; break; case 'a': malloc_abort = 0; break; case 'A': malloc_abort = 1; break; - case 'd': malloc_stats = 0; break; - case 'D': malloc_stats = 1; break; case 'h': malloc_hint = 0; break; case 'H': malloc_hint = 1; break; case 'r': malloc_realloc = 0; break; case 'R': malloc_realloc = 1; break; case 'j': malloc_junk = 0; break; case 'J': malloc_junk = 1; break; +#ifdef HAS_UTRACE case 'u': malloc_utrace = 0; break; case 'U': malloc_utrace = 1; break; +#endif + case 'v': malloc_sysv = 0; break; + case 'V': malloc_sysv = 1; break; + case 'x': malloc_xmalloc = 0; break; + case 'X': malloc_xmalloc = 1; break; case 'z': malloc_zero = 0; break; case 'Z': malloc_zero = 1; break; default: @@ -468,14 +436,16 @@ malloc_init () if (malloc_zero) malloc_junk=1; -#ifdef MALLOC_STATS - if (malloc_stats) - atexit(malloc_exit); -#endif /* MALLOC_STATS */ + /* + * If we run with junk (or implicitly from above: zero), we want to + * force realloc() to get new storage, so we can DTRT with it. + */ + if (malloc_junk) + malloc_realloc=1; /* Allocate one page for the page directory */ - page_dir = (struct pginfo **) mmap(0, malloc_pagesize, PROT_READ|PROT_WRITE, - MAP_ANON|MAP_PRIVATE, -1, 0); + page_dir = (struct pginfo **) MMAP(malloc_pagesize); + if (page_dir == (struct pginfo **) -1) wrterror("mmap(2) failed, check limits.\n"); @@ -488,9 +458,6 @@ malloc_init () malloc_ninfo = malloc_pagesize / sizeof *page_dir; - /* Been here, done that */ - malloc_started++; - /* Recalculate the cache size in bytes, and make sure it's nonzero */ if (!malloc_cache) @@ -504,6 +471,8 @@ malloc_init () */ px = (struct pgfree *) imalloc (sizeof *px); + /* Been here, done that */ + malloc_started++; } /* @@ -520,6 +489,7 @@ malloc_pages(size_t size) size = pageround(size); p = 0; + /* Look for free pages before asking for more */ for(pf = free_list.next; pf; pf = pf->next) { @@ -725,9 +695,6 @@ imalloc(size_t size) { void *result; - if (!malloc_started) - malloc_init(); - if (suicide) abort(); @@ -759,12 +726,7 @@ irealloc(void *ptr, size_t size) int i; if (suicide) - return 0; - - if (!malloc_started) { - wrtwarning("malloc() has never been called.\n"); - return 0; - } + abort(); index = ptr2index(ptr); @@ -833,7 +795,9 @@ irealloc(void *ptr, size_t size) if (p) { /* copy the lesser of the two sizes, and free the old one */ - if (osize < size) + if (!size || !osize) + ; + else if (osize < size) memcpy(p, ptr, osize); else memcpy(p, ptr, size); @@ -1082,18 +1046,6 @@ ifree(void *ptr) * These are the public exported interface routines. */ -#ifdef _THREAD_SAFE -#include <pthread.h> -#include "pthread_private.h" -static int malloc_lock; -#define THREAD_LOCK() _thread_kern_sig_block(&malloc_lock); -#define THREAD_UNLOCK() _thread_kern_sig_unblock(malloc_lock); -#else -#define THREAD_LOCK() -#define THREAD_UNLOCK() -#endif - -static int malloc_active; void * malloc(size_t size) @@ -1107,10 +1059,17 @@ malloc(size_t size) malloc_active--; return (0); } - r = imalloc(size); + if (!malloc_started) + malloc_init(); + if (malloc_sysv && !size) + r = 0; + else + r = imalloc(size); UTRACE(0, size, r); malloc_active--; THREAD_UNLOCK(); + if (malloc_xmalloc && !r) + wrterror("out of memory.\n"); return (r); } @@ -1143,16 +1102,25 @@ realloc(void *ptr, size_t size) malloc_active--; return (0); } - if (!ptr) { - r = imalloc(size); - } else if (ptr && !size) { + if (ptr && !malloc_started) { + wrtwarning("malloc() has never been called.\n"); + ptr = 0; + } + if (!malloc_started) + malloc_init(); + if (malloc_sysv && !size) { ifree(ptr); r = 0; + } else if (!ptr) { + r = imalloc(size); } else { r = irealloc(ptr, size); } UTRACE(ptr, size, r); malloc_active--; THREAD_UNLOCK(); + if (malloc_xmalloc && !r) + wrterror("out of memory.\n"); return (r); } + |
