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.
This commit is contained in:
Rich Felker 2011-06-29 15:29:52 -04:00
parent af3d5405b8
commit f7dff1852b
1 changed files with 28 additions and 7 deletions

View 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;
}