Changeset View
Changeset View
Standalone View
Standalone View
head/lib/libc/stdlib/rand.c
Show All 34 Lines | |||||
static char sccsid[] = "@(#)rand.c 8.1 (Berkeley) 6/14/93"; | static char sccsid[] = "@(#)rand.c 8.1 (Berkeley) 6/14/93"; | ||||
#endif /* LIBC_SCCS and not lint */ | #endif /* LIBC_SCCS and not lint */ | ||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include "namespace.h" | #include "namespace.h" | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/sysctl.h> | #include <sys/sysctl.h> | ||||
#include <assert.h> | |||||
#include <stdbool.h> | #include <stdbool.h> | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <syslog.h> | #include <syslog.h> | ||||
#include "un-namespace.h" | #include "un-namespace.h" | ||||
#include "random.h" | |||||
/* | |||||
* Implement rand(3), the standard C PRNG API, using the non-standard but | |||||
* higher quality random(3) implementation and the same size 128-byte state | |||||
* LFSR as the random(3) default. | |||||
* | |||||
* It turns out there are portable applications that want a PRNG but are too | |||||
* lazy to use better-but-nonstandard interfaces like random(3), when | |||||
* available, and too lazy to import higher-quality and faster PRNGs into their | |||||
* codebase (such as any of SFC, JSF, 128-bit LCGs, PCG, or Splitmix64). | |||||
* | |||||
* Since we're stuck with rand(3) due to the C standard, we can at least have | |||||
* it produce a relatively good PRNG sequence using our existing random(3) | |||||
* LFSR. The random(3) design is not particularly fast nor compact, but it has | |||||
* the advantage of being the one already in the tree. | |||||
*/ | |||||
static struct __random_state *rand3_state; | |||||
static void | |||||
initialize_rand3(void) | |||||
{ | |||||
int error; | |||||
rand3_state = allocatestate(TYPE_3); | |||||
error = initstate_r(rand3_state, 1, rand3_state->rst_randtbl, BREAK_3); | |||||
assert(error == 0); | |||||
} | |||||
int | |||||
rand(void) | |||||
{ | |||||
if (rand3_state == NULL) | |||||
initialize_rand3(); | |||||
return ((int)random_r(rand3_state)); | |||||
} | |||||
void | |||||
srand(unsigned seed) | |||||
{ | |||||
if (rand3_state == NULL) | |||||
initialize_rand3(); | |||||
srandom_r(rand3_state, seed); | |||||
} | |||||
/* | |||||
* FreeBSD 12 and prior compatibility implementation of rand(3). | |||||
*/ | |||||
static int | static int | ||||
do_rand(unsigned long *ctx) | do_rand(unsigned long *ctx) | ||||
{ | { | ||||
/* | /* | ||||
* Compute x = (7^5 * x) mod (2^31 - 1) | * Compute x = (7^5 * x) mod (2^31 - 1) | ||||
* without overflowing 31 bits: | * without overflowing 31 bits: | ||||
* (2^31 - 1) = 127773 * (7^5) + 2836 | * (2^31 - 1) = 127773 * (7^5) + 2836 | ||||
* From "Random number generators: good ones are hard to find", | * From "Random number generators: good ones are hard to find", | ||||
Show All 10 Lines | */ | ||||
if (x < 0) | if (x < 0) | ||||
x += 0x7fffffff; | x += 0x7fffffff; | ||||
/* Transform to [0, 0x7ffffffd] range. */ | /* Transform to [0, 0x7ffffffd] range. */ | ||||
x--; | x--; | ||||
*ctx = x; | *ctx = x; | ||||
return (x); | return (x); | ||||
} | } | ||||
/* | |||||
* Can't fix this garbage; too little state. | |||||
*/ | |||||
int | int | ||||
rand_r(unsigned *ctx) | rand_r(unsigned *ctx) | ||||
{ | { | ||||
u_long val; | u_long val; | ||||
int r; | int r; | ||||
val = *ctx; | val = *ctx; | ||||
r = do_rand(&val); | r = do_rand(&val); | ||||
*ctx = (unsigned)val; | *ctx = (unsigned)val; | ||||
return (r); | return (r); | ||||
} | } | ||||
static u_long next = 1; | static u_long next = 1; | ||||
int __rand_fbsd12(void); | |||||
int | int | ||||
rand(void) | __rand_fbsd12(void) | ||||
{ | { | ||||
return (do_rand(&next)); | return (do_rand(&next)); | ||||
} | } | ||||
__sym_compat(rand, __rand_fbsd12, FBSD_1.0); | |||||
void __srand_fbsd12(unsigned seed); | |||||
void | void | ||||
srand(unsigned seed) | __srand_fbsd12(unsigned seed) | ||||
{ | { | ||||
next = seed; | next = seed; | ||||
} | } | ||||
__sym_compat(srand, __srand_fbsd12, FBSD_1.0); | |||||
void __sranddev_fbsd12(void); | void __sranddev_fbsd12(void); | ||||
void | void | ||||
__sranddev_fbsd12(void) | __sranddev_fbsd12(void) | ||||
{ | { | ||||
static bool warned = false; | static bool warned = false; | ||||
if (!warned) { | if (!warned) { | ||||
syslog(LOG_DEBUG, "Deprecated function sranddev() called"); | syslog(LOG_DEBUG, "Deprecated function sranddev() called"); | ||||
warned = true; | warned = true; | ||||
} | } | ||||
} | } | ||||
__sym_compat(sranddev, __sranddev_fbsd12, FBSD_1.0); | __sym_compat(sranddev, __sranddev_fbsd12, FBSD_1.0); |