From e3553c0365db7315346fcc7df012818fbc126766 Mon Sep 17 00:00:00 2001 From: Poul-Henning Kamp Date: Sun, 22 Jun 1997 17:54:27 +0000 Subject: [PATCH] Integrate calloc with the rest of the gang. Various portability and stylistic cleanups. Kill MALLOC_STATS & the 'D' option. Fix the 'V' option. Major overhaul of the man-page. You milage should not vary. Reviewed by: Keith Bostic Submitted by: Keith Bostic --- lib/libc/stdlib/Makefile.inc | 8 +- lib/libc/stdlib/calloc.3 | 71 ----- lib/libc/stdlib/calloc.c | 52 ---- lib/libc/stdlib/malloc.3 | 516 +++++++++++++++++++++-------------- lib/libc/stdlib/malloc.c | 239 ++++++---------- 5 files changed, 399 insertions(+), 487 deletions(-) delete mode 100644 lib/libc/stdlib/calloc.3 delete mode 100644 lib/libc/stdlib/calloc.c 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 -.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 -#include - -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 .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 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 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 +is valid and unchanged. +If +.Fa ptr +is NULL, the +.Fn realloc +function behaves identically to +.Fn malloc +for the specified size. .Pp The .Fn free -function causes the space pointed to by +function causes the allocated memory referenced 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 . +to be made available for future allocations. If .Fa ptr -is a null pointer, no action occurs. +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 -The -.Fn realloc -function changes the size of the object pointed to 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. -If -.Fa ptr -is a null pointer, 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 -.Fa ptr -is unchanged. -If -.Fa size -is zero and -.Fa ptr -is not a null pointer, the object it points to is freed. +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 -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. +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'' :-) - -.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. - -.It R -``realloc'' always reallocate when +Each byte of new memory allocated by +.Fn malloc +and .Fn realloc -is called, even if the initial allocation was big enough. +will be initialized to 0xd0. +This is intended for debugging and will impact performance negatively. +.It H +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 +Cause the +.Fn realloc +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 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 free function returns no value. +.Sh "DEBUGGING MALLOC PROBLEMS" .Pp -The -.Fn realloc -function returns either a null pointer or a pointer -to the possibly moved allocated space. -.Sh MESSAGES +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 +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 +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 +It is probably also a good idea to recompile the program with suitable +options and symbols for debugger support. +.Pp +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 +Alternatively, if the symptoms are not easy to reproduce, setting the +.Dq J +option may help provoke the problem. +.Pp +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 +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 -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. +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 -Here is a brief description of the error messages and what they mean: +The following is a brief description of possible error messages and +their meanings: .Pp -``(ES): mumble mumble mumble'': -malloc have been compiled with -DEXTRA_SANITY and something looks -fishy in there. Consult sources and/or wizards. +.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 -``allocation failed'' -if the ``A'' option is specified it is an error for -.Fn malloc -or -.Fn realloc -to return NULL. +.Bl -tag -width indent +The following is a brief description of possible warning messages and +their meanings: .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. -.Pp -``freelist is destroyed.'' -mallocs internal freelist has been stomped on. -.Pp -Here is a brief description of the warning messages and what they mean: -.Pp -``chunk/page is already free.'' -A pointer to a free chunk is attempted freed again. -.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 +.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. -.Pp -``modified (chunk-/page-) pointer.'' -The pointer passed to free or realloc has been modified. -.Pp -``pointer to wrong page.'' -The pointer that malloc is trying to free is not pointing to -a sensible page. -.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. -.Pp -``out of memory'' -The ``X'' flag is active and an allocation of memory failed. -.Pp -``open of /dev/zero'' -On certain architectures /dev/zero is used as a source of -anonymous pages for the page directory, opening failed. -.Pp -``unknown char in MALLOC_OPTIONS'' -we found something we didn't understand. +.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. +.Pp +This implementation was authored by Poul-Henning Kamp. +Please report any problems to him at +.Li . .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. +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 $ * */ @@ -21,15 +21,6 @@ #undef MALLOC_EXTRA_SANITY #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(__FreeBSD__) +# if defined(__i386__) +# define malloc_pageshift 12U +# define malloc_minsize 16U +# endif +# define HAS_UTRACE +# if defined(_THREAD_SAFE) +# include +# 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__) +#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__ */ +#endif /* __FOORCPU__ && __BAROS__ */ -#ifdef _THREAD_SAFE -#include -#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 /* * No user serviceable parts behind this point. */ +#include +#include +#include +#include #include #include #include #include -#include -#include -#include -#include /* * 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)-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); +}