locking support for random() prng
authorRich Felker <dalias@aerifal.cx>
Wed, 29 Jun 2011 19:29:52 +0000 (15:29 -0400)
committerRich Felker <dalias@aerifal.cx>
Wed, 29 Jun 2011 19:29:52 +0000 (15:29 -0400)
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

index 4b2daef2116774776d8287c2191478442309efea..cc5702ed87b003275320e08242d794c8e5a78e36 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <stdlib.h>
 #include <stdint.h>
+#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;
 }