summaryrefslogtreecommitdiffstats
path: root/lib/libc/stdlib
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libc/stdlib')
-rw-r--r--lib/libc/stdlib/Makefile.inc17
-rw-r--r--lib/libc/stdlib/abort.38
-rw-r--r--lib/libc/stdlib/abort.c23
-rw-r--r--lib/libc/stdlib/abs.37
-rw-r--r--lib/libc/stdlib/alloca.34
-rw-r--r--lib/libc/stdlib/atexit.c3
-rw-r--r--lib/libc/stdlib/atoi.c1
-rw-r--r--lib/libc/stdlib/bsearch.32
-rw-r--r--lib/libc/stdlib/calloc.35
-rw-r--r--lib/libc/stdlib/calloc.c2
-rw-r--r--lib/libc/stdlib/exit.36
-rw-r--r--lib/libc/stdlib/getenv.c44
-rw-r--r--lib/libc/stdlib/getopt.314
-rw-r--r--lib/libc/stdlib/getsubopt.33
-rw-r--r--lib/libc/stdlib/getsubopt.c3
-rw-r--r--lib/libc/stdlib/heapsort.c3
-rw-r--r--lib/libc/stdlib/labs.32
-rw-r--r--lib/libc/stdlib/ldiv.32
-rw-r--r--lib/libc/stdlib/malloc.3232
-rw-r--r--lib/libc/stdlib/malloc.c1442
-rw-r--r--lib/libc/stdlib/memory.35
-rw-r--r--lib/libc/stdlib/merge.c4
-rw-r--r--lib/libc/stdlib/qsort.c34
-rw-r--r--lib/libc/stdlib/radixsort.33
-rw-r--r--lib/libc/stdlib/radixsort.c10
-rw-r--r--lib/libc/stdlib/random.342
-rw-r--r--lib/libc/stdlib/random.c70
-rw-r--r--lib/libc/stdlib/realpath.c2
-rw-r--r--lib/libc/stdlib/setenv.c7
-rw-r--r--lib/libc/stdlib/strhash.c436
-rw-r--r--lib/libc/stdlib/strtod.c72
-rw-r--r--lib/libc/stdlib/strtol.c6
-rw-r--r--lib/libc/stdlib/strtoll.c138
-rw-r--r--lib/libc/stdlib/strtoq.c6
-rw-r--r--lib/libc/stdlib/strtoul.c6
-rw-r--r--lib/libc/stdlib/strtoull.c116
-rw-r--r--lib/libc/stdlib/strtouq.c8
-rw-r--r--lib/libc/stdlib/system.35
-rw-r--r--lib/libc/stdlib/system.c52
39 files changed, 2307 insertions, 538 deletions
diff --git a/lib/libc/stdlib/Makefile.inc b/lib/libc/stdlib/Makefile.inc
index 5298202..81e8ed0 100644
--- a/lib/libc/stdlib/Makefile.inc
+++ b/lib/libc/stdlib/Makefile.inc
@@ -4,18 +4,22 @@
.PATH: ${.CURDIR}/${MACHINE}/stdlib ${.CURDIR}/stdlib
SRCS+= abort.c atexit.c atof.c atoi.c atol.c bsearch.c calloc.c div.c \
- exit.c getenv.c getopt.c getsubopt.c heapsort.c labs.c ldiv.c \
- malloc.c merge.c putenv.c qsort.c radixsort.c rand.c random.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 \
strtouq.c system.c
# machine-dependent stdlib sources
.include "${.CURDIR}/${MACHINE}/stdlib/Makefile.inc"
-MAN3+= abort.0 abs.0 alloca.0 atexit.0 atof.0 atoi.0 atol.0 bsearch.0 \
- calloc.0 div.0 exit.0 free.0 getenv.0 getopt.0 getsubopt.0 labs.0 \
- ldiv.0 malloc.0 memory.0 qsort.0 radixsort.0 rand.0 random.0 \
- realloc.0 realpath.0 strtod.0 strtol.0 strtoul.0 system.0
+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/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 \
+ stdlib/realpath.3 stdlib/strtod.3 stdlib/strtol.3 stdlib/strtoul.3 \
+ stdlib/system.3
MLINKS+=getenv.3 setenv.3 getenv.3 unsetenv.3 getenv.3 putenv.3
MLINKS+=qsort.3 heapsort.3 qsort.3 mergesort.3
@@ -23,3 +27,4 @@ MLINKS+=rand.3 srand.3
MLINKS+=random.3 initstate.3 random.3 setstate.3 random.3 srandom.3
MLINKS+=strtol.3 strtoq.3
MLINKS+=strtoul.3 strtouq.3
+MLINKS+=malloc.3 free.3 malloc.3 realloc.3
diff --git a/lib/libc/stdlib/abort.3 b/lib/libc/stdlib/abort.3
index 83b4e04..17717e9 100644
--- a/lib/libc/stdlib/abort.3
+++ b/lib/libc/stdlib/abort.3
@@ -53,18 +53,18 @@ signal
.Dv SIGABRT
is being caught and the signal handler does not return.
.Pp
-No open streams are closed or flushed.
+Any open streams are flushed and closed.
.Sh RETURN VALUES
The
-.Nm abort
+.Fn abort
function
never returns.
.Sh SEE ALSO
.Xr sigaction 2 ,
-.Xr exit 2
+.Xr exit 3
.Sh STANDARDS
The
.Fn abort
function
conforms to
-.St -ansiC .
+.St -p1003.1-90 .
diff --git a/lib/libc/stdlib/abort.c b/lib/libc/stdlib/abort.c
index e56e7e9..4fd34dc 100644
--- a/lib/libc/stdlib/abort.c
+++ b/lib/libc/stdlib/abort.c
@@ -35,31 +35,52 @@
static char sccsid[] = "@(#)abort.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/signal.h>
+#include <signal.h>
#include <stdlib.h>
#include <stddef.h>
#include <unistd.h>
+#ifdef _THREAD_SAFE
+#include <pthread.h>
+#include "pthread_private.h"
+#endif
+
+void (*__cleanup)();
void
abort()
{
sigset_t mask;
+ /*
+ * POSIX requires we flush stdio buffers on abort
+ */
+ if (__cleanup)
+ (*__cleanup)();
+
sigfillset(&mask);
/*
* don't block SIGABRT to give any handler a chance; we ignore
* any errors -- X311J doesn't allow abort to return anyway.
*/
sigdelset(&mask, SIGABRT);
+#ifdef _THREAD_SAFE
+ (void) _thread_sys_sigprocmask(SIG_SETMASK, &mask, (sigset_t *)NULL);
+#else
(void)sigprocmask(SIG_SETMASK, &mask, (sigset_t *)NULL);
+#endif
(void)kill(getpid(), SIGABRT);
/*
* if SIGABRT ignored, or caught and the handler returns, do
* it again, only harder.
*/
+#ifdef _THREAD_SAFE
+ (void) _thread_sys_signal(SIGABRT, SIG_DFL);
+ (void) _thread_sys_sigprocmask(SIG_SETMASK, &mask, (sigset_t *)NULL);
+#else
(void)signal(SIGABRT, SIG_DFL);
(void)sigprocmask(SIG_SETMASK, &mask, (sigset_t *)NULL);
+#endif
(void)kill(getpid(), SIGABRT);
exit(1);
}
diff --git a/lib/libc/stdlib/abs.3 b/lib/libc/stdlib/abs.3
index e12f798..501263e 100644
--- a/lib/libc/stdlib/abs.3
+++ b/lib/libc/stdlib/abs.3
@@ -34,6 +34,7 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)abs.3 8.1 (Berkeley) 6/4/93
+.\" $Id$
.\"
.Dd June 4, 1993
.Dt ABS 3
@@ -59,10 +60,10 @@ function
returns
the absolute value.
.Sh SEE ALSO
+.Xr cabs 3 ,
.Xr floor 3 ,
-.Xr labs 3
-.Xr cabs 3
-.Xr hypot 3
+.Xr hypot 3 ,
+.Xr labs 3 ,
.Xr math 3
.Sh STANDARDS
The
diff --git a/lib/libc/stdlib/alloca.3 b/lib/libc/stdlib/alloca.3
index ad5aaf69..498348c 100644
--- a/lib/libc/stdlib/alloca.3
+++ b/lib/libc/stdlib/alloca.3
@@ -59,10 +59,10 @@ If the allocation failed, a
pointer is returned.
.Sh SEE ALSO
.Xr brk 2 ,
-.Xr pagesize 2
.Xr calloc 3 ,
+.Xr getpagesize 3 ,
.Xr malloc 3 ,
-.Xr realloc 3 ,
+.Xr realloc 3
.Sh BUGS
The
.Fn alloca
diff --git a/lib/libc/stdlib/atexit.c b/lib/libc/stdlib/atexit.c
index 9c4caed..ea2a7e2 100644
--- a/lib/libc/stdlib/atexit.c
+++ b/lib/libc/stdlib/atexit.c
@@ -40,6 +40,7 @@ static char sccsid[] = "@(#)atexit.c 8.1 (Berkeley) 6/4/93";
#include <stddef.h>
#include <stdlib.h>
+#include <unistd.h>
#include "atexit.h"
/*
@@ -55,7 +56,7 @@ atexit(fn)
if ((p = __atexit) == NULL)
__atexit = p = &__atexit0;
else if (p->ind >= ATEXIT_SIZE) {
- if ((p = malloc(sizeof(*p))) == NULL)
+ if ((p = (struct atexit *)sbrk(sizeof(*p))) == (struct atexit *)-1)
return (-1);
p->ind = 0;
p->next = __atexit;
diff --git a/lib/libc/stdlib/atoi.c b/lib/libc/stdlib/atoi.c
index a13c0e2..48e508a 100644
--- a/lib/libc/stdlib/atoi.c
+++ b/lib/libc/stdlib/atoi.c
@@ -38,6 +38,7 @@ static char sccsid[] = "@(#)atoi.c 8.1 (Berkeley) 6/4/93";
#include <stdlib.h>
#include <stddef.h>
+int
atoi(str)
const char *str;
{
diff --git a/lib/libc/stdlib/bsearch.3 b/lib/libc/stdlib/bsearch.3
index e4cf49f..a4e076e 100644
--- a/lib/libc/stdlib/bsearch.3
+++ b/lib/libc/stdlib/bsearch.3
@@ -81,7 +81,7 @@ If two members compare as equal, which member is matched is unspecified.
.Sh SEE ALSO
.Xr db 3 ,
.Xr lsearch 3 ,
-.Xr qsort 3 ,
+.Xr qsort 3
.\" .Xr tsearch 3
.Sh STANDARDS
The
diff --git a/lib/libc/stdlib/calloc.3 b/lib/libc/stdlib/calloc.3
index 0ca15e5..6c79272 100644
--- a/lib/libc/stdlib/calloc.3
+++ b/lib/libc/stdlib/calloc.3
@@ -34,6 +34,7 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)calloc.3 8.1 (Berkeley) 6/4/93
+.\" $Id$
.\"
.Dd June 4, 1993
.Dt CALLOC 3
@@ -60,9 +61,9 @@ function returns
a pointer to the
the allocated space if successful; otherwise a null pointer is returned.
.Sh SEE ALSO
-.Xr malloc 3 ,
-.Xr realloc 3 ,
.Xr free 3 ,
+.Xr malloc 3 ,
+.Xr realloc 3
.Sh STANDARDS
The
.Fn calloc
diff --git a/lib/libc/stdlib/calloc.c b/lib/libc/stdlib/calloc.c
index d7c8e07..7a83603 100644
--- a/lib/libc/stdlib/calloc.c
+++ b/lib/libc/stdlib/calloc.c
@@ -46,7 +46,7 @@ calloc(num, size)
register void *p;
size *= num;
- if (p = malloc(size))
+ if ( (p = malloc(size)) )
bzero(p, size);
return(p);
}
diff --git a/lib/libc/stdlib/exit.3 b/lib/libc/stdlib/exit.3
index 43ee3c0..de91276 100644
--- a/lib/libc/stdlib/exit.3
+++ b/lib/libc/stdlib/exit.3
@@ -65,6 +65,11 @@ Unlink all files created with the
.Xr tmpfile 3
function.
.El
+.Pp
+Passing arbitrary values back to the environment as
+.Ar status
+is considered bad style. Instead, use the values as described in
+.Xr sysexits 3 .
.Sh RETURN VALUES
The
.Fn exit
@@ -74,6 +79,7 @@ never returns.
.Xr _exit 2 ,
.Xr atexit 3 ,
.Xr intro 3 ,
+.Xr sysexits 3 ,
.Xr tmpfile 3
.Sh STANDARDS
The
diff --git a/lib/libc/stdlib/getenv.c b/lib/libc/stdlib/getenv.c
index 7407e0b..a6bbd35 100644
--- a/lib/libc/stdlib/getenv.c
+++ b/lib/libc/stdlib/getenv.c
@@ -39,20 +39,7 @@ static char sccsid[] = "@(#)getenv.c 8.1 (Berkeley) 6/4/93";
#include <stddef.h>
#include <string.h>
-char *__findenv __P((const char *, int *));
-
-/*
- * getenv --
- * Returns ptr to value associated with name, if any, else NULL.
- */
-char *
-getenv(name)
- const char *name;
-{
- int offset;
-
- return (__findenv(name, &offset));
-}
+inline char *__findenv __P((const char *, int *));
/*
* __findenv --
@@ -63,25 +50,42 @@ getenv(name)
*
* This routine *should* be a static; don't use it.
*/
-char *
+inline char *
__findenv(name, offset)
register const char *name;
int *offset;
{
extern char **environ;
- register int len;
+ register int len, i;
register const char *np;
- register char **p, *c;
+ register char **p, *cp;
if (name == NULL || environ == NULL)
return (NULL);
for (np = name; *np && *np != '='; ++np)
continue;
len = np - name;
- for (p = environ; (c = *p) != NULL; ++p)
- if (strncmp(c, name, len) == 0 && c[len] == '=') {
+ for (p = environ; (cp = *p) != NULL; ++p) {
+ for (np = name, i = len; i && *cp; i--)
+ if (*cp++ != *np++)
+ break;
+ if (i == 0 && *cp++ == '=') {
*offset = p - environ;
- return (c + len + 1);
+ return (cp);
}
+ }
return (NULL);
}
+
+/*
+ * getenv --
+ * Returns ptr to value associated with name, if any, else NULL.
+ */
+char *
+getenv(name)
+ const char *name;
+{
+ int offset;
+
+ return (__findenv(name, &offset));
+}
diff --git a/lib/libc/stdlib/getopt.3 b/lib/libc/stdlib/getopt.3
index 95ff6e6..3047183 100644
--- a/lib/libc/stdlib/getopt.3
+++ b/lib/libc/stdlib/getopt.3
@@ -122,9 +122,11 @@ The
function
returns an
.Dv EOF
-when the argument list is exhausted, or a non-recognized
+when the argument list is exhausted, or
+.Ql ?
+if a non-recognized
option is encountered.
-The interpretation of options in the argument list may be cancelled
+The interpretation of options in the argument list may be canceled
by the option
.Ql --
(double dash) which causes
@@ -142,10 +144,10 @@ If the
function encounters a character not found in the string
.Va optarg
or detects
-a missing option argument it writes an error message and returns
-.Ql ?
-to the
-.Em stderr .
+a missing option argument it writes an error message to the
+.Em stderr
+and returns
+.Ql ? .
Setting
.Va opterr
to a zero will disable these error messages.
diff --git a/lib/libc/stdlib/getsubopt.3 b/lib/libc/stdlib/getsubopt.3
index e1040d7..3f6f547 100644
--- a/lib/libc/stdlib/getsubopt.3
+++ b/lib/libc/stdlib/getsubopt.3
@@ -142,4 +142,5 @@ while ((ch = getopt(argc, argv, "ab:")) != \-1) {
.Sh HISTORY
The
.Fn getsubopt
-function first appeared in 4.4BSD.
+function first appeared in
+.Bx 4.4 .
diff --git a/lib/libc/stdlib/getsubopt.c b/lib/libc/stdlib/getsubopt.c
index d0ebde2..bc055b8 100644
--- a/lib/libc/stdlib/getsubopt.c
+++ b/lib/libc/stdlib/getsubopt.c
@@ -46,6 +46,7 @@ static char sccsid[] = "@(#)getsubopt.c 8.1 (Berkeley) 6/4/93";
*/
char *suboptarg;
+int
getsubopt(optionp, tokens, valuep)
register char **optionp, **valuep;
register char * const *tokens;
@@ -80,7 +81,7 @@ getsubopt(optionp, tokens, valuep)
*p = '\0';
for (*valuep = ++p;
*p && *p != ',' && *p != ' ' && *p != '\t'; ++p);
- if (*p)
+ if (*p)
*p++ = '\0';
} else
*p++ = '\0';
diff --git a/lib/libc/stdlib/heapsort.c b/lib/libc/stdlib/heapsort.c
index d800064..9649553 100644
--- a/lib/libc/stdlib/heapsort.c
+++ b/lib/libc/stdlib/heapsort.c
@@ -38,10 +38,9 @@
static char sccsid[] = "@(#)heapsort.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/types.h>
#include <errno.h>
-#include <stdlib.h>
#include <stddef.h>
+#include <stdlib.h>
/*
* Swap two areas of size number of bytes. Although qsort(3) permits random
diff --git a/lib/libc/stdlib/labs.3 b/lib/libc/stdlib/labs.3
index ef9ba80..2dba8cc 100644
--- a/lib/libc/stdlib/labs.3
+++ b/lib/libc/stdlib/labs.3
@@ -53,8 +53,8 @@ returns the absolute value of the long integer
.Ar j .
.Sh SEE ALSO
.Xr abs 3 ,
-.Xr floor 3 ,
.Xr cabs 3 ,
+.Xr floor 3 ,
.Xr math 3
.Sh STANDARDS
The
diff --git a/lib/libc/stdlib/ldiv.3 b/lib/libc/stdlib/ldiv.3
index a68952f..2b61499 100644
--- a/lib/libc/stdlib/ldiv.3
+++ b/lib/libc/stdlib/ldiv.3
@@ -44,7 +44,7 @@
.Sh SYNOPSIS
.Fd #include <stdlib.h>
.Ft ldiv_t
-.Fn ldiv "int num" "int denom"
+.Fn ldiv "long num" "long denom"
.Sh DESCRIPTION
The
.Fn ldiv
diff --git a/lib/libc/stdlib/malloc.3 b/lib/libc/stdlib/malloc.3
index 98ebadc..cd10039 100644
--- a/lib/libc/stdlib/malloc.3
+++ b/lib/libc/stdlib/malloc.3
@@ -34,17 +34,30 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)malloc.3 8.1 (Berkeley) 6/4/93
+.\" $Id$
.\"
-.Dd June 4, 1993
+.Dd August 27, 1996
.Dt MALLOC 3
-.Os BSD 4
+.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
.Sh SYNOPSIS
.Fd #include <stdlib.h>
.Ft void *
.Fn malloc "size_t size"
+.Ft void
+.Fn free "void *ptr"
+.Ft void *
+.Fn realloc "void *ptr" "size_t size"
+.Ft char *
+.Va malloc_options
.Sh DESCRIPTION
The
.Fn malloc
@@ -61,30 +74,221 @@ suitably aligned (after possible pointer
coercion) for storage of any type of object. If the space is of
.Em pagesize
or larger, the memory returned will be page-aligned.
+.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.
+.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
+.Va malloc_options
+and scan them for flags in that order.
+Flags are single letters, uppercase means on, lowercase means 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.
+
+.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
+.Fn realloc
+is called, even if the initial allocation was big enough.
+This can substantially aid in compacting memory.
+
+.It U
+``utrace'' generate entries for ktrace(1) for all operations.
+Consult the source for this one.
+
+.It Z
+``zero'' fill some junk into the area allocated (see ``J''),
+except for the exact length the user asked for, which is zeroed.
+
+.It <
+``Half the cache size'' Reduce the size of the cache by a factor of two.
+
+.It >
+``Double the cache size'' Double the size of the cache by a factor of two.
+.El
+.Pp
+So to set a systemwide reduction of cache size and coredumps on problems
+one would:
+.Li ln -s 'A<' /etc/malloc.conf
+.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.
+.Pp
+The default cache size is 16 pages.
+.Sh ENVIRONMENT
+See above.
.Sh RETURN VALUES
The
.Fn malloc
function returns
a pointer to the allocated space if successful; otherwise
a null pointer is returned.
+.Pp
+The
+.Fn free
+function returns no value.
+.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.
+.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
+``unknown char in MALLOC_OPTIONS''
+we found something we didn't understand.
.Sh SEE ALSO
.Xr brk 2 ,
-.Xr pagesize 2 ,
-.Xr free 3 ,
-.Xr calloc 3 ,
.Xr alloca 3 ,
-.Xr realloc 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
.St -ansiC .
-.Sh BUGS
-The current implementation of
-.Xr malloc
-does not always fail gracefully when system
-memory limits are approached.
-It may fail to allocate memory when larger free blocks could be broken
-up, or when limits are exceeded because the size is rounded up.
-It is optimized for sizes that are powers of two.
+.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 until allocated.
+Most malloc implementations will store a data structure containing a,
+possibly double-, linked list in the free chunks of memory, used to tie
+all the free memory together.
+That is a quite suboptimal thing to do.
+Every time the free-list is traversed, all the otherwise unused, and very
+likely paged out, pages get faulted into primary memory, just to see what
+lies after them in the list.
+.Pp
+On systems which are paging, this can make a factor five in difference on the
+page-faults of a process.
diff --git a/lib/libc/stdlib/malloc.c b/lib/libc/stdlib/malloc.c
index ea8f092..6462ad1 100644
--- a/lib/libc/stdlib/malloc.c
+++ b/lib/libc/stdlib/malloc.c
@@ -1,420 +1,1156 @@
/*
- * Copyright (c) 1983, 1993
- * The Regents of the University of California. All rights reserved.
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
*
- * 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.
+ * $Id$
*
- * 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[] = "@(#)malloc.c 8.1 (Berkeley) 6/4/93";
-#endif /* LIBC_SCCS and not lint */
+/*
+ * Defining EXTRA_SANITY will enable extra checks which are related
+ * to internal conditions and consistency in malloc.c. This has a
+ * noticeable runtime performance hit, and generally will not do you
+ * any good unless you fiddle with the internals of malloc or want
+ * to catch random pointer corruption as early as possible.
+ */
+#ifndef MALLOC_EXTRA_SANITY
+#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.
+ */
+#define SOME_JUNK 0xd0 /* as in "Duh" :-) */
/*
- * malloc.c (Caltech) 2/21/82
- * Chris Kingsley, kingsley@cit-20.
+ * The basic parameters you can tweak.
+ *
+ * malloc_pageshift pagesize = 1 << malloc_pageshift
+ * It's probably best if this is the native
+ * page size, but it shouldn't have to be.
+ *
+ * malloc_minsize minimum size of an allocation in bytes.
+ * If this is too small it's too much work
+ * to manage them. This is also the smallest
+ * unit of alignment used for the storage
+ * returned by malloc/realloc.
*
- * This is a very fast storage allocator. It allocates blocks of a small
- * number of different sizes, and keeps free lists of each size. Blocks that
- * don't exactly fit are passed up to the next larger size. In this
- * implementation, the available sizes are 2^n-4 (or 2^n-10) bytes long.
- * This is designed for use in a virtual memory environment.
*/
-#include <sys/types.h>
+#if defined(__i386__) && defined(__FreeBSD__)
+# define malloc_pageshift 12U
+# define malloc_minsize 16U
+#endif /* __i386__ && __FreeBSD__ */
+
+/* Insert your combination here... */
+#if defined(__FOOCPU__) && defined(__BAROS__)
+# define malloc_pageshift 12U
+# define malloc_minsize 16U
+#endif /* __i386__ && __FreeBSD__ */
+
+/*
+ * No user serviceable parts behind this point.
+ */
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/mman.h>
-#define NULL 0
+/*
+ * This structure describes a page worth of chunks.
+ */
-static void morecore();
-static int findbucket();
+struct pginfo {
+ struct pginfo *next; /* next on the free list */
+ void *page; /* Pointer to the page */
+ u_short size; /* size of this page's chunks */
+ u_short shift; /* How far to shift for this size chunks */
+ u_short free; /* How many free chunks */
+ u_short total; /* How many chunk */
+ u_int bits[1]; /* Which chunks are free */
+};
/*
- * The overhead on a block is at least 4 bytes. When free, this space
- * contains a pointer to the next free block, and the bottom two bits must
- * be zero. When in use, the first byte is set to MAGIC, and the second
- * byte is the size index. The remaining bytes are for alignment.
- * If range checking is enabled then a second word holds the size of the
- * requested block, less 1, rounded up to a multiple of sizeof(RMAGIC).
- * The order of elements is critical: ov_magic must overlay the low order
- * bits of ov_next, and ov_magic can not be a valid ov_next bit pattern.
+ * This structure describes a number of free pages.
*/
-union overhead {
- union overhead *ov_next; /* when free */
- struct {
- u_char ovu_magic; /* magic number */
- u_char ovu_index; /* bucket # */
-#ifdef RCHECK
- u_short ovu_rmagic; /* range magic number */
- u_int ovu_size; /* actual block size */
-#endif
- } ovu;
-#define ov_magic ovu.ovu_magic
-#define ov_index ovu.ovu_index
-#define ov_rmagic ovu.ovu_rmagic
-#define ov_size ovu.ovu_size
+
+struct pgfree {
+ struct pgfree *next; /* next run of free pages */
+ 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 */
};
-#define MAGIC 0xef /* magic # on accounting info */
-#define RMAGIC 0x5555 /* magic # on range info */
+/*
+ * How many bits per u_int in the bitmap.
+ * Change only if not 8 bits/byte
+ */
+#define MALLOC_BITS (8*sizeof(u_int))
+
+/*
+ * Magic values to put in the page_directory
+ */
+#define MALLOC_NOT_MINE ((struct pginfo*) 0)
+#define MALLOC_FREE ((struct pginfo*) 1)
+#define MALLOC_FIRST ((struct pginfo*) 2)
+#define MALLOC_FOLLOW ((struct pginfo*) 3)
+#define MALLOC_MAGIC ((struct pginfo*) 4)
-#ifdef RCHECK
-#define RSLOP sizeof (u_short)
-#else
-#define RSLOP 0
+#ifndef malloc_pageshift
+#define malloc_pageshift 12U
+#endif
+
+#ifndef malloc_minsize
+#define malloc_minsize 16U
+#endif
+
+#ifndef malloc_pageshift
+#error "malloc_pageshift undefined"
+#endif
+
+#if !defined(malloc_pagesize)
+#define malloc_pagesize (1U<<malloc_pageshift)
+#endif
+
+#if ((1<<malloc_pageshift) != malloc_pagesize)
+#error "(1<<malloc_pageshift) != malloc_pagesize"
+#endif
+
+#ifndef malloc_maxsize
+#define malloc_maxsize ((malloc_pagesize)>>1)
#endif
+/* A mask for the offset inside a page. */
+#define malloc_pagemask ((malloc_pagesize)-1)
+
+#define pageround(foo) (((foo) + (malloc_pagemask))&(~(malloc_pagemask)))
+#define ptr2index(foo) (((u_long)(foo) >> malloc_pageshift)-malloc_origo)
+
+/* Set when initialization has been done */
+static unsigned malloc_started;
+
+/* Number of free pages we cache */
+static unsigned malloc_cache = 16;
+
+/* The offset from pagenumber to index into the page directory */
+static u_long malloc_origo;
+
+/* The last index in the page directory we care about */
+static u_long last_index;
+
+/* Pointer to page directory. Allocated "as if with" malloc */
+static struct pginfo **page_dir;
+
+/* How many slots in the page directory */
+static unsigned malloc_ninfo;
+
+/* Free pages line up here */
+static struct pgfree free_list;
+
+/* Abort(), user doesn't handle problems. */
+static int malloc_abort;
+
+/* Are we trying to die ? */
+static int suicide;
+
+/* dump statistics */
+static int malloc_stats;
+
+/* always realloc ? */
+static int malloc_realloc;
+
+/* pass the kernel a hint on free pages ? */
+static int malloc_hint;
+
+/* zero fill ? */
+static int malloc_zero;
+
+/* junk fill ? */
+static int malloc_junk;
+
+/* utrace ? */
+static int malloc_utrace;
+
+#ifdef __FreeBSD__
+struct ut { void *p; size_t s; void *r; };
+
+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__ */
+#define UTRACE(a,b,c)
+#endif
+
+/* my last break. */
+static void *malloc_brk;
+
+/* one location cache for free-list holders */
+static struct pgfree *px;
+
+/* compile-time options */
+char *malloc_options;
+
+/* Name of the current public function */
+static char *malloc_func;
+
/*
- * nextf[i] is the pointer to the next free block of size 2^(i+3). The
- * smallest allocatable block is 8 bytes. The overhead information
- * precedes the data area returned to the user.
+ * Necessary function declarations
*/
-#define NBUCKETS 30
-static union overhead *nextf[NBUCKETS];
-extern char *sbrk();
+static int extend_pgdir(u_long index);
+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: ";
+ suicide = 1;
+ write(2, __progname, strlen(__progname));
+ write(2, malloc_func, strlen(malloc_func));
+ write(2, q, strlen(q));
+ write(2, p, strlen(p));
+#ifdef MALLOC_STATS
+ if (malloc_stats)
+ malloc_dump(stderr);
+#endif /* MALLOC_STATS */
+ abort();
+}
+
+static void
+wrtwarning(char *p)
+{
+ char *q = " warning: ";
+ if (malloc_abort)
+ wrterror(p);
+ write(2, __progname, strlen(__progname));
+ write(2, malloc_func, strlen(malloc_func));
+ write(2, q, strlen(q));
+ write(2, p, strlen(p));
+}
+
+#ifdef MALLOC_STATS
+static void
+malloc_exit()
+{
+ FILE *fd = fopen("malloc.out", "a");
+ char *q = "malloc() warning: Couldn't dump stats.\n";
+ if (fd) {
+ malloc_dump(fd);
+ fclose(fd);
+ } else
+ write(2, q, strlen(q));
+}
+#endif /* MALLOC_STATS */
-static int pagesz; /* page size */
-static int pagebucket; /* page size bucket */
-#ifdef MSTATS
/*
- * nmalloc[i] is the difference between the number of mallocs and frees
- * for a given block size.
+ * Allocate a number of pages from the OS
*/
-static u_int nmalloc[NBUCKETS];
-#include <stdio.h>
-#endif
+static caddr_t
+map_pages(int pages)
+{
+ caddr_t result, tail;
-#if defined(DEBUG) || defined(RCHECK)
-#define ASSERT(p) if (!(p)) botch("p")
-#include <stdio.h>
-static
-botch(s)
- char *s;
+ result = (caddr_t)pageround((u_long)sbrk(0));
+ tail = result + (pages << malloc_pageshift);
+
+ if (brk(tail)) {
+#ifdef EXTRA_SANITY
+ wrterror("(ES): map_pages fails\n");
+#endif /* EXTRA_SANITY */
+ return 0;
+ }
+
+ last_index = ptr2index(tail) - 1;
+ malloc_brk = tail;
+
+ if ((last_index+1) >= malloc_ninfo && !extend_pgdir(last_index))
+ return 0;;
+
+ return result;
+}
+
+/*
+ * Extend page directory
+ */
+static int
+extend_pgdir(u_long index)
{
- fprintf(stderr, "\r\nassertion botched: %s\r\n", s);
- (void) fflush(stderr); /* just in case user buffered it */
- abort();
+ struct pginfo **new, **old;
+ int i, oldlen;
+
+ /* Make it this many pages */
+ i = index * sizeof *page_dir;
+ i /= malloc_pagesize;
+ i += 2;
+
+ /* remember the old mapping size */
+ oldlen = malloc_ninfo * sizeof *page_dir;
+
+ /*
+ * NOTE: we allocate new pages and copy the directory rather than tempt
+ * fate by trying to "grow" the region.. There is nothing to prevent
+ * us from accidently re-mapping space that's been allocated by our caller
+ * via dlopen() or other mmap().
+ *
+ * The copy problem is not too bad, as there is 4K of page index per
+ * 4MB of malloc arena.
+ *
+ * We can totally avoid the copy if we open a file descriptor to associate
+ * the anon mappings with. Then, when we remap the pages at the new
+ * address, the old pages will be "magically" remapped.. But this means
+ * keeping open a "secret" file descriptor.....
+ */
+
+ /* Get new pages */
+ new = (struct pginfo**) mmap(0, i * malloc_pagesize, PROT_READ|PROT_WRITE,
+ MAP_ANON|MAP_PRIVATE, -1, 0);
+ if (new == (struct pginfo **)-1)
+ return 0;
+
+ /* Copy the old stuff */
+ memcpy(new, page_dir,
+ malloc_ninfo * sizeof *page_dir);
+
+ /* register the new size */
+ malloc_ninfo = i * malloc_pagesize / sizeof *page_dir;
+
+ /* swap the pointers */
+ old = page_dir;
+ page_dir = new;
+
+ /* Now free the old stuff */
+ munmap((caddr_t)old, oldlen);
+ return 1;
}
-#else
-#define ASSERT(p)
-#endif
-void *
-malloc(nbytes)
- size_t nbytes;
+/*
+ * Initialize the world
+ */
+static void
+malloc_init ()
{
- register union overhead *op;
- register int bucket, n;
- register unsigned amt;
+ char *p, b[64];
+ int i, j;
- /*
- * First time malloc is called, setup page size and
- * align break pointer so all data will be page aligned.
- */
- if (pagesz == 0) {
- pagesz = n = getpagesize();
- op = (union overhead *)sbrk(0);
- n = n - sizeof (*op) - ((int)op & (n - 1));
- if (n < 0)
- n += pagesz;
- if (n) {
- if (sbrk(n) == (char *)-1)
- return (NULL);
- }
- bucket = 0;
- amt = 8;
- while (pagesz > amt) {
- amt <<= 1;
- bucket++;
- }
- pagebucket = bucket;
- }
- /*
- * Convert amount of memory requested into closest block size
- * stored in hash buckets which satisfies request.
- * Account for space used per block for accounting.
- */
- if (nbytes <= (n = pagesz - sizeof (*op) - RSLOP)) {
-#ifndef RCHECK
- amt = 8; /* size of first bucket */
- bucket = 0;
-#else
- amt = 16; /* size of first bucket */
- bucket = 1;
-#endif
- n = -(sizeof (*op) + RSLOP);
+
+#ifdef EXTRA_SANITY
+ malloc_junk = 1;
+#endif /* EXTRA_SANITY */
+
+ for (i = 0; i < 3; i++) {
+ if (i == 0) {
+ j = readlink("/etc/malloc.conf", b, sizeof b - 1);
+ if (j <= 0)
+ continue;
+ b[j] = '\0';
+ p = b;
+ } else if (i == 1) {
+ p = getenv("MALLOC_OPTIONS");
} else {
- amt = pagesz;
- bucket = pagebucket;
+ p = malloc_options;
}
- while (nbytes > amt + n) {
- amt <<= 1;
- if (amt == 0)
- return (NULL);
- bucket++;
- }
- /*
- * If nothing in hash bucket right now,
- * request more memory from the system.
- */
- if ((op = nextf[bucket]) == NULL) {
- morecore(bucket);
- if ((op = nextf[bucket]) == NULL)
- return (NULL);
+ for (; p && *p; p++) {
+ switch (*p) {
+ case '>': malloc_cache <<= 1; break;
+ case '<': malloc_cache >>= 1; break;
+ case 'a': malloc_abort = 0; break;
+ case 'A': malloc_abort = 1; break;
+ case 'd': malloc_stats = 0; break;
+ case 'D': malloc_stats = 1; break;
+ case 'h': malloc_hint = 0; break;
+ case 'H': malloc_hint = 1; break;
+ case 'r': malloc_realloc = 0; break;
+ case 'R': malloc_realloc = 1; break;
+ case 'j': malloc_junk = 0; break;
+ case 'J': malloc_junk = 1; break;
+ case 'u': malloc_utrace = 0; break;
+ case 'U': malloc_utrace = 1; break;
+ case 'z': malloc_zero = 0; break;
+ case 'Z': malloc_zero = 1; break;
+ default:
+ j = malloc_abort;
+ malloc_abort = 0;
+ wrtwarning("unknown char in MALLOC_OPTIONS\n");
+ malloc_abort = j;
+ break;
+ }
}
- /* remove from linked list */
- nextf[bucket] = op->ov_next;
- op->ov_magic = MAGIC;
- op->ov_index = bucket;
-#ifdef MSTATS
- nmalloc[bucket]++;
-#endif
-#ifdef RCHECK
- /*
- * Record allocated size of block and
- * bound space with magic numbers.
- */
- op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1);
- op->ov_rmagic = RMAGIC;
- *(u_short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC;
-#endif
- return ((char *)(op + 1));
+ }
+
+ UTRACE(0, 0, 0);
+
+ /*
+ * We want junk in the entire allocation, and zero only in the part
+ * the user asked for.
+ */
+ 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(0, malloc_pagesize, PROT_READ|PROT_WRITE,
+ MAP_ANON|MAP_PRIVATE, -1, 0);
+ if (page_dir == (struct pginfo **) -1)
+ wrterror("mmap(2) failed, check limits.\n");
+
+ /*
+ * We need a maximum of malloc_pageshift buckets, steal these from the
+ * front of the page_directory;
+ */
+ malloc_origo = ((u_long)pageround((u_long)sbrk(0))) >> malloc_pageshift;
+ malloc_origo -= malloc_pageshift;
+
+ malloc_ninfo = malloc_pagesize / sizeof *page_dir;
+
+ /* Been here, done that */
+ malloc_started++;
+
+ /* Recalculate the cache size in bytes, and make sure it's nonzero */
+
+ if (!malloc_cache)
+ malloc_cache++;
+
+ malloc_cache <<= malloc_pageshift;
+
+ /*
+ * This is a nice hack from Kaleb Keithly (kaleb@x.org).
+ * We can sbrk(2) further back when we keep this on a low address.
+ */
+ px = (struct pgfree *) imalloc (sizeof *px);
+
}
/*
- * Allocate more memory to the indicated bucket.
+ * Allocate a number of complete pages
*/
-static void
-morecore(bucket)
- int bucket;
+static void *
+malloc_pages(size_t size)
{
- register union overhead *op;
- register int sz; /* size of desired block */
- int amt; /* amount to allocate */
- int nblks; /* how many blocks we get */
+ void *p, *delay_free = 0;
+ int i;
+ struct pgfree *pf;
+ u_long index;
- /*
- * sbrk_size <= 0 only for big, FLUFFY, requests (about
- * 2^30 bytes on a VAX, I think) or for a negative arg.
- */
- sz = 1 << (bucket + 3);
-#ifdef DEBUG
- ASSERT(sz > 0);
-#else
- if (sz <= 0)
- return;
-#endif
- if (sz < pagesz) {
- amt = pagesz;
- nblks = amt / sz;
- } else {
- amt = sz + pagesz;
- nblks = 1;
+ size = pageround(size);
+
+ p = 0;
+ /* Look for free pages before asking for more */
+ for(pf = free_list.next; pf; pf = pf->next) {
+
+#ifdef EXTRA_SANITY
+ if (pf->size & malloc_pagemask)
+ wrterror("(ES): junk length entry on free_list\n");
+ if (!pf->size)
+ wrterror("(ES): zero length entry on free_list\n");
+ if (pf->page == pf->end)
+ wrterror("(ES): zero entry on free_list\n");
+ if (pf->page > pf->end)
+ wrterror("(ES): sick entry on free_list\n");
+ if ((void*)pf->page >= (void*)sbrk(0))
+ wrterror("(ES): entry on free_list past brk\n");
+ if (page_dir[ptr2index(pf->page)] != MALLOC_FREE)
+ wrterror("(ES): non-free first page on free-list\n");
+ if (page_dir[ptr2index(pf->end)-1] != MALLOC_FREE)
+ wrterror("(ES): non-free last page on free-list\n");
+#endif /* EXTRA_SANITY */
+
+ if (pf->size < size)
+ continue;
+
+ if (pf->size == size) {
+ p = pf->page;
+ if (pf->next)
+ pf->next->prev = pf->prev;
+ pf->prev->next = pf->next;
+ delay_free = pf;
+ break;
+ }
+
+ p = pf->page;
+ pf->page = (char *)pf->page + size;
+ pf->size -= size;
+ break;
+ }
+
+#ifdef EXTRA_SANITY
+ if (p && page_dir[ptr2index(p)] != MALLOC_FREE)
+ wrterror("(ES): allocated non-free page on free-list\n");
+#endif /* EXTRA_SANITY */
+
+ size >>= malloc_pageshift;
+
+ /* Map new pages */
+ if (!p)
+ p = map_pages(size);
+
+ if (p) {
+
+ index = ptr2index(p);
+ page_dir[index] = MALLOC_FIRST;
+ for (i=1;i<size;i++)
+ page_dir[index+i] = MALLOC_FOLLOW;
+
+ if (malloc_junk)
+ memset(p, SOME_JUNK, size << malloc_pageshift);
+ }
+
+ if (delay_free) {
+ if (!px)
+ px = delay_free;
+ else
+ ifree(delay_free);
+ }
+
+ return p;
+}
+
+/*
+ * Allocate a page of fragments
+ */
+
+static __inline__ int
+malloc_make_chunks(int bits)
+{
+ struct pginfo *bp;
+ void *pp;
+ int i, k, l;
+
+ /* Allocate a new bucket */
+ pp = malloc_pages(malloc_pagesize);
+ if (!pp)
+ return 0;
+
+ /* Find length of admin structure */
+ l = sizeof *bp - sizeof(u_long);
+ l += sizeof(u_long) *
+ (((malloc_pagesize >> bits)+MALLOC_BITS-1) / MALLOC_BITS);
+
+ /* Don't waste more than two chunks on this */
+ if ((1<<(bits)) <= l+l) {
+ bp = (struct pginfo *)pp;
+ } else {
+ bp = (struct pginfo *)imalloc(l);
+ if (!bp) {
+ ifree(pp);
+ return 0;
}
- op = (union overhead *)sbrk(amt);
- /* no more room! */
- if ((int)op == -1)
- return;
- /*
- * Add new memory allocated to that on
- * free list for this hash bucket.
- */
- nextf[bucket] = op;
- while (--nblks > 0) {
- op->ov_next = (union overhead *)((caddr_t)op + sz);
- op = (union overhead *)((caddr_t)op + sz);
- }
+ }
+
+ bp->size = (1<<bits);
+ bp->shift = bits;
+ bp->total = bp->free = malloc_pagesize >> bits;
+ bp->page = pp;
+
+ /* set all valid bits in the bitmap */
+ k = bp->total;
+ i = 0;
+
+ /* Do a bunch at a time */
+ for(;k-i >= MALLOC_BITS; i += MALLOC_BITS)
+ bp->bits[i / MALLOC_BITS] = ~0;
+
+ for(; i < k; i++)
+ bp->bits[i/MALLOC_BITS] |= 1<<(i%MALLOC_BITS);
+
+ if (bp == bp->page) {
+ /* Mark the ones we stole for ourselves */
+ for(i=0;l > 0;i++) {
+ bp->bits[i/MALLOC_BITS] &= ~(1<<(i%MALLOC_BITS));
+ bp->free--;
+ bp->total--;
+ l -= (1 << bits);
+ }
+ }
+
+ /* MALLOC_LOCK */
+
+ page_dir[ptr2index(pp)] = bp;
+
+ bp->next = page_dir[bits];
+ page_dir[bits] = bp;
+
+ /* MALLOC_UNLOCK */
+
+ return 1;
}
-void
-free(cp)
- void *cp;
-{
- register int size;
- register union overhead *op;
-
- if (cp == NULL)
- return;
- op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
-#ifdef DEBUG
- ASSERT(op->ov_magic == MAGIC); /* make sure it was in use */
-#else
- if (op->ov_magic != MAGIC)
- return; /* sanity */
-#endif
-#ifdef RCHECK
- ASSERT(op->ov_rmagic == RMAGIC);
- ASSERT(*(u_short *)((caddr_t)(op + 1) + op->ov_size) == RMAGIC);
-#endif
- size = op->ov_index;
- ASSERT(size < NBUCKETS);
- op->ov_next = nextf[size]; /* also clobbers ov_magic */
- nextf[size] = op;
-#ifdef MSTATS
- nmalloc[size]--;
-#endif
+/*
+ * Allocate a fragment
+ */
+static void *
+malloc_bytes(size_t size)
+{
+ int i,j;
+ u_int u;
+ struct pginfo *bp;
+ int k;
+ u_int *lp;
+
+ /* Don't bother with anything less than this */
+ if (size < malloc_minsize)
+ size = malloc_minsize;
+
+ /* Find the right bucket */
+ j = 1;
+ i = size-1;
+ while (i >>= 1)
+ j++;
+
+ /* If it's empty, make a page more of that size chunks */
+ if (!page_dir[j] && !malloc_make_chunks(j))
+ return 0;
+
+ bp = page_dir[j];
+
+ /* Find first word of bitmap which isn't empty */
+ for (lp = bp->bits; !*lp; lp++)
+ ;
+
+ /* Find that bit, and tweak it */
+ u = 1;
+ k = 0;
+ while (!(*lp & u)) {
+ u += u;
+ k++;
+ }
+ *lp ^= u;
+
+ /* If there are no more free, remove from free-list */
+ if (!--bp->free) {
+ page_dir[j] = bp->next;
+ bp->next = 0;
+ }
+
+ /* Adjust to the real offset of that chunk */
+ k += (lp-bp->bits)*MALLOC_BITS;
+ k <<= bp->shift;
+
+ if (malloc_junk)
+ memset((u_char*)bp->page + k, SOME_JUNK, bp->size);
+
+ return (u_char *)bp->page + k;
}
/*
- * When a program attempts "storage compaction" as mentioned in the
- * old malloc man page, it realloc's an already freed block. Usually
- * this is the last block it freed; occasionally it might be farther
- * back. We have to search all the free lists for the block in order
- * to determine its bucket: 1st we make one pass thru the lists
- * checking only the first block in each; if that fails we search
- * ``__realloc_srchlen'' blocks in each list for a match (the variable
- * is extern so the caller can modify it). If that fails we just copy
- * however many bytes was given to realloc() and hope it's not huge.
+ * Allocate a piece of memory
*/
-int __realloc_srchlen = 4; /* 4 should be plenty, -1 =>'s whole list */
+static void *
+imalloc(size_t size)
+{
+ void *result;
-void *
-realloc(cp, nbytes)
- void *cp;
- size_t nbytes;
-{
- register u_int onb;
- register int i;
- union overhead *op;
- char *res;
- int was_alloced = 0;
-
- if (cp == NULL)
- return (malloc(nbytes));
- op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
- if (op->ov_magic == MAGIC) {
- was_alloced++;
- i = op->ov_index;
- } else {
- /*
- * Already free, doing "compaction".
- *
- * Search for the old block of memory on the
- * free list. First, check the most common
- * case (last element free'd), then (this failing)
- * the last ``__realloc_srchlen'' items free'd.
- * If all lookups fail, then assume the size of
- * the memory block being realloc'd is the
- * largest possible (so that all "nbytes" of new
- * memory are copied into). Note that this could cause
- * a memory fault if the old area was tiny, and the moon
- * is gibbous. However, that is very unlikely.
- */
- if ((i = findbucket(op, 1)) < 0 &&
- (i = findbucket(op, __realloc_srchlen)) < 0)
- i = NBUCKETS;
+ if (!malloc_started)
+ malloc_init();
+
+ if (suicide)
+ abort();
+
+ if (size <= malloc_maxsize)
+ result = malloc_bytes(size);
+ else
+ result = malloc_pages(size);
+
+ if (malloc_abort && !result)
+ wrterror("allocation failed.\n");
+
+ if (malloc_zero && result)
+ memset(result, 0, size);
+
+ return result;
+}
+
+/*
+ * Change the size of an allocation.
+ */
+static void *
+irealloc(void *ptr, size_t size)
+{
+ void *p;
+ u_long osize, index;
+ struct pginfo **mp;
+ int i;
+
+ if (suicide)
+ return 0;
+
+ if (!malloc_started) {
+ wrtwarning("malloc() has never been called.\n");
+ return 0;
+ }
+
+ index = ptr2index(ptr);
+
+ if (index < malloc_pageshift) {
+ wrtwarning("junk pointer, too low to make sense.\n");
+ return 0;
+ }
+
+ if (index > last_index) {
+ wrtwarning("junk pointer, too high to make sense.\n");
+ return 0;
+ }
+
+ mp = &page_dir[index];
+
+ if (*mp == MALLOC_FIRST) { /* Page allocation */
+
+ /* Check the pointer */
+ if ((u_long)ptr & malloc_pagemask) {
+ wrtwarning("modified (page-) pointer.\n");
+ return 0;
}
- onb = 1 << (i + 3);
- if (onb < pagesz)
- onb -= sizeof (*op) + RSLOP;
- else
- onb += pagesz - sizeof (*op) - RSLOP;
- /* avoid the copy if same size block */
- if (was_alloced) {
- if (i) {
- i = 1 << (i + 2);
- if (i < pagesz)
- i -= sizeof (*op) + RSLOP;
- else
- i += pagesz - sizeof (*op) - RSLOP;
- }
- if (nbytes <= onb && nbytes > i) {
-#ifdef RCHECK
- op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1);
- *(u_short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC;
-#endif
- return(cp);
- } else
- free(cp);
+
+ /* Find the size in bytes */
+ for (osize = malloc_pagesize; *++mp == MALLOC_FOLLOW;)
+ osize += malloc_pagesize;
+
+ if (!malloc_realloc && /* unless we have to, */
+ size <= osize && /* .. or are too small, */
+ size > (osize - malloc_pagesize)) { /* .. or can free a page, */
+ return ptr; /* don't do anything. */
}
- if ((res = malloc(nbytes)) == NULL)
- return (NULL);
- if (cp != res) /* common optimization if "compacting" */
- bcopy(cp, res, (nbytes < onb) ? nbytes : onb);
- return (res);
+
+ } else if (*mp >= MALLOC_MAGIC) { /* Chunk allocation */
+
+ /* Check the pointer for sane values */
+ if (((u_long)ptr & ((*mp)->size-1))) {
+ wrtwarning("modified (chunk-) pointer.\n");
+ return 0;
+ }
+
+ /* Find the chunk index in the page */
+ i = ((u_long)ptr & malloc_pagemask) >> (*mp)->shift;
+
+ /* Verify that it isn't a free chunk already */
+ if ((*mp)->bits[i/MALLOC_BITS] & (1<<(i%MALLOC_BITS))) {
+ wrtwarning("chunk is already free.\n");
+ return 0;
+ }
+
+ osize = (*mp)->size;
+
+ if (!malloc_realloc && /* Unless we have to, */
+ size < osize && /* ..or are too small, */
+ (size > osize/2 || /* ..or could use a smaller size, */
+ osize == malloc_minsize)) { /* ..(if there is one) */
+ return ptr; /* ..Don't do anything */
+ }
+
+ } else {
+ wrtwarning("pointer to wrong page.\n");
+ return 0;
+ }
+
+ p = imalloc(size);
+
+ if (p) {
+ /* copy the lesser of the two sizes, and free the old one */
+ if (osize < size)
+ memcpy(p, ptr, osize);
+ else
+ memcpy(p, ptr, size);
+ ifree(ptr);
+ }
+ return p;
}
/*
- * Search ``srchlen'' elements of each free list for a block whose
- * header starts at ``freep''. If srchlen is -1 search the whole list.
- * Return bucket number, or -1 if not found.
+ * Free a sequence of pages
*/
-static
-findbucket(freep, srchlen)
- union overhead *freep;
- int srchlen;
+
+static __inline__ void
+free_pages(void *ptr, int index, struct pginfo *info)
{
- register union overhead *p;
- register int i, j;
-
- for (i = 0; i < NBUCKETS; i++) {
- j = 0;
- for (p = nextf[i]; p && j != srchlen; p = p->ov_next) {
- if (p == freep)
- return (i);
- j++;
- }
+ int i;
+ struct pgfree *pf, *pt=0;
+ u_long l;
+ void *tail;
+
+ if (info == MALLOC_FREE) {
+ wrtwarning("page is already free.\n");
+ return;
+ }
+
+ if (info != MALLOC_FIRST) {
+ wrtwarning("pointer to wrong page.\n");
+ return;
+ }
+
+ if ((u_long)ptr & malloc_pagemask) {
+ wrtwarning("modified (page-) pointer.\n");
+ return;
+ }
+
+ /* Count how many pages and mark them free at the same time */
+ page_dir[index] = MALLOC_FREE;
+ for (i = 1; page_dir[index+i] == MALLOC_FOLLOW; i++)
+ page_dir[index + i] = MALLOC_FREE;
+
+ l = i << malloc_pageshift;
+
+ if (malloc_junk)
+ memset(ptr, SOME_JUNK, l);
+
+ if (malloc_hint)
+ madvise(ptr, l, MADV_FREE);
+
+ tail = (char *)ptr+l;
+
+ /* add to free-list */
+ if (!px)
+ px = imalloc(sizeof *pt); /* This cannot fail... */
+ px->page = ptr;
+ px->end = tail;
+ px->size = l;
+ if (!free_list.next) {
+
+ /* Nothing on free list, put this at head */
+ px->next = free_list.next;
+ px->prev = &free_list;
+ free_list.next = px;
+ pf = px;
+ px = 0;
+
+ } else {
+
+ /* Find the right spot, leave pf pointing to the modified entry. */
+ tail = (char *)ptr+l;
+
+ for(pf = free_list.next; pf->end < ptr && pf->next; pf = pf->next)
+ ; /* Race ahead here */
+
+ if (pf->page > tail) {
+ /* Insert before entry */
+ px->next = pf;
+ px->prev = pf->prev;
+ pf->prev = px;
+ px->prev->next = px;
+ pf = px;
+ px = 0;
+ } else if (pf->end == ptr ) {
+ /* Append to the previous entry */
+ pf->end = (char *)pf->end + l;
+ pf->size += l;
+ if (pf->next && pf->end == pf->next->page ) {
+ /* And collapse the next too. */
+ pt = pf->next;
+ pf->end = pt->end;
+ pf->size += pt->size;
+ pf->next = pt->next;
+ if (pf->next)
+ pf->next->prev = pf;
+ }
+ } else if (pf->page == tail) {
+ /* Prepend to entry */
+ pf->size += l;
+ pf->page = ptr;
+ } else if (!pf->next) {
+ /* Append at tail of chain */
+ px->next = 0;
+ px->prev = pf;
+ pf->next = px;
+ pf = px;
+ px = 0;
+ } else {
+ wrterror("freelist is destroyed.\n");
}
- return (-1);
+ }
+
+ /* Return something to OS ? */
+ if (!pf->next && /* If we're the last one, */
+ pf->size > malloc_cache && /* ..and the cache is full, */
+ pf->end == malloc_brk && /* ..and none behind us, */
+ malloc_brk == sbrk(0)) { /* ..and it's OK to do... */
+
+ /*
+ * Keep the cache intact. Notice that the '>' above guarantees that
+ * the pf will always have at least one page afterwards.
+ */
+ pf->end = (char *)pf->page + malloc_cache;
+ pf->size = malloc_cache;
+
+ brk(pf->end);
+ malloc_brk = pf->end;
+
+ index = ptr2index(pf->end);
+ last_index = index - 1;
+
+ for(i=index;i <= last_index;)
+ page_dir[i++] = MALLOC_NOT_MINE;
+
+ /* XXX: We could realloc/shrink the pagedir here I guess. */
+ }
+ if (pt)
+ ifree(pt);
}
-#ifdef MSTATS
/*
- * mstats - print out statistics about malloc
- *
- * Prints two lines of numbers, one showing the length of the free list
- * for each size category, the second showing the number of mallocs -
- * frees for each size category.
+ * Free a chunk, and possibly the page it's on, if the page becomes empty.
*/
-mstats(s)
- char *s;
+
+static __inline__ void
+free_bytes(void *ptr, int index, struct pginfo *info)
{
- register int i, j;
- register union overhead *p;
- int totfree = 0,
- totused = 0;
-
- fprintf(stderr, "Memory allocation statistics %s\nfree:\t", s);
- for (i = 0; i < NBUCKETS; i++) {
- for (j = 0, p = nextf[i]; p; p = p->ov_next, j++)
- ;
- fprintf(stderr, " %d", j);
- totfree += j * (1 << (i + 3));
- }
- fprintf(stderr, "\nused:\t");
- for (i = 0; i < NBUCKETS; i++) {
- fprintf(stderr, " %d", nmalloc[i]);
- totused += nmalloc[i] * (1 << (i + 3));
- }
- fprintf(stderr, "\n\tTotal in use: %d, total free: %d\n",
- totused, totfree);
+ int i;
+ struct pginfo **mp;
+ void *vp;
+
+ /* Find the chunk number on the page */
+ i = ((u_long)ptr & malloc_pagemask) >> info->shift;
+
+ if (((u_long)ptr & (info->size-1))) {
+ wrtwarning("modified (chunk-) pointer.\n");
+ return;
+ }
+
+ if (info->bits[i/MALLOC_BITS] & (1<<(i%MALLOC_BITS))) {
+ wrtwarning("chunk is already free.\n");
+ return;
+ }
+
+ if (malloc_junk)
+ memset(ptr, SOME_JUNK, info->size);
+
+ info->bits[i/MALLOC_BITS] |= 1<<(i%MALLOC_BITS);
+ info->free++;
+
+ mp = page_dir + info->shift;
+
+ if (info->free == 1) {
+
+ /* Page became non-full */
+
+ mp = page_dir + info->shift;
+ /* Insert in address order */
+ while (*mp && (*mp)->next && (*mp)->next->page < info->page)
+ mp = &(*mp)->next;
+ info->next = *mp;
+ *mp = info;
+ return;
+ }
+
+ if (info->free != info->total)
+ return;
+
+ /* Find & remove this page in the queue */
+ while (*mp != info) {
+ mp = &((*mp)->next);
+#ifdef EXTRA_SANITY
+ if (!*mp)
+ wrterror("(ES): Not on queue\n");
+#endif /* EXTRA_SANITY */
+ }
+ *mp = info->next;
+
+ /* Free the page & the info structure if need be */
+ page_dir[ptr2index(info->page)] = MALLOC_FIRST;
+ vp = info->page; /* Order is important ! */
+ if(vp != (void*)info)
+ ifree(info);
+ ifree(vp);
}
+
+static void
+ifree(void *ptr)
+{
+ struct pginfo *info;
+ int index;
+
+ /* This is legal */
+ if (!ptr)
+ return;
+
+ if (!malloc_started) {
+ wrtwarning("malloc() has never been called.\n");
+ return;
+ }
+
+ /* If we're already sinking, don't make matters any worse. */
+ if (suicide)
+ return;
+
+ index = ptr2index(ptr);
+
+ if (index < malloc_pageshift) {
+ wrtwarning("junk pointer, too low to make sense.\n");
+ return;
+ }
+
+ if (index > last_index) {
+ wrtwarning("junk pointer, too high to make sense.\n");
+ return;
+ }
+
+ info = page_dir[index];
+
+ if (info < MALLOC_MAGIC)
+ free_pages(ptr, index, info);
+ else
+ free_bytes(ptr, index, info);
+ return;
+}
+
+/*
+ * These are the public exported interface routines.
+ */
+
+#ifdef _THREAD_SAFE
+#include <pthread.h>
+#include "pthread_private.h"
+static int malloc_lock;
+#define THREAD_LOCK() _thread_kern_sig_block(&malloc_lock);
+#define THREAD_UNLOCK() _thread_kern_sig_unblock(malloc_lock);
+#else
+#define THREAD_LOCK()
+#define THREAD_UNLOCK()
#endif
+
+static int malloc_active;
+
+void *
+malloc(size_t size)
+{
+ register void *r;
+
+ malloc_func = " in malloc():";
+ THREAD_LOCK();
+ if (malloc_active++) {
+ wrtwarning("recursive call.\n");
+ malloc_active--;
+ return (0);
+ }
+ r = imalloc(size);
+ UTRACE(0, size, r);
+ malloc_active--;
+ THREAD_UNLOCK();
+ return (r);
+}
+
+void
+free(void *ptr)
+{
+ malloc_func = " in free():";
+ THREAD_LOCK();
+ if (malloc_active++) {
+ wrtwarning("recursive call.\n");
+ malloc_active--;
+ return;
+ }
+ ifree(ptr);
+ UTRACE(ptr, 0, 0);
+ malloc_active--;
+ THREAD_UNLOCK();
+ return;
+}
+
+void *
+realloc(void *ptr, size_t size)
+{
+ register void *r;
+
+ malloc_func = " in realloc():";
+ THREAD_LOCK();
+ if (malloc_active++) {
+ wrtwarning("recursive call.\n");
+ malloc_active--;
+ return (0);
+ }
+ if (!ptr) {
+ r = imalloc(size);
+ } else if (ptr && !size) {
+ ifree(ptr);
+ r = 0;
+ } else {
+ r = irealloc(ptr, size);
+ }
+ UTRACE(ptr, size, r);
+ malloc_active--;
+ THREAD_UNLOCK();
+ return (r);
+}
diff --git a/lib/libc/stdlib/memory.3 b/lib/libc/stdlib/memory.3
index 9bc600b..0a1fed4 100644
--- a/lib/libc/stdlib/memory.3
+++ b/lib/libc/stdlib/memory.3
@@ -30,6 +30,7 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)memory.3 8.1 (Berkeley) 6/4/93
+.\" $Id$
.\"
.Dd June 4, 1993
.Dt MEMORY 3
@@ -58,11 +59,11 @@ These functions allocate and free memory for the calling process.
They are described in the
individual manual pages.
.Sh SEE ALSO
+.Xr alloca 3 ,
.Xr calloc 3 ,
.Xr free 3 ,
.Xr malloc 3 ,
-.Xr realloc 3 ,
-.Xr alloca 3 ,
+.Xr realloc 3
.Sh STANDARDS
These functions, with the exception of
.Fn alloca
diff --git a/lib/libc/stdlib/merge.c b/lib/libc/stdlib/merge.c
index 7d00844..a47e300 100644
--- a/lib/libc/stdlib/merge.c
+++ b/lib/libc/stdlib/merge.c
@@ -80,7 +80,7 @@ static void insertionsort __P((u_char *, size_t, size_t, int (*)()));
do \
*dst++ = *src++; \
while (i -= 1)
-
+
/*
* Find the next possible pointer head. (Trickery for forcing an array
* to do double duty as a linked list when objects do not align with word
@@ -164,7 +164,7 @@ EXPONENTIAL: for (i = size; ; i <<= 1)
} else if ((*cmp)(q, p) <= sense) {
t = p;
if (i == size)
- big = 0;
+ big = 0;
goto FASTCASE;
} else
b = p;
diff --git a/lib/libc/stdlib/qsort.c b/lib/libc/stdlib/qsort.c
index 1d3aa93..ff3def5 100644
--- a/lib/libc/stdlib/qsort.c
+++ b/lib/libc/stdlib/qsort.c
@@ -32,13 +32,17 @@
*/
#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
static char sccsid[] = "@(#)qsort.c 8.1 (Berkeley) 6/4/93";
+#endif
+static const char rcsid[] =
+ "$Id$";
#endif /* LIBC_SCCS and not lint */
-#include <sys/types.h>
#include <stdlib.h>
-static inline char *med3 __P((char *, char *, char *, int (*)()));
+typedef int cmp_t __P((const void *, const void *));
+static inline char *med3 __P((char *, char *, char *, cmp_t *));
static inline void swapfunc __P((char *, char *, int, int));
#define min(a, b) (a) < (b) ? a : b
@@ -65,7 +69,7 @@ swapfunc(a, b, n, swaptype)
char *a, *b;
int n, swaptype;
{
- if(swaptype <= 1)
+ if(swaptype <= 1)
swapcode(long, a, b, n)
else
swapcode(char, a, b, n)
@@ -84,7 +88,7 @@ swapfunc(a, b, n, swaptype)
static inline char *
med3(a, b, c, cmp)
char *a, *b, *c;
- int (*cmp)();
+ cmp_t *cmp;
{
return cmp(a, b) < 0 ?
(cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a ))
@@ -95,7 +99,7 @@ void
qsort(a, n, es, cmp)
void *a;
size_t n, es;
- int (*cmp)();
+ cmp_t *cmp;
{
char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
int d, r, swaptype, swap_cnt;
@@ -103,16 +107,16 @@ qsort(a, n, es, cmp)
loop: SWAPINIT(a, es);
swap_cnt = 0;
if (n < 7) {
- for (pm = a + es; pm < (char *) a + n * es; pm += es)
- for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
+ for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
+ for (pl = pm; pl > (char *)a && cmp(pl - es, pl) > 0;
pl -= es)
swap(pl, pl - es);
return;
}
- pm = a + (n / 2) * es;
+ pm = (char *)a + (n / 2) * es;
if (n > 7) {
pl = a;
- pn = a + (n - 1) * es;
+ pn = (char *)a + (n - 1) * es;
if (n > 40) {
d = (n / 8) * es;
pl = med3(pl, pl + d, pl + 2 * d, cmp);
@@ -122,9 +126,9 @@ loop: SWAPINIT(a, es);
pm = med3(pl, pm, pn, cmp);
}
swap(a, pm);
- pa = pb = a + es;
+ pa = pb = (char *)a + es;
- pc = pd = a + (n - 1) * es;
+ pc = pd = (char *)a + (n - 1) * es;
for (;;) {
while (pb <= pc && (r = cmp(pb, a)) <= 0) {
if (r == 0) {
@@ -150,21 +154,21 @@ loop: SWAPINIT(a, es);
pc -= es;
}
if (swap_cnt == 0) { /* Switch to insertion sort */
- for (pm = a + es; pm < (char *) a + n * es; pm += es)
- for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
+ for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
+ for (pl = pm; pl > (char *)a && cmp(pl - es, pl) > 0;
pl -= es)
swap(pl, pl - es);
return;
}
- pn = a + n * es;
+ pn = (char *)a + n * es;
r = min(pa - (char *)a, pb - pa);
vecswap(a, pb - r, r);
r = min(pd - pc, pn - pd - es);
vecswap(pb, pn - r, r);
if ((r = pb - pa) > es)
qsort(a, r / es, es, cmp);
- if ((r = pd - pc) > es) {
+ if ((r = pd - pc) > es) {
/* Iterate rather than recurse to save stack space */
a = pn - r;
n = r / es;
diff --git a/lib/libc/stdlib/radixsort.3 b/lib/libc/stdlib/radixsort.3
index ce30378..4d49d46 100644
--- a/lib/libc/stdlib/radixsort.3
+++ b/lib/libc/stdlib/radixsort.3
@@ -157,4 +157,5 @@ for any of the errors specified for the library routine
.Sh HISTORY
The
.Fn radixsort
-function first appeared in 4.4BSD.
+function first appeared in
+.Bx 4.4 .
diff --git a/lib/libc/stdlib/radixsort.c b/lib/libc/stdlib/radixsort.c
index d211f3d..af47fb0 100644
--- a/lib/libc/stdlib/radixsort.c
+++ b/lib/libc/stdlib/radixsort.c
@@ -3,7 +3,7 @@
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
- * Peter McIlroy and by Dan Bernstein at New York University,
+ * Peter McIlroy and by Dan Bernstein at New York University,
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -40,13 +40,13 @@ static char sccsid[] = "@(#)radixsort.c 8.1 (Berkeley) 6/4/93";
/*
* Radixsort routines.
- *
+ *
* Program r_sort_a() is unstable but uses O(logN) extra memory for a stack.
* Use radixsort(a, n, trace, endchar) for this case.
- *
+ *
* For stable sorting (using N extra pointers) use sradixsort(), which calls
* r_sort_b().
- *
+ *
* For a description of this code, see D. McIlroy, P. McIlroy, K. Bostic,
* "Engineering Radix Sort".
*/
@@ -294,7 +294,7 @@ r_sort_b(a, ta, n, i, tr, endch)
*--top[tr[(*ak)[i]]] = *ak;
}
}
-
+
static inline void
simplesort(a, n, b, tr, endch) /* insertion sort */
register const u_char **a;
diff --git a/lib/libc/stdlib/random.3 b/lib/libc/stdlib/random.3
index 84680e2..dd85711 100644
--- a/lib/libc/stdlib/random.3
+++ b/lib/libc/stdlib/random.3
@@ -64,11 +64,16 @@ The period of this random number generator is very large, approximately
.if n 16*((2**31)\(mi1).
.Pp
The
-.Fn random Ns / Fn srandom
-have (almost) the same calling sequence and initialization properties as
-.Xr rand 3 Ns / Xr srand 3 .
+.Fn random
+and
+.Fn srandom
+functions have (almost) the same calling sequence and initialization properties as the
+.Xr rand 3
+and
+.Xr srand 3
+functions.
The difference is that
-.Xr rand
+.Xr rand 3
produces a much less random sequence \(em in fact, the low dozen bits
generated by rand go through a cyclic pattern. All the bits generated by
.Fn random
@@ -77,15 +82,8 @@ are usable. For example,
will produce a random binary
value.
.Pp
-Unlike
-.Xr srand ,
-.Fn srandom
-does not return the old seed; the reason for this is that the amount of
-state information used is much more than a single word. (Two other
-routines are provided to deal with restarting/changing random
-number generators). Like
+Like
.Xr rand 3 ,
-however,
.Fn random
will by default produce a sequence of numbers that can be duplicated
by calling
@@ -156,11 +154,29 @@ is called with less than 8 bytes of state information, or if
detects that the state information has been garbled, error
messages are printed on the standard error output.
.Sh SEE ALSO
-.Xr rand 3
+.Xr rand 3 ,
+.Xr srand 3
.Sh HISTORY
These
functions appeared in
.Bx 4.2 .
.Sh BUGS
+.Pp
About 2/3 the speed of
.Xr rand 3 .
+.Pp
+The historical implementation used to have a very weak seeding; the
+random sequence did not vary much with the seed. For compatibility
+reasons, this implementation has been made available until the
+next FreeBSD release
+via the
+functions
+.Fn orandom ,
+.Fn osrandom ,
+.Fn oinitstate
+and
+.Fn osetstate
+from the compatibility library,
+.Em libcompat .
+The current implementation employs a better pseudo-random number
+generator for the initial state calculation.
diff --git a/lib/libc/stdlib/random.c b/lib/libc/stdlib/random.c
index 18babba..d1ec971 100644
--- a/lib/libc/stdlib/random.c
+++ b/lib/libc/stdlib/random.c
@@ -35,6 +35,14 @@
static char sccsid[] = "@(#)random.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
+#ifdef COMPAT_WEAK_SEEDING
+#define USE_WEAK_SEEDING
+#define random orandom
+#define srandom osrandom
+#define initstate oinitstate
+#define setstate osetstate
+#endif
+
#include <stdio.h>
#include <stdlib.h>
@@ -61,7 +69,7 @@ static char sccsid[] = "@(#)random.c 8.1 (Berkeley) 6/4/93";
* state information, which will allow a degree seven polynomial. (Note:
* the zeroeth word of state information also has some other information
* stored in it -- see setstate() for details).
- *
+ *
* The random number generation technique is a linear feedback shift register
* approach, employing trinomials (since there are fewer terms to sum up that
* way). In this approach, the least significant bit of all the numbers in
@@ -122,7 +130,7 @@ static int seps [MAX_TYPES] = { SEP_0, SEP_1, SEP_2, SEP_3, SEP_4 };
/*
* Initially, everything is set up as if from:
*
- * initstate(1, &randtbl, 128);
+ * initstate(1, randtbl, 128);
*
* Note that this initialization takes advantage of the fact that srandom()
* advances the front and rear pointers 10*rand_deg times, and hence the
@@ -135,12 +143,23 @@ static int seps [MAX_TYPES] = { SEP_0, SEP_1, SEP_2, SEP_3, SEP_4 };
static long randtbl[DEG_3 + 1] = {
TYPE_3,
+#ifdef USE_WEAK_SEEDING
+/* Historic implementation compatibility */
+/* The random sequences do not vary much with the seed */
0x9a319039, 0x32d9c024, 0x9b663182, 0x5da1f342, 0xde3b81e0, 0xdf0a6fb5,
0xf103bc02, 0x48f340fb, 0x7449e56b, 0xbeb1dbb0, 0xab5c5918, 0x946554fd,
0x8c2e680f, 0xeb3d799f, 0xb11ee0b7, 0x2d436b86, 0xda672e2a, 0x1588ca88,
0xe369735d, 0x904f35f7, 0xd7158fd6, 0x6fa6f051, 0x616e6b96, 0xac94efdc,
0x36413f93, 0xc622c298, 0xf5a42ab8, 0x8a88d77b, 0xf5ad9d0e, 0x8999220b,
0x27fb47b9,
+#else /* !USE_WEAK_SEEDING */
+ 0x991539b1, 0x16a5bce3, 0x6774a4cd, 0x3e01511e, 0x4e508aaa, 0x61048c05,
+ 0xf5500617, 0x846b7115, 0x6a19892c, 0x896a97af, 0xdb48f936, 0x14898454,
+ 0x37ffd106, 0xb58bff9c, 0x59e17104, 0xcf918a49, 0x09378c83, 0x52c7a471,
+ 0x8d293ea9, 0x1f4fc301, 0xc3db71be, 0x39b44e1c, 0xf8a44ef9, 0x4c8b80b1,
+ 0x19edc328, 0x87bf4bdd, 0xc9b240e5, 0xe9ee4b1b, 0x4382aee7, 0x535b6b41,
+ 0xf3bec5da
+#endif /* !USE_WEAK_SEEDING */
};
/*
@@ -176,6 +195,38 @@ static int rand_deg = DEG_3;
static int rand_sep = SEP_3;
static long *end_ptr = &randtbl[DEG_3 + 1];
+static inline long good_rand __P((long));
+
+static inline long good_rand (x)
+ register long x;
+{
+#ifdef USE_WEAK_SEEDING
+/*
+ * Historic implementation compatibility.
+ * The random sequences do not vary much with the seed,
+ * even with overflowing.
+ */
+ return (1103515245 * x + 12345);
+#else /* !USE_WEAK_SEEDING */
+/*
+ * Compute x = (7^5 * x) mod (2^31 - 1)
+ * wihout overflowing 31 bits:
+ * (2^31 - 1) = 127773 * (7^5) + 2836
+ * From "Random number generators: good ones are hard to find",
+ * Park and Miller, Communications of the ACM, vol. 31, no. 10,
+ * October 1988, p. 1195.
+ */
+ register long hi, lo;
+
+ hi = x / 127773;
+ lo = x % 127773;
+ x = 16807 * lo - 2836 * hi;
+ if (x <= 0)
+ x += 0x7fffffff;
+ return (x);
+#endif /* !USE_WEAK_SEEDING */
+}
+
/*
* srandom:
*
@@ -190,17 +241,16 @@ static long *end_ptr = &randtbl[DEG_3 + 1];
*/
void
srandom(x)
- u_int x;
+ unsigned int x;
{
- register int i, j;
+ register int i;
if (rand_type == TYPE_0)
state[0] = x;
else {
- j = 1;
state[0] = x;
for (i = 1; i < rand_deg; i++)
- state[i] = 1103515245 * state[i - 1] + 12345;
+ state[i] = good_rand(state[i - 1]);
fptr = &state[rand_sep];
rptr = &state[0];
for (i = 0; i < 10 * rand_deg; i++)
@@ -216,12 +266,12 @@ srandom(x)
* the break values for the different R.N.G.'s, we choose the best (largest)
* one we can and set things up for it. srandom() is then called to
* initialize the state information.
- *
+ *
* Note that on return from srandom(), we set state[-1] to be the type
* multiplexed with the current value of the rear pointer; this is so
* successive calls to initstate() won't lose this information and will be
* able to restart with setstate().
- *
+ *
* Note: the first thing we do is save the current state, if any, just like
* setstate() so that it doesn't matter when initstate is called.
*
@@ -229,7 +279,7 @@ srandom(x)
*/
char *
initstate(seed, arg_state, n)
- u_int seed; /* seed for R.N.G. */
+ unsigned int seed; /* seed for R.N.G. */
char *arg_state; /* pointer to state array */
int n; /* # bytes of state info */
{
@@ -349,7 +399,7 @@ random()
long i;
if (rand_type == TYPE_0)
- i = state[0] = (state[0] * 1103515245 + 12345) & 0x7fffffff;
+ i = state[0] = good_rand(state[0]) & 0x7fffffff;
else {
*fptr += *rptr;
i = (*fptr >> 1) & 0x7fffffff; /* chucking least random bit */
diff --git a/lib/libc/stdlib/realpath.c b/lib/libc/stdlib/realpath.c
index 20efabd..28380d7 100644
--- a/lib/libc/stdlib/realpath.c
+++ b/lib/libc/stdlib/realpath.c
@@ -98,7 +98,7 @@ loop:
p = resolved;
/* Deal with the last component. */
- if (lstat(p, &sb) == 0) {
+ if (*p != '\0' && lstat(p, &sb) == 0) {
if (S_ISLNK(sb.st_mode)) {
n = readlink(p, resolved, MAXPATHLEN);
if (n < 0)
diff --git a/lib/libc/stdlib/setenv.c b/lib/libc/stdlib/setenv.c
index b36d673..d981277 100644
--- a/lib/libc/stdlib/setenv.c
+++ b/lib/libc/stdlib/setenv.c
@@ -39,13 +39,14 @@ static char sccsid[] = "@(#)setenv.c 8.1 (Berkeley) 6/4/93";
#include <stdlib.h>
#include <string.h>
-char *__findenv __P((const char *, int *));
+char *__findenv __P((const char *, int *));
/*
* setenv --
* Set the value of the environmental variable "name" to be
* "value". If rewrite is set, replace any current value.
*/
+int
setenv(name, value, rewrite)
register const char *name;
register const char *value;
@@ -63,7 +64,7 @@ setenv(name, value, rewrite)
if (!rewrite)
return (0);
if (strlen(c) >= l_value) { /* old larger; copy over */
- while (*c++ = *value++);
+ while ( (*c++ = *value++) );
return (0);
}
} else { /* create new slot */
@@ -93,7 +94,7 @@ setenv(name, value, rewrite)
malloc((size_t)((int)(c - name) + l_value + 2))))
return (-1);
for (c = environ[offset]; (*c = *name++) && *c != '='; ++c);
- for (*c++ = '='; *c++ = *value++;);
+ for (*c++ = '='; (*c++ = *value++); );
return (0);
}
diff --git a/lib/libc/stdlib/strhash.c b/lib/libc/stdlib/strhash.c
new file mode 100644
index 0000000..8e2230b
--- /dev/null
+++ b/lib/libc/stdlib/strhash.c
@@ -0,0 +1,436 @@
+#ifndef lint
+static char *rcsid = "$Header: /home/ncvs/src/lib/libc/stdlib/strhash.c,v 1.5 1995/10/22 14:53:17 phk Exp $";
+#endif
+
+/*
+ *
+ * Copyright 1990
+ * Terry Jones & Jordan Hubbard
+ *
+ * PCS Computer Systeme, GmbH.
+ * Munich, West Germany
+ *
+ *
+ * All rights reserved.
+ *
+ * This is unsupported software and is subject to change without notice.
+ * the author makes no representations about the suitability of this software
+ * for any purpose. It is supplied "as is" without express or implied
+ * warranty.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the author not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission.
+ *
+ */
+
+/*
+ * This is a fairly simple open addressing hash scheme.
+ * Terry did all the code, I just did the spec.
+ * Thanks again, you crazy Aussie..
+ *
+ */
+
+/*
+ * $Log: strhash.c,v $
+ * Revision 1.5 1995/10/22 14:53:17 phk
+ * Mino cleanup, #includes & unused vars.
+ *
+ * Revision 1.4 1995/05/30 05:41:55 rgrimes
+ * Remove trailing whitespace.
+ *
+ * Revision 1.3 1995/03/28 08:41:02 jkh
+ * Fix a missing _hash() to prevent namespace pollution with the db/hash routines.
+ * Grrr. If the dbhash routines weren't grossly overengineered I wouldn't
+ * even need to do this! :-(
+ *
+ * Also now export the hash_stats routine. Manpage coming RSN - I promise.
+ *
+ * Revision 1.2 1995/03/26 19:32:24 ache
+ * Hash 8bit chars without sign extension
+ *
+ * Revision 1.1 1995/03/26 10:21:55 jkh
+ * Add the strhash family of routines. They provide a number of features
+ * that the db/hash functions don't, and they're much simpler to use for
+ * low-overhead string hashing.
+ *
+ * Revision 1.1 1995/02/25 02:16:34 jkh
+ * Second version of this - now support the essentials of a basic
+ * attributed file system for storing menu information and command
+ * templates. This is not finished yet, but it does compile so I can
+ * commit it to the tree now and continue working on it.
+ *
+ * Revision 2.0 90/03/26 01:44:26 jkh
+ * pre-beta check-in
+ *
+ * Revision 1.8 90/03/09 19:22:35 jkh
+ * Fixed bogus comment.
+ *
+ * Revision 1.7 90/03/09 19:01:08 jkh
+ * Added comments, GPL.
+ *
+ * Revision 1.6 90/03/08 17:55:58 terry
+ * Rearranged hash_purge to be a tiny bit more efficient.
+ * Added verbose option to hash_stats.
+ *
+ * Revision 1.5 90/03/08 17:19:54 terry
+ * Added hash_purge. Added arg to hash_traverse. Changed all
+ * void * to Generic.
+ *
+ * Revision 1.4 90/03/08 12:02:35 terry
+ * Fixed problems with allocation that I screwed up last night.
+ * Changed bucket lists to be singly linked. Thanks to JKH, my hero.
+ *
+ * Revision 1.3 90/03/07 21:33:33 terry
+ * Cleaned up a few decls to keep gcc -Wall quiet.
+ *
+ * Revision 1.2 90/03/07 21:14:53 terry
+ * Comments. Added HASH_STATS define. Removed hash_find()
+ * and new_node().
+ *
+ * Revision 1.1 90/03/07 20:49:45 terry
+ * Initial revision
+ *
+ *
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <strhash.h>
+
+#define HASH_NULL (hash_table *)0
+#define NODE_NULL (hash_node *)0
+#define GENERIC_NULL (void *)0
+
+#define HASH_SZ 97
+
+
+static int _hash(int size, char *key);
+static hash_node *list_find(caddr_t key, hash_node *head);
+
+
+/*
+ * hash_create()
+ *
+ * Malloc room for a new hash table and then room for its
+ * bucket pointers. Then set all the buckets to
+ * point to 0. Return the address of the new table.
+ */
+hash_table *
+hash_create(int size)
+{
+ register int i;
+ hash_table *new = (hash_table *)malloc(sizeof(hash_table));
+
+ if (!new || size < 0){
+ return HASH_NULL;
+ }
+
+ if (size == 0){
+ size = HASH_SZ;
+ }
+
+ if (!(new->buckets = (hash_node **)malloc(size * sizeof(hash_node *)))){
+ return HASH_NULL;
+ }
+
+ for (i = 0; i < size; i++){
+ new->buckets[i] = NODE_NULL;
+ }
+ new->size = size;
+
+ return new;
+}
+
+
+/*
+ * list_find()
+ *
+ * Find the key in the linked list pointed to by head.
+ */
+static hash_node *
+list_find(caddr_t key, hash_node *head)
+{
+ while (head){
+ if (!strcmp(head->key, key)){
+ return head;
+ }
+ head = head->next;
+ }
+ return NODE_NULL;
+}
+
+
+/*
+ * _hash()
+ *
+ * Compute the hash value for the given key.
+ */
+static int
+_hash(int size, char *key)
+{
+ unsigned int h = 0x0;
+
+ while (*key){
+ h = (h << 1) ^ (h ^ (unsigned char) *key++);
+ }
+
+ h %= size;
+ return h;
+}
+
+/*
+ * hash_destroy()
+ *
+ * Find the key and (if it's there) remove it entirely.
+ * The function (*nukefunc)() is in charge of disposing
+ * of the storage help by the data associated with the node.
+ */
+void
+hash_destroy(hash_table *table, char *key, void (*nukefunc)())
+{
+ int bucket = _hash(table->size, key);
+ hash_node *found = table->buckets[bucket];
+ hash_node *to_free = NODE_NULL;
+
+ if (!found) {
+ return;
+ }
+
+ if (!strcmp(found->key, key)) {
+ /*
+ * It was the head of the list.
+ */
+ table->buckets[bucket] = found->next;
+ to_free = found;
+ }
+ else {
+ /*
+ * Walk the list, looking one ahead.
+ */
+ while (found->next) {
+ if (!strcmp(found->next->key, key)) {
+ to_free = found->next;
+ found->next = found->next->next;
+ break;
+ }
+ found = found->next;
+ }
+
+ if (!to_free){
+ return;
+ }
+ }
+
+ if (nukefunc)
+ (*nukefunc)(to_free->key, to_free->data);
+ free(to_free);
+ return;
+}
+
+
+/*
+ * hash_search()
+ *
+ * Search the table for the given key. Then:
+ *
+ * 1) If you find it and there is no replacement function, just
+ * return what you found. (This is a simple search).
+ * 2) If you find it and there is a replacement function, run
+ * the function on the data you found, and replace the old
+ * data with whatever is passed in datum. Return 0.
+ * 3) If you don't find it and there is some datum, insert a
+ * new item into the table. Insertions go at the front of
+ * the bucket. Return 0.
+ * 4) Otherwise just return 0.
+ *
+ */
+void *
+hash_search(hash_table *table, caddr_t key, void *datum,
+ void (*replace_func)())
+{
+ int bucket = _hash(table->size, key);
+ hash_node *found = list_find(key, table->buckets[bucket]);
+
+ if (found){
+ if (!replace_func){
+ return found->data;
+ }
+ else{
+ (*replace_func)(found->data);
+ found->data = datum;
+ }
+ }
+ else{
+ if (datum){
+
+ static int assign_key();
+
+ hash_node *new = (hash_node *)malloc(sizeof(hash_node));
+
+ if (!new || !assign_key(key, new)){
+ return GENERIC_NULL;
+ }
+ new->data = datum;
+ new->next = table->buckets[bucket];
+ table->buckets[bucket] = new;
+ return new;
+ }
+ }
+ return GENERIC_NULL;
+}
+
+
+/*
+ * assign_key()
+ *
+ * Set the key value of a node to be 'key'. Get some space from
+ * malloc and copy it in etc. Return 1 if all is well, 0 otherwise.
+ */
+static int
+assign_key(char *key, hash_node *node)
+{
+ if (!node || !key){
+ return 0;
+ }
+
+ if (!(node->key = (char *)malloc(strlen(key) + 1))){
+ return 0;
+ }
+
+ node->key[0] = '\0';
+ strcat(node->key, key);
+ return 1;
+}
+
+/*
+ * hash_traverse()
+ *
+ * Traverse the hash table and run the function func on the
+ * data found at each node and the argument we're passed for it.
+ */
+void
+hash_traverse(hash_table *table, int (*func)(), void *arg)
+{
+ register int i;
+ register int size = table->size;
+
+ if (!func)
+ return;
+
+ for (i = 0; i < size; i++) {
+ hash_node *n = table->buckets[i];
+ while (n) {
+ if ((*func)(n->key, n->data, arg) == 0)
+ return;
+ n = n->next;
+ }
+ }
+ return;
+}
+
+/*
+ * hash_purge()
+ *
+ * Run through the entire hash table. Call purge_func
+ * on the data found at each node, and then free the node.
+ * Set all the bucket pointers to 0.
+ */
+void
+hash_purge(hash_table *table, void (*purge_func)(char *p1, void *p2))
+{
+ register int i;
+ register int size = table->size;
+
+ for (i = 0; i < size; i++) {
+ hash_node *n = table->buckets[i];
+ if (n) {
+ do {
+ hash_node *to_free = n;
+ if (purge_func) {
+ (*purge_func)(n->key, n->data);
+ }
+ n = n->next;
+ free(to_free);
+ } while (n);
+ table->buckets[i] = NODE_NULL;
+ }
+ }
+}
+
+#undef min
+#define min(a, b) (a) < (b) ? (a) : (b)
+
+/*
+ * hash_stats()
+ *
+ * Print statistics about the current table allocation to stdout.
+ */
+void
+hash_stats(hash_table *table, int verbose)
+{
+ register int i;
+ int total_elements = 0;
+ int non_empty_buckets = 0;
+ int max_count = 0;
+ int max_repeats = 0;
+ int *counts;
+ int size = table->size;
+
+ if (!(counts = (int *)malloc(size * sizeof(int)))){
+ fprintf(stderr, "malloc returns 0\n");
+ exit(1);
+ }
+
+ for (i = 0; i < size; i++){
+ int x = 0;
+ hash_node *n = table->buckets[i];
+ counts[i] = 0;
+ while (n){
+ if (!x){
+ x = 1;
+ non_empty_buckets++;
+ if (verbose){
+ printf("bucket %2d: ", i);
+ }
+ }
+ if (verbose){
+ printf(" %s", n->key);
+ }
+ counts[i]++;
+ n = n->next;
+ }
+
+ total_elements += counts[i];
+ if (counts[i] > max_count){
+ max_count = counts[i];
+ max_repeats = 1;
+ }
+ else if (counts[i] == max_count){
+ max_repeats++;
+ }
+
+ if (counts[i] && verbose){
+ printf(" (%d)\n", counts[i]);
+ }
+ }
+
+ printf("\n");
+ printf("%d element%s in storage.\n", total_elements, total_elements == 1 ? "" : "s");
+
+ if (total_elements){
+ printf("%d of %d (%.2f%%) buckets are in use\n", non_empty_buckets, size,
+ (double)100 * (double)non_empty_buckets / (double)(size));
+ printf("the maximum number of elements in a bucket is %d (%d times)\n", max_count, max_repeats);
+ printf("average per bucket is %f\n", (double)total_elements / (double)non_empty_buckets);
+ printf("optimal would be %f\n", (double)total_elements / (double)(min(size, total_elements)));
+ }
+ return;
+}
diff --git a/lib/libc/stdlib/strtod.c b/lib/libc/stdlib/strtod.c
index cd82c73..27fb499 100644
--- a/lib/libc/stdlib/strtod.c
+++ b/lib/libc/stdlib/strtod.c
@@ -146,6 +146,7 @@ static char sccsid[] = "@(#)strtod.c 8.1 (Berkeley) 6/4/93";
#endif
#include "errno.h"
+#include <ctype.h>
#ifdef Bad_float_h
#undef __STDC__
#ifdef IEEE_MC68k
@@ -381,7 +382,7 @@ Balloc
int x;
Bigint *rv;
- if (rv = freelist[k]) {
+ if ( (rv = freelist[k]) ) {
freelist[k] = rv->next;
} else {
x = 1 << k;
@@ -627,7 +628,7 @@ mult
xc0 = c->x;
#ifdef Pack_32
for (; xb < xbe; xb++, xc0++) {
- if (y = *xb & 0xffff) {
+ if ( (y = *xb & 0xffff) ) {
x = xa;
xc = xc0;
carry = 0;
@@ -640,7 +641,7 @@ mult
} while (x < xae);
*xc = carry;
}
- if (y = *xb >> 16) {
+ if ( (y = *xb >> 16) ) {
x = xa;
xc = xc0;
carry = 0;
@@ -689,7 +690,7 @@ pow5mult
int i;
static int p05[3] = { 5, 25, 125 };
- if (i = k & 3)
+ if ( (i = k & 3) )
b = multadd(b, p05[i-1], 0);
if (!(k >>= 2))
@@ -751,7 +752,7 @@ lshift
*x1++ = *x << k | z;
z = *x++ >> k1;
} while (x < xe);
- if (*x1 = z)
+ if ( (*x1 = z) )
++n1;
}
#else
@@ -917,7 +918,7 @@ ulp
} else {
word0(a) = 0;
L -= Exp_shift;
- word1(a) = L >= 31 ? 1 : 1 << 31 - L;
+ word1(a) = L >= 31 ? 1 : 1 << (31 - L);
}
}
#endif
@@ -952,16 +953,16 @@ b2d
*e = 32 - k;
#ifdef Pack_32
if (k < Ebits) {
- d0 = Exp_1 | y >> Ebits - k;
+ d0 = Exp_1 | (y >> (Ebits - k));
w = xa > xa0 ? *--xa : 0;
- d1 = y << (32-Ebits) + k | w >> Ebits - k;
+ d1 = (y << ((32-Ebits) + k)) | (w >> (Ebits - k));
goto ret_d;
}
z = xa > xa0 ? *--xa : 0;
if (k -= Ebits) {
- d0 = Exp_1 | y << k | z >> 32 - k;
+ d0 = Exp_1 | (y << k) | (z >> (32 - k));
y = xa > xa0 ? *--xa : 0;
- d1 = z << k | y >> 32 - k;
+ d1 = (z << k) | (y >> (32 - k));
} else {
d0 = Exp_1 | y;
d1 = z;
@@ -1028,13 +1029,13 @@ d2b
z |= Exp_msk11;
#endif
#else
- if (de = (int)(d0 >> Exp_shift))
+ if ( (de = (int)(d0 >> Exp_shift)) )
z |= Exp_msk1;
#endif
#ifdef Pack_32
- if (y = d1) {
- if (k = lo0bits(&y)) {
- x[0] = y | z << 32 - k;
+ if ( (y = d1) ) {
+ if ( (k = lo0bits(&y)) ) {
+ x[0] = y | (z << (32 - k));
z >>= k;
}
else
@@ -1212,14 +1213,9 @@ strtod
case 0:
s = s00;
goto ret;
- case '\t':
- case '\n':
- case '\v':
- case '\f':
- case '\r':
- case ' ':
- continue;
default:
+ if (isspace((unsigned char)*s))
+ continue;
goto break2;
}
break2:
@@ -1375,9 +1371,9 @@ strtod
/* Get starting approximation = rv * 10**e1 */
if (e1 > 0) {
- if (i = e1 & 15)
+ if ( (i = e1 & 15) )
rv *= tens[i];
- if (e1 &= ~15) {
+ if ( (e1 &= ~15) ) {
if (e1 > DBL_MAX_10_EXP) {
ovfl:
errno = ERANGE;
@@ -1417,9 +1413,9 @@ strtod
}
} else if (e1 < 0) {
e1 = -e1;
- if (i = e1 & 15)
+ if ( (i = e1 & 15) )
rv /= tens[i];
- if (e1 &= ~15) {
+ if ( (e1 &= ~15) ) {
e1 >>= 4;
for (j = 0; e1 > 1; j++, e1 >>= 1)
if (e1 & 1)
@@ -1950,13 +1946,13 @@ __dtoa
#ifdef Sudden_Underflow
i = (int)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1));
#else
- if (i = (int)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1))) {
+ if ( (i = (int)((word0(d) >> Exp_shift1) & (Exp_mask>>Exp_shift1))) ) {
#endif
d2 = d;
word0(d2) &= Frac_mask1;
word0(d2) |= Exp_11;
#ifdef IBM
- if (j = 11 - hi0bits(word0(d2) & Frac_mask))
+ if ( (j = 11 - hi0bits(word0(d2) & Frac_mask)) )
d2 /= 1 << j;
#endif
@@ -1993,8 +1989,8 @@ __dtoa
/* d is denormalized */
i = bbits + be + (Bias + (P-1) - 1);
- x = i > 32 ? word0(d) << 64 - i | word1(d) >> i - 32
- : word1(d) << 32 - i;
+ x = i > 32 ? ((word0(d) << (64 - i)) | (word1(d) >> (i - 32)))
+ : (word1(d) << (32 - i));
d2 = x;
word0(d2) -= 31*Exp_msk1; /* adjust exponent */
i -= (Bias + (P-1) - 1) + 1;
@@ -2091,7 +2087,7 @@ __dtoa
ds *= bigtens[i];
}
d /= ds;
- } else if (j1 = -k) {
+ } else if ( (j1 = -k) ) {
d *= tens[j1 & 0xf];
for (j = j1 >> 4; j; j >>= 1, i++)
if (j & 1) {
@@ -2190,7 +2186,7 @@ __dtoa
*s++ = '0' + (int)L;
if (i == ilim) {
d += d;
- if (d > ds || d == ds && L & 1) {
+ if (d > ds || (d == ds && L & 1)) {
bump_up:
while (*--s == '9')
if (s == s0) {
@@ -2254,7 +2250,7 @@ __dtoa
Bfree(b);
b = b1;
}
- if (j = b5 - m5)
+ if ( (j = b5 - m5) )
b = pow5mult(b, j);
} else
b = pow5mult(b, b5);
@@ -2287,10 +2283,10 @@ __dtoa
* can do shifts and ors to compute the numerator for q.
*/
#ifdef Pack_32
- if (i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f)
+ if ( (i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f) )
i = 32 - i;
#else
- if (i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0xf)
+ if ( (i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0xf) )
i = 16 - i;
#endif
if (i > 4) {
@@ -2363,15 +2359,15 @@ __dtoa
goto ret;
}
#endif
- if (j < 0 || j == 0 && !mode
+ if (j < 0 || (j == 0 && !mode
#ifndef ROUND_BIASED
&& !(word1(d) & 1)
#endif
- ) {
+ )) {
if (j1 > 0) {
b = lshift(b, 1);
j1 = cmp(b, S);
- if ((j1 > 0 || j1 == 0 && dig & 1)
+ if ((j1 > 0 || (j1 == 0 && dig & 1))
&& dig++ == '9')
goto round_9_up;
}
@@ -2410,7 +2406,7 @@ __dtoa
b = lshift(b, 1);
j = cmp(b, S);
- if (j > 0 || j == 0 && dig & 1) {
+ if (j > 0 || (j == 0 && dig & 1)) {
roundoff:
while (*--s == '9')
if (s == s0) {
diff --git a/lib/libc/stdlib/strtol.c b/lib/libc/stdlib/strtol.c
index 1a7f7b3..18e3972 100644
--- a/lib/libc/stdlib/strtol.c
+++ b/lib/libc/stdlib/strtol.c
@@ -55,7 +55,7 @@ strtol(nptr, endptr, base)
{
register const char *s = nptr;
register unsigned long acc;
- register int c;
+ register unsigned char c;
register unsigned long cutoff;
register int neg = 0, any, cutlim;
@@ -102,6 +102,8 @@ strtol(nptr, endptr, base)
cutlim = cutoff % (unsigned long)base;
cutoff /= (unsigned long)base;
for (acc = 0, any = 0;; c = *s++) {
+ if (!isascii(c))
+ break;
if (isdigit(c))
c -= '0';
else if (isalpha(c))
@@ -110,7 +112,7 @@ strtol(nptr, endptr, base)
break;
if (c >= base)
break;
- if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim)
+ if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
any = -1;
else {
any = 1;
diff --git a/lib/libc/stdlib/strtoll.c b/lib/libc/stdlib/strtoll.c
new file mode 100644
index 0000000..2666749
--- /dev/null
+++ b/lib/libc/stdlib/strtoll.c
@@ -0,0 +1,138 @@
+/*-
+ * Copyright (c) 1992, 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[] = "@(#)strtoq.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+
+#include <limits.h>
+#include <errno.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+/*
+ * Convert a string to a quad integer.
+ *
+ * Ignores `locale' stuff. Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+quad_t
+strtoq(nptr, endptr, base)
+ const char *nptr;
+ char **endptr;
+ register int base;
+{
+ register const char *s;
+ register u_quad_t acc;
+ register unsigned char c;
+ register u_quad_t qbase, cutoff;
+ register int neg, any, cutlim;
+
+ /*
+ * Skip white space and pick up leading +/- sign if any.
+ * If base is 0, allow 0x for hex and 0 for octal, else
+ * assume decimal; if base is already 16, allow 0x.
+ */
+ s = nptr;
+ do {
+ c = *s++;
+ } while (isspace(c));
+ if (c == '-') {
+ neg = 1;
+ c = *s++;
+ } else {
+ neg = 0;
+ if (c == '+')
+ c = *s++;
+ }
+ if ((base == 0 || base == 16) &&
+ c == '0' && (*s == 'x' || *s == 'X')) {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = c == '0' ? 8 : 10;
+
+ /*
+ * Compute the cutoff value between legal numbers and illegal
+ * numbers. That is the largest legal value, divided by the
+ * base. An input number that is greater than this value, if
+ * followed by a legal input character, is too big. One that
+ * is equal to this value may be valid or not; the limit
+ * between valid and invalid numbers is then based on the last
+ * digit. For instance, if the range for quads is
+ * [-9223372036854775808..9223372036854775807] and the input base
+ * is 10, cutoff will be set to 922337203685477580 and cutlim to
+ * either 7 (neg==0) or 8 (neg==1), meaning that if we have
+ * accumulated a value > 922337203685477580, or equal but the
+ * next digit is > 7 (or 8), the number is too big, and we will
+ * return a range error.
+ *
+ * Set any if any `digits' consumed; make it negative to indicate
+ * overflow.
+ */
+ qbase = (unsigned)base;
+ cutoff = neg ? -(u_quad_t)QUAD_MIN : QUAD_MAX;
+ cutlim = cutoff % qbase;
+ cutoff /= qbase;
+ for (acc = 0, any = 0;; c = *s++) {
+ if (!isascii(c))
+ break;
+ if (isdigit(c))
+ c -= '0';
+ else if (isalpha(c))
+ c -= isupper(c) ? 'A' - 10 : 'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
+ any = -1;
+ else {
+ any = 1;
+ acc *= qbase;
+ acc += c;
+ }
+ }
+ if (any < 0) {
+ acc = neg ? QUAD_MIN : QUAD_MAX;
+ errno = ERANGE;
+ } else if (neg)
+ acc = -acc;
+ if (endptr != 0)
+ *endptr = (char *)(any ? s - 1 : nptr);
+ return (acc);
+}
diff --git a/lib/libc/stdlib/strtoq.c b/lib/libc/stdlib/strtoq.c
index b31cca4..2666749 100644
--- a/lib/libc/stdlib/strtoq.c
+++ b/lib/libc/stdlib/strtoq.c
@@ -56,7 +56,7 @@ strtoq(nptr, endptr, base)
{
register const char *s;
register u_quad_t acc;
- register int c;
+ register unsigned char c;
register u_quad_t qbase, cutoff;
register int neg, any, cutlim;
@@ -109,6 +109,8 @@ strtoq(nptr, endptr, base)
cutlim = cutoff % qbase;
cutoff /= qbase;
for (acc = 0, any = 0;; c = *s++) {
+ if (!isascii(c))
+ break;
if (isdigit(c))
c -= '0';
else if (isalpha(c))
@@ -117,7 +119,7 @@ strtoq(nptr, endptr, base)
break;
if (c >= base)
break;
- if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim)
+ if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
any = -1;
else {
any = 1;
diff --git a/lib/libc/stdlib/strtoul.c b/lib/libc/stdlib/strtoul.c
index e60556c0..304150a 100644
--- a/lib/libc/stdlib/strtoul.c
+++ b/lib/libc/stdlib/strtoul.c
@@ -54,7 +54,7 @@ strtoul(nptr, endptr, base)
{
register const char *s = nptr;
register unsigned long acc;
- register int c;
+ register unsigned char c;
register unsigned long cutoff;
register int neg = 0, any, cutlim;
@@ -80,6 +80,8 @@ strtoul(nptr, endptr, base)
cutoff = (unsigned long)ULONG_MAX / (unsigned long)base;
cutlim = (unsigned long)ULONG_MAX % (unsigned long)base;
for (acc = 0, any = 0;; c = *s++) {
+ if (!isascii(c))
+ break;
if (isdigit(c))
c -= '0';
else if (isalpha(c))
@@ -88,7 +90,7 @@ strtoul(nptr, endptr, base)
break;
if (c >= base)
break;
- if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim)
+ if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
any = -1;
else {
any = 1;
diff --git a/lib/libc/stdlib/strtoull.c b/lib/libc/stdlib/strtoull.c
new file mode 100644
index 0000000..7656a3c
--- /dev/null
+++ b/lib/libc/stdlib/strtoull.c
@@ -0,0 +1,116 @@
+/*-
+ * Copyright (c) 1992, 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[] = "@(#)strtouq.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+
+#include <limits.h>
+#include <errno.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+/*
+ * Convert a string to an unsigned quad integer.
+ *
+ * Ignores `locale' stuff. Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+u_quad_t
+strtouq(nptr, endptr, base)
+ const char *nptr;
+ char **endptr;
+ register int base;
+{
+ register const char *s = nptr;
+ register u_quad_t acc;
+ register unsigned char c;
+ register u_quad_t qbase, cutoff;
+ register int neg, any, cutlim;
+
+ /*
+ * See strtoq for comments as to the logic used.
+ */
+ s = nptr;
+ do {
+ c = *s++;
+ } while (isspace(c));
+ if (c == '-') {
+ neg = 1;
+ c = *s++;
+ } else {
+ neg = 0;
+ if (c == '+')
+ c = *s++;
+ }
+ if ((base == 0 || base == 16) &&
+ c == '0' && (*s == 'x' || *s == 'X')) {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = c == '0' ? 8 : 10;
+ qbase = (unsigned)base;
+ cutoff = (u_quad_t)UQUAD_MAX / qbase;
+ cutlim = (u_quad_t)UQUAD_MAX % qbase;
+ for (acc = 0, any = 0;; c = *s++) {
+ if (!isascii(c))
+ break;
+ if (isdigit(c))
+ c -= '0';
+ else if (isalpha(c))
+ c -= isupper(c) ? 'A' - 10 : 'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
+ any = -1;
+ else {
+ any = 1;
+ acc *= qbase;
+ acc += c;
+ }
+ }
+ if (any < 0) {
+ acc = UQUAD_MAX;
+ errno = ERANGE;
+ } else if (neg)
+ acc = -acc;
+ if (endptr != 0)
+ *endptr = (char *)(any ? s - 1 : nptr);
+ return (acc);
+}
diff --git a/lib/libc/stdlib/strtouq.c b/lib/libc/stdlib/strtouq.c
index cc62a07..7656a3c 100644
--- a/lib/libc/stdlib/strtouq.c
+++ b/lib/libc/stdlib/strtouq.c
@@ -56,7 +56,7 @@ strtouq(nptr, endptr, base)
{
register const char *s = nptr;
register u_quad_t acc;
- register int c;
+ register unsigned char c;
register u_quad_t qbase, cutoff;
register int neg, any, cutlim;
@@ -70,7 +70,7 @@ strtouq(nptr, endptr, base)
if (c == '-') {
neg = 1;
c = *s++;
- } else {
+ } else {
neg = 0;
if (c == '+')
c = *s++;
@@ -87,6 +87,8 @@ strtouq(nptr, endptr, base)
cutoff = (u_quad_t)UQUAD_MAX / qbase;
cutlim = (u_quad_t)UQUAD_MAX % qbase;
for (acc = 0, any = 0;; c = *s++) {
+ if (!isascii(c))
+ break;
if (isdigit(c))
c -= '0';
else if (isalpha(c))
@@ -95,7 +97,7 @@ strtouq(nptr, endptr, base)
break;
if (c >= base)
break;
- if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim)
+ if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
any = -1;
else {
any = 1;
diff --git a/lib/libc/stdlib/system.3 b/lib/libc/stdlib/system.3
index d89c79e..9b82e7b 100644
--- a/lib/libc/stdlib/system.3
+++ b/lib/libc/stdlib/system.3
@@ -76,7 +76,7 @@ The
.Fn system
function
returns the exit status of the shell, or \-1 if the
-.Xr wait 3
+.Xr wait 2
for the shell failed.
A return value of 127 means the execution of the shell
failed.
@@ -91,3 +91,6 @@ The
function
conforms to
.St -ansiC .
+and is expected to be
+.St -p1003.2
+compatible.
diff --git a/lib/libc/stdlib/system.c b/lib/libc/stdlib/system.c
index c438f17..00db7d6 100644
--- a/lib/libc/stdlib/system.c
+++ b/lib/libc/stdlib/system.c
@@ -42,35 +42,51 @@ static char sccsid[] = "@(#)system.c 8.1 (Berkeley) 6/4/93";
#include <stddef.h>
#include <unistd.h>
#include <paths.h>
+#include <errno.h>
-system(command)
+int system(command)
const char *command;
{
- union wait pstat;
pid_t pid;
- int omask;
- sig_t intsave, quitsave;
+ int pstat;
+ struct sigaction ign, intact, quitact;
+ sigset_t newsigblock, oldsigblock;
if (!command) /* just checking... */
return(1);
- omask = sigblock(sigmask(SIGCHLD));
- switch(pid = vfork()) {
+ /*
+ * Ignore SIGINT and SIGQUIT, block SIGCHLD. Remember to save
+ * existing signal dispositions.
+ */
+ ign.sa_handler = SIG_IGN;
+ (void)sigemptyset(&ign.sa_mask);
+ ign.sa_flags = 0;
+ (void)sigaction(SIGINT, &ign, &intact);
+ (void)sigaction(SIGQUIT, &ign, &quitact);
+ (void)sigemptyset(&newsigblock);
+ (void)sigaddset(&newsigblock, SIGCHLD);
+ (void)sigprocmask(SIG_BLOCK, &newsigblock, &oldsigblock);
+ switch(pid = fork()) {
case -1: /* error */
- (void)sigsetmask(omask);
- pstat.w_status = 0;
- pstat.w_retcode = 127;
- return(pstat.w_status);
+ break;
case 0: /* child */
- (void)sigsetmask(omask);
+ /*
+ * Restore original signal dispositions and exec the command.
+ */
+ (void)sigaction(SIGINT, &intact, NULL);
+ (void)sigaction(SIGQUIT, &quitact, NULL);
+ (void)sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
execl(_PATH_BSHELL, "sh", "-c", command, (char *)NULL);
_exit(127);
+ default: /* parent */
+ do {
+ pid = waitpid(pid, &pstat, 0);
+ } while (pid == -1 && errno == EINTR);
+ break;
}
- intsave = signal(SIGINT, SIG_IGN);
- quitsave = signal(SIGQUIT, SIG_IGN);
- pid = waitpid(pid, (int *)&pstat, 0);
- (void)sigsetmask(omask);
- (void)signal(SIGINT, intsave);
- (void)signal(SIGQUIT, quitsave);
- return(pid == -1 ? -1 : pstat.w_status);
+ (void)sigaction(SIGINT, &intact, NULL);
+ (void)sigaction(SIGQUIT, &quitact, NULL);
+ (void)sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
+ return(pid == -1 ? -1 : pstat);
}
OpenPOWER on IntegriCloud