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>
This commit is contained in:
Poul-Henning Kamp 1997-06-22 17:54:27 +00:00
parent 8de2b8b504
commit e3553c0365
5 changed files with 399 additions and 487 deletions

View File

@ -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

View File

@ -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 .

View File

@ -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);
}

View File

@ -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 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.
.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
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
and scan them for flags in that order.
Flags are single letters, uppercase means on, lowercase means off.
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'' :-)
.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
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
The following is a brief description of possible error messages and
their meanings:
.Pp
.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
.Bl -tag -width indent
The following is a brief description of possible warning messages and
their meanings:
.Pp
.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
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
has been modified.
.It "pointer to wrong page
The pointer that
.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.
.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
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.
.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 <phk@FreeBSD.org> .
.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.

View File

@ -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 <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__)
#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 <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
/*
* 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);
}