diff --git a/src/makeint.h b/src/makeint.h index b8dbc1ff..00dded16 100644 --- a/src/makeint.h +++ b/src/makeint.h @@ -537,6 +537,8 @@ void perror_with_name (const char *, const char *); unsigned int make_toui (const char*, const char**); char *make_lltoa (long long, char *); char *make_ulltoa (unsigned long long, char *); +void make_seed (unsigned int); +unsigned int make_rand (); pid_t make_pid (); void *xmalloc (size_t); void *xcalloc (size_t); diff --git a/src/misc.c b/src/misc.c index 8f9be328..48e4cb5e 100644 --- a/src/misc.c +++ b/src/misc.c @@ -78,6 +78,35 @@ make_ulltoa (unsigned long long val, char *buf) return buf; } +/* Simple random number generator, for use with shuffle. + This doesn't need to be truly random, just pretty random. Use our own + implementation rather than relying on the C runtime's rand() so we always + get the same results for a given seed, regardless of OS. */ + +static unsigned int mk_state = 0; + +void +make_seed(unsigned int seed) +{ + mk_state = seed; +} + +unsigned int +make_rand() +{ + /* mk_state must never be 0. */ + if (mk_state == 0) { + mk_state = (unsigned int)(time (NULL) ^ make_pid ()) + 1; + } + + /* A simple xorshift RNG. */ + mk_state ^= mk_state << 13; + mk_state ^= mk_state >> 17; + mk_state ^= mk_state << 5; + + return mk_state; +} + /* Compare strings *S1 and *S2. Return negative if the first is less, positive if it is greater, zero if they are equal. */ diff --git a/src/shuffle.c b/src/shuffle.c index 95f60bea..5f68caf6 100644 --- a/src/shuffle.c +++ b/src/shuffle.c @@ -82,9 +82,7 @@ shuffle_set_mode (const char *cmdarg) } else { - if (strcasecmp (cmdarg, "random") == 0) - config.seed = (unsigned int) (time (NULL) ^ make_pid ()); - else + if (strcasecmp (cmdarg, "random") != 0) { /* Assume explicit seed. */ const char *err; @@ -109,7 +107,7 @@ random_shuffle_array (void **a, size_t len) void *t; /* Pick random element and swap. */ - unsigned int j = rand () % len; + unsigned int j = make_rand () % len; if (i == j) continue; @@ -227,7 +225,7 @@ shuffle_deps_recursive (struct dep *deps) /* Set specific seed at the top level of recursion. */ if (config.mode == sm_random) - srand (config.seed); + make_seed (config.seed); shuffle_deps (deps);