summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorphk <phk@FreeBSD.org>1997-06-22 17:54:27 +0000
committerphk <phk@FreeBSD.org>1997-06-22 17:54:27 +0000
commite682320b6b4ec6dadaaa13a6cbeb428242eac686 (patch)
tree15d9e10f5c4d9600616dea47bc017c23b30b8df4
parent711f7235a180f520b0c1eb667d0519ae5792bdfa (diff)
downloadFreeBSD-src-e682320b6b4ec6dadaaa13a6cbeb428242eac686.zip
FreeBSD-src-e682320b6b4ec6dadaaa13a6cbeb428242eac686.tar.gz
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 <bostic@bostic.com> Submitted by: Keith Bostic <bostic@bostic.com>
-rw-r--r--lib/libc/stdlib/Makefile.inc8
-rw-r--r--lib/libc/stdlib/calloc.371
-rw-r--r--lib/libc/stdlib/calloc.c52
-rw-r--r--lib/libc/stdlib/malloc.3494
-rw-r--r--lib/libc/stdlib/malloc.c243
5 files changed, 390 insertions, 478 deletions
diff --git a/lib/libc/stdlib/Makefile.inc b/lib/libc/stdlib/Makefile.inc
index cf6be9e..980dd57 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 6c79272..0000000
--- 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 7a83603..0000000
--- 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 479ab00..a0262c1 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 446f55d..fb770f5 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);
+}
OpenPOWER on IntegriCloud