From 26af642c3723839ffecc86139959434d4957e94e Mon Sep 17 00:00:00 2001 From: Jim Meyering Date: Wed, 22 Oct 2008 11:19:27 +0200 Subject: [PATCH] random_r: new module * modules/random_r: New file. * m4/random_r.m4: New file. * lib/random_r.c: New file, from glibc. * modules/random_r-tests: New file. * tests/test-random_r.c: New file. * lib/stdlib.in.h (srandom_r, initstate_r, setstate_r, random_r): Declare. (RAND_MAX): Define. * m4/stdlib_h.m4: Define and AC_SUBST GNULIB_RANDOM_R and HAVE_RANDOM_R. * modules/stdlib: Substitute them, too. * MODULES.html.sh (Extra functions based on POSIX:2001) [Misc]: Add it. * doc/glibc-functions/initstate_r.texi: Mention the new module. * doc/glibc-functions/random_r.texi: Likewise. * doc/glibc-functions/setstate_r.texi: Likewise. * doc/glibc-functions/srandom_r.texi: Likewise. * config/srclist.txt: Mention it. --- ChangeLog | 20 ++ MODULES.html.sh | 1 + config/srclist.txt | 1 + doc/glibc-functions/initstate_r.texi | 8 +- doc/glibc-functions/random_r.texi | 8 +- doc/glibc-functions/setstate_r.texi | 8 +- doc/glibc-functions/srandom_r.texi | 8 +- lib/random_r.c | 420 +++++++++++++++++++++++++++++++++++ lib/stdlib.in.h | 37 +++ m4/random_r.m4 | 21 ++ m4/stdlib_h.m4 | 4 +- modules/random_r | 24 ++ modules/random_r-tests | 13 ++ modules/stdlib | 2 + tests/test-random_r.c | 56 +++++ 15 files changed, 614 insertions(+), 17 deletions(-) create mode 100644 lib/random_r.c create mode 100644 m4/random_r.m4 create mode 100644 modules/random_r create mode 100644 modules/random_r-tests create mode 100644 tests/test-random_r.c diff --git a/ChangeLog b/ChangeLog index bf5f629cc..47913b92d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,23 @@ +2008-10-23 Jim Meyering + + random_r: new module + * modules/random_r: New file. + * m4/random_r.m4: New file. + * lib/random_r.c: New file, from glibc. + * modules/random_r-tests: New file. + * tests/test-random_r.c: New file. + * lib/stdlib.in.h (srandom_r, initstate_r, setstate_r, random_r): + Declare. + (RAND_MAX): Define. + * m4/stdlib_h.m4: Define and AC_SUBST GNULIB_RANDOM_R and HAVE_RANDOM_R. + * modules/stdlib: Substitute them, too. + * MODULES.html.sh (Extra functions based on POSIX:2001) [Misc]: Add it. + * doc/glibc-functions/initstate_r.texi: Mention the new module. + * doc/glibc-functions/random_r.texi: Likewise. + * doc/glibc-functions/setstate_r.texi: Likewise. + * doc/glibc-functions/srandom_r.texi: Likewise. + * config/srclist.txt: Mention it. + 2008-10-23 David Lutterkort * modules/selinux-h: Search for LIB_SELINUX and mark it as a diff --git a/MODULES.html.sh b/MODULES.html.sh index 968016363..cf79994d4 100755 --- a/MODULES.html.sh +++ b/MODULES.html.sh @@ -2941,6 +2941,7 @@ func_all_modules () func_module quotearg func_module quote func_module readutmp + func_module random_r func_module sysexits func_module verror func_module visibility diff --git a/config/srclist.txt b/config/srclist.txt index 12bbe3609..7d5c195ba 100644 --- a/config/srclist.txt +++ b/config/srclist.txt @@ -179,6 +179,7 @@ $LIBCSRC/stdlib/strtoul.c lib gpl #$LIBCSRC/posix/glob.h lib gpl (glob-libc.h in gnulib) # #$LIBCSRC/stdlib/putenv.c lib gpl +#$LIBCSRC/stdlib/random_r.c lib gpl #$LIBCSRC/stdlib/rpmatch.c lib gpl #$LIBCSRC/stdlib/strtol.c lib gpl #$LIBCSRC/string/strndup.c lib gpl diff --git a/doc/glibc-functions/initstate_r.texi b/doc/glibc-functions/initstate_r.texi index b61a17ed6..238d5dd04 100644 --- a/doc/glibc-functions/initstate_r.texi +++ b/doc/glibc-functions/initstate_r.texi @@ -2,15 +2,15 @@ @subsection @code{initstate_r} @findex initstate_r -Gnulib module: --- +Gnulib module: random_r Portability problems fixed by Gnulib: @itemize +@item +This function is missing on some platforms: +MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0, OpenBSD 3.8, HP-UX 11, IRIX 6.5, Solaris 10, Cygwin, mingw, Interix 3.5. @end itemize Portability problems not fixed by Gnulib: @itemize -@item -This function is missing on some platforms: -MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0, OpenBSD 3.8, HP-UX 11, IRIX 6.5, Solaris 10, Cygwin, mingw, Interix 3.5. @end itemize diff --git a/doc/glibc-functions/random_r.texi b/doc/glibc-functions/random_r.texi index 50081b6d7..be20c0409 100644 --- a/doc/glibc-functions/random_r.texi +++ b/doc/glibc-functions/random_r.texi @@ -2,15 +2,15 @@ @subsection @code{random_r} @findex random_r -Gnulib module: --- +Gnulib module: random_r Portability problems fixed by Gnulib: @itemize +@item +This function is missing on some platforms: +MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0, OpenBSD 3.8, HP-UX 11, IRIX 6.5, Solaris 10, Cygwin, mingw, Interix 3.5. @end itemize Portability problems not fixed by Gnulib: @itemize -@item -This function is missing on some platforms: -MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0, OpenBSD 3.8, HP-UX 11, IRIX 6.5, Solaris 10, Cygwin, mingw, Interix 3.5. @end itemize diff --git a/doc/glibc-functions/setstate_r.texi b/doc/glibc-functions/setstate_r.texi index d0c3492f2..631e125a6 100644 --- a/doc/glibc-functions/setstate_r.texi +++ b/doc/glibc-functions/setstate_r.texi @@ -2,15 +2,15 @@ @subsection @code{setstate_r} @findex setstate_r -Gnulib module: --- +Gnulib module: random_r Portability problems fixed by Gnulib: @itemize +@item +This function is missing on some platforms: +MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0, OpenBSD 3.8, HP-UX 11, IRIX 6.5, Solaris 10, Cygwin, mingw, Interix 3.5. @end itemize Portability problems not fixed by Gnulib: @itemize -@item -This function is missing on some platforms: -MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0, OpenBSD 3.8, HP-UX 11, IRIX 6.5, Solaris 10, Cygwin, mingw, Interix 3.5. @end itemize diff --git a/doc/glibc-functions/srandom_r.texi b/doc/glibc-functions/srandom_r.texi index 348e191ef..0af243f93 100644 --- a/doc/glibc-functions/srandom_r.texi +++ b/doc/glibc-functions/srandom_r.texi @@ -2,15 +2,15 @@ @subsection @code{srandom_r} @findex srandom_r -Gnulib module: --- +Gnulib module: random_r Portability problems fixed by Gnulib: @itemize +@item +This function is missing on some platforms: +MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0, OpenBSD 3.8, HP-UX 11, IRIX 6.5, Solaris 10, Cygwin, mingw, Interix 3.5. @end itemize Portability problems not fixed by Gnulib: @itemize -@item -This function is missing on some platforms: -MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0, OpenBSD 3.8, HP-UX 11, IRIX 6.5, Solaris 10, Cygwin, mingw, Interix 3.5. @end itemize diff --git a/lib/random_r.c b/lib/random_r.c new file mode 100644 index 000000000..3b1d4b6f1 --- /dev/null +++ b/lib/random_r.c @@ -0,0 +1,420 @@ +/* + Copyright (C) 1995, 2005, 2008 Free Software Foundation + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* + Copyright (C) 1983 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. + 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.*/ + +/* + * This is derived from the Berkeley source: + * @(#)random.c 5.5 (Berkeley) 7/6/88 + * It was reworked for the GNU C Library by Roland McGrath. + * Rewritten to be reentrant by Ulrich Drepper, 1995 + */ + +#include + +#include +#include +#include +#include +#include + + +/* An improved random number generation package. In addition to the standard + rand()/srand() like interface, this package also has a special state info + interface. The initstate() routine is called with a seed, an array of + bytes, and a count of how many bytes are being passed in; this array is + then initialized to contain information for random number generation with + that much state information. Good sizes for the amount of state + information are 32, 64, 128, and 256 bytes. The state can be switched by + calling the setstate() function with the same array as was initialized + with initstate(). By default, the package runs with 128 bytes of state + information and generates far better random numbers than a linear + congruential generator. If the amount of state information is less than + 32 bytes, a simple linear congruential R.N.G. is used. Internally, the + state information is treated as an array of longs; the zeroth element of + the array is the type of R.N.G. being used (small integer); the remainder + of the array is the state information for the R.N.G. Thus, 32 bytes of + state information will give 7 longs worth of state information, which will + allow a degree seven polynomial. (Note: The zeroth 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 the state table will act as a linear feedback shift register, + and will have period 2^deg - 1 (where deg is the degree of the polynomial + being used, assuming that the polynomial is irreducible and primitive). + The higher order bits will have longer periods, since their values are + also influenced by pseudo-random carries out of the lower bits. The + total period of the generator is approximately deg*(2**deg - 1); thus + doubling the amount of state information has a vast influence on the + period of the generator. Note: The deg*(2**deg - 1) is an approximation + only good for large deg, when the period of the shift register is the + dominant factor. With deg equal to seven, the period is actually much + longer than the 7*(2**7 - 1) predicted by this formula. */ + + + +/* For each of the currently supported random number generators, we have a + break value on the amount of state information (you need at least this many + bytes of state info to support this random number generator), a degree for + the polynomial (actually a trinomial) that the R.N.G. is based on, and + separation between the two lower order coefficients of the trinomial. */ + +/* Linear congruential. */ +#define TYPE_0 0 +#define BREAK_0 8 +#define DEG_0 0 +#define SEP_0 0 + +/* x**7 + x**3 + 1. */ +#define TYPE_1 1 +#define BREAK_1 32 +#define DEG_1 7 +#define SEP_1 3 + +/* x**15 + x + 1. */ +#define TYPE_2 2 +#define BREAK_2 64 +#define DEG_2 15 +#define SEP_2 1 + +/* x**31 + x**3 + 1. */ +#define TYPE_3 3 +#define BREAK_3 128 +#define DEG_3 31 +#define SEP_3 3 + +/* x**63 + x + 1. */ +#define TYPE_4 4 +#define BREAK_4 256 +#define DEG_4 63 +#define SEP_4 1 + + +/* Array versions of the above information to make code run faster. + Relies on fact that TYPE_i == i. */ + +#define MAX_TYPES 5 /* Max number of types above. */ + +struct random_poly_info +{ + int seps[MAX_TYPES]; + int degrees[MAX_TYPES]; +}; + +static const struct random_poly_info random_poly_info = +{ + { SEP_0, SEP_1, SEP_2, SEP_3, SEP_4 }, + { DEG_0, DEG_1, DEG_2, DEG_3, DEG_4 } +}; + +#ifndef _LIBC +# define weak_alias(local, symbol) +# define __set_errno(e) errno = (e) +# define __srandom_r srandom_r +# define __initstate_r initstate_r +# define __setstate_r setstate_r +# define __random_r random_r +#endif + + + +/* Initialize the random number generator based on the given seed. If the + type is the trivial no-state-information type, just remember the seed. + Otherwise, initializes state[] based on the given "seed" via a linear + congruential generator. Then, the pointers are set to known locations + that are exactly rand_sep places apart. Lastly, it cycles the state + information a given number of times to get rid of any initial dependencies + introduced by the L.C.R.N.G. Note that the initialization of randtbl[] + for default usage relies on values produced by this routine. */ +int +__srandom_r (unsigned int seed, struct random_data *buf) +{ + int type; + int32_t *state; + long int i; + long int word; + int32_t *dst; + int kc; + + if (buf == NULL) + goto fail; + type = buf->rand_type; + if ((unsigned int) type >= MAX_TYPES) + goto fail; + + state = buf->state; + /* We must make sure the seed is not 0. Take arbitrarily 1 in this case. */ + if (seed == 0) + seed = 1; + state[0] = seed; + if (type == TYPE_0) + goto done; + + dst = state; + word = seed; + kc = buf->rand_deg; + for (i = 1; i < kc; ++i) + { + /* This does: + state[i] = (16807 * state[i - 1]) % 2147483647; + but avoids overflowing 31 bits. */ + long int hi = word / 127773; + long int lo = word % 127773; + word = 16807 * lo - 2836 * hi; + if (word < 0) + word += 2147483647; + *++dst = word; + } + + buf->fptr = &state[buf->rand_sep]; + buf->rptr = &state[0]; + kc *= 10; + while (--kc >= 0) + { + int32_t discard; + (void) __random_r (buf, &discard); + } + + done: + return 0; + + fail: + return -1; +} + +weak_alias (__srandom_r, srandom_r) + +/* Initialize the state information in the given array of N bytes for + future random number generation. Based on the number of bytes we + are given, and 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. + Returns a pointer to the old state. */ +int +__initstate_r (unsigned int seed, char *arg_state, size_t n, + struct random_data *buf) +{ + int32_t *old_state; + int32_t *state; + int type; + int degree; + int separation; + + if (buf == NULL) + goto fail; + + old_state = buf->state; + if (old_state != NULL) + { + int old_type = buf->rand_type; + if (old_type == TYPE_0) + old_state[-1] = TYPE_0; + else + old_state[-1] = (MAX_TYPES * (buf->rptr - old_state)) + old_type; + } + + if (n >= BREAK_3) + type = n < BREAK_4 ? TYPE_3 : TYPE_4; + else if (n < BREAK_1) + { + if (n < BREAK_0) + { + __set_errno (EINVAL); + goto fail; + } + type = TYPE_0; + } + else + type = n < BREAK_2 ? TYPE_1 : TYPE_2; + + degree = random_poly_info.degrees[type]; + separation = random_poly_info.seps[type]; + + buf->rand_type = type; + buf->rand_sep = separation; + buf->rand_deg = degree; + state = &((int32_t *) arg_state)[1]; /* First location. */ + /* Must set END_PTR before srandom. */ + buf->end_ptr = &state[degree]; + + buf->state = state; + + __srandom_r (seed, buf); + + state[-1] = TYPE_0; + if (type != TYPE_0) + state[-1] = (buf->rptr - state) * MAX_TYPES + type; + + return 0; + + fail: + __set_errno (EINVAL); + return -1; +} + +weak_alias (__initstate_r, initstate_r) + +/* Restore the state from the given state array. + Note: It is important that we also remember the locations of the pointers + in the current state information, and restore the locations of the pointers + from the old state information. This is done by multiplexing the pointer + location into the zeroth word of the state information. Note that due + to the order in which things are done, it is OK to call setstate with the + same state as the current state + Returns a pointer to the old state information. */ +int +__setstate_r (char *arg_state, struct random_data *buf) +{ + int32_t *new_state = 1 + (int32_t *) arg_state; + int type; + int old_type; + int32_t *old_state; + int degree; + int separation; + + if (arg_state == NULL || buf == NULL) + goto fail; + + old_type = buf->rand_type; + old_state = buf->state; + if (old_type == TYPE_0) + old_state[-1] = TYPE_0; + else + old_state[-1] = (MAX_TYPES * (buf->rptr - old_state)) + old_type; + + type = new_state[-1] % MAX_TYPES; + if (type < TYPE_0 || type > TYPE_4) + goto fail; + + buf->rand_deg = degree = random_poly_info.degrees[type]; + buf->rand_sep = separation = random_poly_info.seps[type]; + buf->rand_type = type; + + if (type != TYPE_0) + { + int rear = new_state[-1] / MAX_TYPES; + buf->rptr = &new_state[rear]; + buf->fptr = &new_state[(rear + separation) % degree]; + } + buf->state = new_state; + /* Set end_ptr too. */ + buf->end_ptr = &new_state[degree]; + + return 0; + + fail: + __set_errno (EINVAL); + return -1; +} + +weak_alias (__setstate_r, setstate_r) + +/* If we are using the trivial TYPE_0 R.N.G., just do the old linear + congruential bit. Otherwise, we do our fancy trinomial stuff, which is the + same in all the other cases due to all the global variables that have been + set up. The basic operation is to add the number at the rear pointer into + the one at the front pointer. Then both pointers are advanced to the next + location cyclically in the table. The value returned is the sum generated, + reduced to 31 bits by throwing away the "least random" low bit. + Note: The code takes advantage of the fact that both the front and + rear pointers can't wrap on the same call by not testing the rear + pointer if the front one has wrapped. Returns a 31-bit random number. */ + +int +__random_r (struct random_data *buf, int32_t *result) +{ + int32_t *state; + + if (buf == NULL || result == NULL) + goto fail; + + state = buf->state; + + if (buf->rand_type == TYPE_0) + { + int32_t val = state[0]; + val = ((state[0] * 1103515245) + 12345) & 0x7fffffff; + state[0] = val; + *result = val; + } + else + { + int32_t *fptr = buf->fptr; + int32_t *rptr = buf->rptr; + int32_t *end_ptr = buf->end_ptr; + int32_t val; + + val = *fptr += *rptr; + /* Chucking least random bit. */ + *result = (val >> 1) & 0x7fffffff; + ++fptr; + if (fptr >= end_ptr) + { + fptr = state; + ++rptr; + } + else + { + ++rptr; + if (rptr >= end_ptr) + rptr = state; + } + buf->fptr = fptr; + buf->rptr = rptr; + } + return 0; + + fail: + __set_errno (EINVAL); + return -1; +} + +weak_alias (__random_r, random_r) diff --git a/lib/stdlib.in.h b/lib/stdlib.in.h index c5615b039..b44703bce 100644 --- a/lib/stdlib.in.h +++ b/lib/stdlib.in.h @@ -217,6 +217,43 @@ extern int putenv (char *string); #endif +#if @GNULIB_RANDOM_R@ +# if !@HAVE_RANDOM_R@ + +# ifndef RAND_MAX +# define RAND_MAX 2147483647 +# endif + +int srandom_r (unsigned int seed, struct random_data *rand_state); +int initstate_r (unsigned int seed, char *buf, size_t buf_size, + struct random_data *rand_state); +int setstate_r (char *arg_state, struct random_data *rand_state); +int random_r (struct random_data *buf, int32_t *result); +# endif +#elif defined GNULIB_POSIXCHECK +# undef random_r +# define random_r(b,r) \ + (GL_LINK_WARNING ("random_r is unportable - " \ + "use gnulib module random_r for portability"), \ + random_r (b,r)) +# undef initstate_r +# define initstate_r(s,b,sz,r) \ + (GL_LINK_WARNING ("initstate_r is unportable - " \ + "use gnulib module random_r for portability"), \ + initstate_r (s,b,sz,r)) +# undef srandom_r +# define srandom_r(s,r) \ + (GL_LINK_WARNING ("srandom_r is unportable - " \ + "use gnulib module random_r for portability"), \ + srandom_r (s,r)) +# undef setstate_r +# define setstate_r(a,r) \ + (GL_LINK_WARNING ("setstate_r is unportable - " \ + "use gnulib module random_r for portability"), \ + setstate_r (a,r)) +#endif + + #if @GNULIB_RPMATCH@ # if !@HAVE_RPMATCH@ /* Test a user response to a question. diff --git a/m4/random_r.m4 b/m4/random_r.m4 new file mode 100644 index 000000000..03e18f80d --- /dev/null +++ b/m4/random_r.m4 @@ -0,0 +1,21 @@ +# serial 1 +dnl Copyright (C) 2008 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +AC_DEFUN([gl_FUNC_RANDOM_R], +[ + AC_REQUIRE([gl_STDLIB_H_DEFAULTS]) + AC_CHECK_FUNCS([random_r]) + if test $ac_cv_func_random_r = no; then + HAVE_RANDOM_R=0 + AC_LIBOBJ([random_r]) + gl_PREREQ_RANDOM_R + fi +]) + +# Prerequisites of lib/random_r.c. +AC_DEFUN([gl_PREREQ_RANDOM_R], [ + : +]) diff --git a/m4/stdlib_h.m4 b/m4/stdlib_h.m4 index 838c5b668..3702d166d 100644 --- a/m4/stdlib_h.m4 +++ b/m4/stdlib_h.m4 @@ -1,4 +1,4 @@ -# stdlib_h.m4 serial 10 +# stdlib_h.m4 serial 11 dnl Copyright (C) 2007, 2008 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -28,6 +28,7 @@ AC_DEFUN([gl_STDLIB_H_DEFAULTS], GNULIB_MKDTEMP=0; AC_SUBST([GNULIB_MKDTEMP]) GNULIB_MKSTEMP=0; AC_SUBST([GNULIB_MKSTEMP]) GNULIB_PUTENV=0; AC_SUBST([GNULIB_PUTENV]) + GNULIB_RANDOM_R=0; AC_SUBST([GNULIB_RANDOM_R]) GNULIB_RPMATCH=0; AC_SUBST([GNULIB_RPMATCH]) GNULIB_SETENV=0; AC_SUBST([GNULIB_SETENV]) GNULIB_STRTOD=0; AC_SUBST([GNULIB_STRTOD]) @@ -41,6 +42,7 @@ AC_DEFUN([gl_STDLIB_H_DEFAULTS], HAVE_MALLOC_POSIX=1; AC_SUBST([HAVE_MALLOC_POSIX]) HAVE_MKDTEMP=1; AC_SUBST([HAVE_MKDTEMP]) HAVE_REALLOC_POSIX=1; AC_SUBST([HAVE_REALLOC_POSIX]) + HAVE_RANDOM_R=1; AC_SUBST([HAVE_RANDOM_R]) HAVE_RPMATCH=1; AC_SUBST([HAVE_RPMATCH]) HAVE_SETENV=1; AC_SUBST([HAVE_SETENV]) HAVE_STRTOD=1; AC_SUBST([HAVE_STRTOD]) diff --git a/modules/random_r b/modules/random_r new file mode 100644 index 000000000..ad5c0f543 --- /dev/null +++ b/modules/random_r @@ -0,0 +1,24 @@ +Description: +reentrant random number generator + +Files: +lib/random_r.c +m4/random_r.m4 + +Depends-on: +stdlib + +configure.ac: +gl_FUNC_RANDOM_R +gl_STDLIB_MODULE_INDICATOR([random_r]) + +Makefile.am: + +Include: +#include + +License: +LGPLv2+ + +Maintainer: +Jim Meyering diff --git a/modules/random_r-tests b/modules/random_r-tests new file mode 100644 index 000000000..814b150a2 --- /dev/null +++ b/modules/random_r-tests @@ -0,0 +1,13 @@ +Files: +tests/test-random_r.c + +Depends-on: + +configure.ac: + +Makefile.am: +TESTS += test-random_r +check_PROGRAMS += test-random_r + +License: +LGPL diff --git a/modules/stdlib b/modules/stdlib index 78b64d0d7..715feeab7 100644 --- a/modules/stdlib +++ b/modules/stdlib @@ -33,6 +33,7 @@ stdlib.h: stdlib.in.h -e 's|@''GNULIB_MKDTEMP''@|$(GNULIB_MKDTEMP)|g' \ -e 's|@''GNULIB_MKSTEMP''@|$(GNULIB_MKSTEMP)|g' \ -e 's|@''GNULIB_PUTENV''@|$(GNULIB_PUTENV)|g' \ + -e 's|@''GNULIB_RANDOM_R''@|$(GNULIB_RANDOM_R)|g' \ -e 's|@''GNULIB_RPMATCH''@|$(GNULIB_RPMATCH)|g' \ -e 's|@''GNULIB_SETENV''@|$(GNULIB_SETENV)|g' \ -e 's|@''GNULIB_STRTOD''@|$(GNULIB_STRTOD)|g' \ @@ -45,6 +46,7 @@ stdlib.h: stdlib.in.h -e 's|@''HAVE_MALLOC_POSIX''@|$(HAVE_MALLOC_POSIX)|g' \ -e 's|@''HAVE_MKDTEMP''@|$(HAVE_MKDTEMP)|g' \ -e 's|@''HAVE_REALLOC_POSIX''@|$(HAVE_REALLOC_POSIX)|g' \ + -e 's|@''HAVE_RANDOM_R''@|$(HAVE_RANDOM_R)|g' \ -e 's|@''HAVE_RPMATCH''@|$(HAVE_RPMATCH)|g' \ -e 's|@''HAVE_SETENV''@|$(HAVE_SETENV)|g' \ -e 's|@''HAVE_STRTOD''@|$(HAVE_STRTOD)|g' \ diff --git a/tests/test-random_r.c b/tests/test-random_r.c new file mode 100644 index 000000000..5308f7337 --- /dev/null +++ b/tests/test-random_r.c @@ -0,0 +1,56 @@ +/* Test random_r. + Copyright (C) 2008 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include +#include +#include +#include + +#define ASSERT(expr) \ + do \ + { \ + if (!(expr)) \ + { \ + fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \ + fflush (stderr); \ + abort (); \ + } \ + } \ + while (0) + +int +main () +{ + struct random_data rand_state; + char buf[128]; + unsigned int i; + unsigned int n_big = 0; + + rand_state.state = NULL; + if (initstate_r (time (NULL), buf, sizeof buf, &rand_state)) + return 1; + for (i = 0; i < 1000; i++) + { + int32_t r; + ASSERT (random_r (&rand_state, &r) == 0); + ASSERT (0 <= r); + if (RAND_MAX / 2 < r) + ++n_big; + } + + /* Fail if none of the numbers were larger than RAND_MAX / 2. */ + return !n_big; +} -- 2.11.0