Skip to content

Commit

Permalink
Implement C99's _Exit() interface.
Browse files Browse the repository at this point in the history
Implement a version of qsort that provides a thunk to the comparison function.

Update manual pages.
  • Loading branch information
gwollman committed Sep 10, 2002
1 parent 3c4b3f0 commit ab723a2
Show file tree
Hide file tree
Showing 6 changed files with 158 additions and 55 deletions.
7 changes: 4 additions & 3 deletions lib/libc/stdlib/Makefile.inc
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
# machine-independent stdlib sources
.PATH: ${.CURDIR}/../libc/${MACHINE_ARCH}/stdlib ${.CURDIR}/../libc/stdlib

MISRCS+=abort.c abs.c atexit.c atof.c atoi.c atol.c atoll.c \
MISRCS+=_Exit.c abort.c abs.c atexit.c atof.c atoi.c atol.c atoll.c \
bsearch.c calloc.c div.c exit.c getenv.c getopt.c \
getsubopt.c hcreate.c heapsort.c imaxabs.c imaxdiv.c \
labs.c ldiv.c llabs.c lldiv.c malloc.c merge.c putenv.c \
qsort.c radixsort.c rand.c random.c reallocf.c realpath.c \
qsort.c qsort_r.c radixsort.c rand.c random.c reallocf.c realpath.c \
setenv.c strfmon.c strhash.c strtod.c strtoimax.c strtol.c strtoll.c \
strtoq.c strtoul.c strtoull.c strtoumax.c strtouq.c system.c \
tdelete.c tfind.c tsearch.c twalk.c
Expand All @@ -26,9 +26,10 @@ MAN+= abort.3 abs.3 alloca.3 atexit.3 atof.3 atoi.3 atol.3 bsearch.3 \
realpath.3 strfmon.3 strtod.3 strtol.3 strtoul.3 system.3 tsearch.3

MLINKS+=atol.3 atoll.3
MLINKS+=exit.3 _Exit.3
MLINKS+=getenv.3 putenv.3 getenv.3 setenv.3 getenv.3 unsetenv.3
MLINKS+=hcreate.3 hdestroy.3 hcreate.3 hsearch.3
MLINKS+=qsort.3 heapsort.3 qsort.3 mergesort.3
MLINKS+=qsort.3 heapsort.3 qsort.3 mergesort.3 qsort.3 qsort_r.3
MLINKS+=rand.3 rand_r.3 rand.3 srand.3 rand.3 sranddev.3
MLINKS+=random.3 initstate.3 random.3 setstate.3 random.3 srandom.3 \
random.3 srandomdev.3
Expand Down
22 changes: 22 additions & 0 deletions lib/libc/stdlib/_Exit.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* This file is in the public domain. Written by Garrett A. Wollman,
* 2002-09-07.
*
* $FreeBSD$
*/

#include <stdlib.h>
#include <unistd.h>

/*
* ISO C99 added this function to provide for Standard C applications
* which needed something like POSIX _exit(). A new interface was created
* in case it turned out that _exit() was insufficient to meet the
* requirements of ISO C. (That's probably not the case, but here
* is where you would put the extra code if it were.)
*/
void
_Exit(int code)
{
_exit(code);
}
69 changes: 47 additions & 22 deletions lib/libc/stdlib/exit.3
Original file line number Diff line number Diff line change
Expand Up @@ -36,24 +36,30 @@
.\" @(#)exit.3 8.1 (Berkeley) 6/4/93
.\" $FreeBSD$
.\"
.Dd September 6, 2002
.Dd September 9, 2002
.Dt EXIT 3
.Os
.Sh NAME
.Nm exit
.Nm exit , _Exit
.Nd perform normal program termination
.Sh LIBRARY
.Lb libc
.Sh SYNOPSIS
.In stdlib.h
.Ft void
.Fn exit "int status"
.Ft void
.Fn _Exit "int status"
.Sh DESCRIPTION
.Fn Exit
terminates a process.
The
.Fn exit
and
.Fn _Exit
functions terminate a process.
.Pp
Before termination it performs the following functions in the
order listed:
Before termination,
.Fn exit
performs the following functions in the order listed:
.Bl -enum -offset indent
.It
Call the functions registered with the
Expand All @@ -69,16 +75,31 @@ Unlink all files created with the
function.
.El
.Pp
Passing arbitrary values back to the environment as
.Ar status
is considered bad style;
you should use the values
.Dv EXIT_SUCCESS
The
.Fn _Exit
function terminates without calling the functions registered with the
.Xr atexit 3
function, and may or may not perform the other actions listed.
Both functions make the low-order eight bits of the
.Fa status
argument available to a parent process which has called a
.Xr wait 2 Ns -family
function.
.Pp
The C Standard
.Pq St -isoC-99
defines the values
.Li 0 ,
.Dv EXIT_SUCCESS ,
and
.Dv EXIT_FAILURE .
If portability is not a concern, you may
use the values described in
.Xr sysexits 3 .
.Dv EXIT_FAILURE
as possible values of
.Fa status .
Cooperating processes may use other values;
in a program which might be called by a mail transfer agent, the
the values described in
.Xr sysexits 3
may be used to provide more information to the parent process.
.Pp
Note that
.Fn exit
Expand All @@ -87,23 +108,27 @@ using
.Xr atexit 3
itself call
.Fn exit .
Such functions should call
.Xr _exit 2
Such functions must call
.Fn _Exit
instead (although this has other effects as well which may not be desired).
.Sh RETURN VALUES
The
.Fn exit
function
never returns.
and
.Fn _Exit
functions
never return.
.Sh SEE ALSO
.Xr _exit 2 ,
.Xr wait 2 ,
.Xr atexit 3 ,
.Xr intro 3 ,
.Xr sysexits 3 ,
.Xr tmpfile 3
.Sh STANDARDS
The
.Fn exit
function
conforms to
.St -isoC .
and
.Fn _Exit
functions conform to
.St -isoC-99 .
48 changes: 37 additions & 11 deletions lib/libc/stdlib/qsort.3
Original file line number Diff line number Diff line change
Expand Up @@ -36,18 +36,26 @@
.\" @(#)qsort.3 8.1 (Berkeley) 6/4/93
.\" $FreeBSD$
.\"
.Dd June 4, 1993
.Dd September 7, 2002
.Dt QSORT 3
.Os
.Sh NAME
.Nm qsort , heapsort , mergesort
.Nm qsort , qsort_r , heapsort , mergesort
.Nd sort functions
.Sh LIBRARY
.Lb libc
.Sh SYNOPSIS
.In stdlib.h
.Ft void
.Fn qsort "void *base" "size_t nmemb" "size_t size" "int (*compar)(const void *, const void *)"
.Ft void
.Fo qsort_r
.Fa "void *base"
.Fa "size_t nmemb"
.Fa "size_t size"
.Fa "void *thunk"
.Fa "int (*compar)(void *, const void *, const void *)"
.Fc
.Ft int
.Fn heapsort "void *base" "size_t nmemb" "size_t size" "int (*compar)(const void *, const void *)"
.Ft int
Expand Down Expand Up @@ -94,24 +102,40 @@ The comparison function must return an integer less than, equal to, or
greater than zero if the first argument is considered to be respectively
less than, equal to, or greater than the second.
.Pp
The functions
.Fn qsort
The
.Fn qsort_r
function behaves identically to
.Fn qsort ,
except that it takes an additional argument,
.Fa thunk ,
which is passed unchanged as the first argument to function pointed to
.Fa compar .
This allows the comparison function to access additional
data without using global variables, and thus
.Fn qsort_r
is suitable for use in functions which must be reentrant.
.Pp
The algorithms implemented by
.Fn qsort ,
.Fn qsort_r ,
and
.Fn heapsort
are
.Em not
stable, that is, if two members compare as equal, their order in
the sorted array is undefined.
The function
The
.Fn mergesort
is stable.
algorithm is stable.
.Pp
The
.Fn qsort
function is an implementation of C.A.R. Hoare's ``quicksort'' algorithm,
and
.Fn qsort_r
functions are an implementation of C.A.R. Hoare's ``quicksort'' algorithm,
a variant of partition-exchange sorting; in particular, see D.E. Knuth's
Algorithm Q.
.Fn Qsort
.Sy Quicksort
takes O N lg N average time.
This implementation uses median selection to avoid its
O N**2 worst-case behavior.
Expand All @@ -120,7 +144,7 @@ The
.Fn heapsort
function is an implementation of J.W.J. William's ``heapsort'' algorithm,
a variant of selection sorting; in particular, see D.E. Knuth's Algorithm H.
.Fn Heapsort
.Sy Heapsort
takes O N lg N worst-case time.
Its
.Em only
Expand Down Expand Up @@ -151,8 +175,10 @@ untrue.
.Sh RETURN VALUES
The
.Fn qsort
function
returns no value.
and
.Fn qsort_r
functions
return no value.
.Pp
.Rv -std heapsort mergesort
.Sh ERRORS
Expand Down
59 changes: 40 additions & 19 deletions lib/libc/stdlib/qsort.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,12 @@ __FBSDID("$FreeBSD$");

#include <stdlib.h>

#ifdef I_AM_QSORT_R
typedef int cmp_t(void *, const void *, const void *);
#else
typedef int cmp_t(const void *, const void *);
static inline char *med3(char *, char *, char *, cmp_t *);
#endif
static inline char *med3(char *, char *, char *, cmp_t *, void *);
static inline void swapfunc(char *, char *, int, int);

#define min(a, b) (a) < (b) ? a : b
Expand Down Expand Up @@ -83,21 +87,32 @@ swapfunc(a, b, n, swaptype)

#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype)

#ifdef I_AM_QSORT_R
#define CMP(t, x, y) (cmp((t), (x), (y)))
#else
#define CMP(t, x, y) (cmp((x), (y)))
#endif

static inline char *
med3(a, b, c, cmp)
char *a, *b, *c;
cmp_t *cmp;
med3(char *a, char *b, char *c, cmp_t *cmp, void *thunk
#ifndef I_AM_QSORT_R
__unused
#endif
)
{
return cmp(a, b) < 0 ?
(cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a ))
:(cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c ));
return CMP(thunk, a, b) < 0 ?
(CMP(thunk, b, c) < 0 ? b : (CMP(thunk, a, c) < 0 ? c : a ))
:(CMP(thunk, b, c) > 0 ? b : (CMP(thunk, a, c) < 0 ? a : c ));
}

#ifdef I_AM_QSORT_R
void
qsort_r(void *a, size_t n, size_t es, void *thunk, cmp_t *cmp)
#else
#define thunk NULL
void
qsort(a, n, es, cmp)
void *a;
size_t n, es;
cmp_t *cmp;
qsort(void *a, size_t n, size_t es, cmp_t *cmp)
#endif
{
char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
int d, r, swaptype, swap_cnt;
Expand All @@ -106,7 +121,8 @@ loop: SWAPINIT(a, es);
swap_cnt = 0;
if (n < 7) {
for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
for (pl = pm; pl > (char *)a && cmp(pl - es, pl) > 0;
for (pl = pm;
pl > (char *)a && CMP(thunk, pl - es, pl) > 0;
pl -= es)
swap(pl, pl - es);
return;
Expand All @@ -117,26 +133,26 @@ loop: SWAPINIT(a, es);
pn = (char *)a + (n - 1) * es;
if (n > 40) {
d = (n / 8) * es;
pl = med3(pl, pl + d, pl + 2 * d, cmp);
pm = med3(pm - d, pm, pm + d, cmp);
pn = med3(pn - 2 * d, pn - d, pn, cmp);
pl = med3(pl, pl + d, pl + 2 * d, cmp, thunk);
pm = med3(pm - d, pm, pm + d, cmp, thunk);
pn = med3(pn - 2 * d, pn - d, pn, cmp, thunk);
}
pm = med3(pl, pm, pn, cmp);
pm = med3(pl, pm, pn, cmp, thunk);
}
swap(a, pm);
pa = pb = (char *)a + es;

pc = pd = (char *)a + (n - 1) * es;
for (;;) {
while (pb <= pc && (r = cmp(pb, a)) <= 0) {
while (pb <= pc && (r = CMP(thunk, pb, a)) <= 0) {
if (r == 0) {
swap_cnt = 1;
swap(pa, pb);
pa += es;
}
pb += es;
}
while (pb <= pc && (r = cmp(pc, a)) >= 0) {
while (pb <= pc && (r = CMP(thunk, pc, a)) >= 0) {
if (r == 0) {
swap_cnt = 1;
swap(pc, pd);
Expand All @@ -153,7 +169,8 @@ loop: SWAPINIT(a, es);
}
if (swap_cnt == 0) { /* Switch to insertion sort */
for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
for (pl = pm; pl > (char *)a && cmp(pl - es, pl) > 0;
for (pl = pm;
pl > (char *)a && CMP(thunk, pl - es, pl) > 0;
pl -= es)
swap(pl, pl - es);
return;
Expand All @@ -165,7 +182,11 @@ loop: SWAPINIT(a, es);
r = min(pd - pc, pn - pd - es);
vecswap(pb, pn - r, r);
if ((r = pb - pa) > es)
#ifdef I_AM_QSORT_R
qsort_r(a, r / es, es, thunk, cmp);
#else
qsort(a, r / es, es, cmp);
#endif
if ((r = pd - pc) > es) {
/* Iterate rather than recurse to save stack space */
a = pn - r;
Expand Down
8 changes: 8 additions & 0 deletions lib/libc/stdlib/qsort_r.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
* This file is in the public domain. Originally written by Garrett
* A. Wollman.
*
* $FreeBSD$
*/
#define I_AM_QSORT_R
#include "qsort.c"

0 comments on commit ab723a2

Please sign in to comment.