From f7dff1852b996363061e04531a15a3403351c375 Mon Sep 17 00:00:00 2001 From: Rich Felker Date: Wed, 29 Jun 2011 15:29:52 -0400 Subject: locking support for random() prng these interfaces are required to be thread-safe even though they are not state-free. the random number sequence is shared across all threads. --- src/prng/random.c | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/prng/random.c b/src/prng/random.c index 4b2daef..cc5702e 100644 --- a/src/prng/random.c +++ b/src/prng/random.c @@ -7,6 +7,7 @@ #include #include +#include "libc.h" /* this code uses the same lagged fibonacci generator as the @@ -32,6 +33,7 @@ static int n = 31; static int i = 3; static int j = 0; static uint32_t *x = init+1; +static int lock; static uint32_t lcg31(uint32_t x) { return (1103515245*x + 12345) & 0x7fffffff; @@ -53,7 +55,7 @@ static void loadstate(uint32_t *state) { j = x[-1]&0xff; } -void srandom(unsigned seed) { +static void __srandom(unsigned seed) { int k; uint64_t s = seed; @@ -71,11 +73,20 @@ void srandom(unsigned seed) { x[0] |= 1; } +void srandom(unsigned seed) { + LOCK(&lock); + __srandom(seed); + UNLOCK(&lock); +} + char *initstate(unsigned seed, char *state, size_t size) { - void *old = savestate(); + void *old; + if (size < 8) return 0; - else if (size < 32) + LOCK(&lock); + old = savestate(); + if (size < 32) n = 0; else if (size < 64) n = 7; @@ -86,26 +97,36 @@ char *initstate(unsigned seed, char *state, size_t size) { else n = 63; x = (uint32_t*)state + 1; - srandom(seed); + __srandom(seed); + UNLOCK(&lock); return old; } char *setstate(char *state) { - void *old = savestate(); + void *old; + + LOCK(&lock); + old = savestate(); loadstate((uint32_t*)state); + UNLOCK(&lock); return old; } long random(void) { long k; - if (n == 0) - return x[0] = lcg31(x[0]); + LOCK(&lock); + if (n == 0) { + k = x[0] = lcg31(x[0]); + goto end; + } x[i] += x[j]; k = x[i]>>1; if (++i == n) i = 0; if (++j == n) j = 0; +end: + UNLOCK(&lock); return k; } -- cgit v1.1