diff options
| author | Poul-Henning Kamp <phk@FreeBSD.org> | 1997-06-22 17:54:27 +0000 | 
|---|---|---|
| committer | Poul-Henning Kamp <phk@FreeBSD.org> | 1997-06-22 17:54:27 +0000 | 
| commit | e3553c0365db7315346fcc7df012818fbc126766 (patch) | |
| tree | f781af3328ad052da13abf21eb21410a5ac77bfe /lib/libc/stdlib | |
| parent | 8de2b8b5046595f4b796f4c5426c8c0a3c5ac08e (diff) | |
Notes
Diffstat (limited to 'lib/libc/stdlib')
| -rw-r--r-- | lib/libc/stdlib/Makefile.inc | 8 | ||||
| -rw-r--r-- | lib/libc/stdlib/calloc.3 | 71 | ||||
| -rw-r--r-- | lib/libc/stdlib/calloc.c | 52 | ||||
| -rw-r--r-- | lib/libc/stdlib/malloc.3 | 494 | ||||
| -rw-r--r-- | lib/libc/stdlib/malloc.c | 243 | 
5 files changed, 390 insertions, 478 deletions
| diff --git a/lib/libc/stdlib/Makefile.inc b/lib/libc/stdlib/Makefile.inc index cf6be9ea4e0b..980dd57cbcce 100644 --- a/lib/libc/stdlib/Makefile.inc +++ b/lib/libc/stdlib/Makefile.inc @@ -1,10 +1,10 @@  #	from @(#)Makefile.inc	8.3 (Berkeley) 2/4/95 -#	$Id$ +#	$Id: Makefile.inc,v 1.8 1997/05/03 03:50:04 jb Exp $  # machine-independent stdlib sources  .PATH: ${.CURDIR}/../libc/${MACHINE}/stdlib ${.CURDIR}/../libc/stdlib -SRCS+=	abort.c atexit.c atof.c atoi.c atol.c bsearch.c calloc.c div.c \ +SRCS+=	abort.c atexit.c atof.c atoi.c atol.c bsearch.c div.c \  	exit.c getenv.c getopt.c getsubopt.c strhash.c heapsort.c labs.c \  	ldiv.c malloc.c merge.c putenv.c qsort.c radixsort.c rand.c random.c \  	realpath.c setenv.c strtod.c strtol.c strtoq.c strtoul.c \ @@ -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 \ @@ -31,5 +31,5 @@ MLINKS+=random.3 initstate.3 random.3 setstate.3 random.3 srandom.3 \  	random.3 srandomdev.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 6c79272296ac..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$ -.\" -.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/calloc.c b/lib/libc/stdlib/calloc.c deleted file mode 100644 index 7a836030d5b0..000000000000 --- a/lib/libc/stdlib/calloc.c +++ /dev/null @@ -1,52 +0,0 @@ -/*- - * Copyright (c) 1990, 1993 - *	The Regents of the University of California.  All rights reserved. - * - * 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. - */ - -#if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)calloc.c	8.1 (Berkeley) 6/4/93"; -#endif /* LIBC_SCCS and not lint */ - -#include <stdlib.h> -#include <string.h> - -void * -calloc(num, size) -	size_t num; -	register size_t size; -{ -	register void *p; - -	size *= num; -	if ( (p = malloc(size)) ) -		bzero(p, size); -	return(p); -} diff --git a/lib/libc/stdlib/malloc.3 b/lib/libc/stdlib/malloc.3 index 479ab002db40..a0262c1245fa 100644 --- a/lib/libc/stdlib/malloc.3 +++ b/lib/libc/stdlib/malloc.3 @@ -34,288 +34,380 @@  .\" SUCH DAMAGE.  .\"  .\"     @(#)malloc.3	8.1 (Berkeley) 6/4/93 -.\"     $Id: malloc.3,v 1.10 1997/05/30 20:39:32 phk Exp $ +.\"     $Id: malloc.3,v 1.11 1997/06/12 12:45:45 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 +.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 -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. +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 alloction 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 +and +.Fn realloc +will be initialized to 0xd0. +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 -``sysV'' operations that attempt to allocate zero bytes will -return a null pointer.  Be aware of the conflict if you also -have ``X'' set. - +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 -``xmalloc''  -rather than return failure, -.Xr abort 3 -the program with a diagnostic message on stderr. -It is the intention that this option be set at compile time by -including in the source: +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. - +Initialize all allocated memory to nul bytes, and overwrite any +surrounding memory necessary for alignment reasons with 0xd0 bytes. +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. -.Pp -Here is a brief description of the error messages and what they mean: -.Pp -``(ES): mumble mumble mumble'': -malloc have been compiled with -DEXTRA_SANITY and something looks -fishy in there.  Consult sources and/or wizards. -.Pp -``allocation failed'' -if the ``A'' option is specified it is an error for -.Fn malloc -or  -.Fn realloc -to return NULL. -.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. +function returns no value. +.Sh "DEBUGGING MALLOC PROBLEMS"  .Pp -``freelist is destroyed.'' -mallocs internal freelist has been stomped on. +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 -Here is a brief description of the warning messages and what they mean: +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 -``chunk/page is already free.'' -A pointer to a free chunk is attempted freed again. +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 -``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. +It is probably also a good idea to recompile the program with suitable +options and symbols for debugger support.  .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. +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 -``malloc() has never been called.'' -Nothing has ever been allocated, yet something is being freed or -realloc'ed. +Alternatively, if the symptoms are not easy to reproduce, setting the +.Dq J +option may help provoke the problem.  .Pp -``modified (chunk-/page-) pointer.'' -The pointer passed to free or realloc has been modified. +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 -``pointer to wrong page.'' -The pointer that malloc is trying to free is not pointing to -a sensible page. +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 -``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. +The following is a brief description of possible error messages and +their meanings:  .Pp -``out of memory'' -The ``X'' flag is active and an allocation of memory failed. +.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 -``open of /dev/zero'' -On certain architectures /dev/zero is used as a source of  -anonymous pages for the page directory, opening failed. +.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 BUGS +The messages printed in case of problems provide no detail about the +actual values. +.Pp  It can be argued that returning a null pointer when asked to  allocate zero bytes is a silly response to a silly question. -.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.  .Pp -The main difference from other malloc implementations are believed to be that -the free pages are not accessed unless 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. -.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 446f55db290b..fb770f5d1886 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.24 1997/06/04 12:55:49 jb Exp $ + * $Id: malloc.c,v 1.25 1997/06/12 12:45:45 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,16 +42,31 @@   *   */ -#if defined(__i386__) && defined(__FreeBSD__) -#   define malloc_pageshift		12U -#   define malloc_minsize		16U -#endif /* __i386__ && __FreeBSD__ */ - -#if defined(__sparc__) +#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  #   define MAP_ANON			(0) -#   define USE_DEV_ZERO +    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__ */ @@ -68,31 +74,20 @@  #if defined(__FOOCPU__) && defined(__BAROS__)  #   define malloc_pageshift		12U  #   define malloc_minsize		16U -#endif /* __i386__ && __FreeBSD__ */ - -#ifdef _THREAD_SAFE -#include <pthread.h> -#include "pthread_private.h" -static struct pthread_mutex	_malloc_lock = PTHREAD_MUTEX_INITIALIZER; -static pthread_mutex_t malloc_lock = &_malloc_lock; -#define THREAD_LOCK()		pthread_mutex_lock(&malloc_lock) -#define THREAD_UNLOCK()		pthread_mutex_unlock(&malloc_lock) -#else -#define THREAD_LOCK() -#define THREAD_UNLOCK() -#endif +#endif /* __FOORCPU__ && __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 <fcntl.h> -#include <errno.h> -#include <sys/types.h> -#include <sys/mman.h>  /*   * This structure describes a page worth of chunks. @@ -117,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 */  };  /* @@ -143,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 @@ -165,21 +156,28 @@ struct pgfree {  #define pageround(foo) (((foo) + (malloc_pagemask))&(~(malloc_pagemask)))  #define ptr2index(foo) (((u_long)(foo) >> malloc_pageshift)-malloc_origo) -/* fd of /dev/zero */ -#ifdef USE_DEV_ZERO -static int fdzero; -#define	MMAP_FD	fdzero -#define INIT_MMAP() \ -	{ if ((fdzero=open("/dev/zero", O_RDWR, 0000)) == -1) \ -	    wrterror("open of /dev/zero"); } -#else +#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; @@ -204,9 +202,6 @@ static int malloc_abort;  /* Are we trying to die ?  */  static int suicide; -/* dump statistics */ -static int malloc_stats; -  /* always realloc ?  */  static int malloc_realloc; @@ -228,7 +223,7 @@ static int malloc_junk;  /* utrace ?  */  static int malloc_utrace; -#ifdef __FreeBSD__ +#ifdef HAS_UTRACE  struct ut { void *p; size_t s; void *r; };  void utrace __P((struct ut *, int)); @@ -236,7 +231,7 @@ 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 @@ -265,79 +260,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(2, __progname, strlen(__progname)); -    write(2, malloc_func, strlen(malloc_func)); -    write(2, q, strlen(q)); -    write(2, p, strlen(p)); +    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; -#ifdef MALLOC_STATS -    if (malloc_stats) -	malloc_dump(stderr); -#endif /* MALLOC_STATS */      abort();  } @@ -347,26 +280,12 @@ 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)); +    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));  } -#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)); -} -#endif /* MALLOC_STATS */ -  /*   * Allocate a number of pages from the OS @@ -481,8 +400,6 @@ 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; @@ -516,11 +433,6 @@ malloc_init ()      if (malloc_zero)  	malloc_junk=1; -#ifdef MALLOC_STATS -    if (malloc_stats) -	atexit(malloc_exit); -#endif /* MALLOC_STATS */ -      /* Allocate one page for the page directory */      page_dir = (struct pginfo **) MMAP(malloc_pagesize); @@ -568,6 +480,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) { @@ -779,9 +692,7 @@ imalloc(size_t size)      if (suicide)  	abort(); -    if (malloc_sysv && !size) -	result = 0; -    else if ((size + malloc_pagesize) < size)	/* Check for overflow */ +    if ((size + malloc_pagesize) < size)	/* Check for overflow */  	result = 0;      else if (size <= malloc_maxsize)  	result =  malloc_bytes(size); @@ -883,7 +794,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); @@ -1132,13 +1045,14 @@ ifree(void *ptr)   * These are the public exported interface routines.   */ -static int malloc_active;  void *  malloc(size_t size)  {      register void *r; +    if (malloc_sysv && !size) +	return (0);      malloc_func = " in malloc():";      THREAD_LOCK();      if (malloc_active++) { @@ -1184,7 +1098,10 @@ realloc(void *ptr, size_t size)          malloc_active--;  	return (0);      } -    if (!ptr) { +    if (malloc_sysv && !size) { +	ifree(ptr); +	r = 0; +    } else if (!ptr) {  	r = imalloc(size);      } else {          r = irealloc(ptr, size); @@ -1196,3 +1113,29 @@ realloc(void *ptr, size_t size)  	wrterror("out of memory.\n");      return (r);  } + +void * +calloc(size_t num, size_t size) +{ +    register void *r; + +    size *= num; +    if (malloc_sysv && !size) +	return (0); +    malloc_func = " in calloc():"; +    THREAD_LOCK(); +    if (malloc_active++) { +	wrtwarning("recursive call.\n"); +        malloc_active--; +	return (0); +    } +    r = imalloc(size); +    UTRACE(0, size, r); +    malloc_active--; +    THREAD_UNLOCK(); +    if (malloc_xmalloc && !r) +	wrterror("out of memory.\n"); +    if (r) +	memset(r, 0, size); +    return (r); +} | 
