Make RandState thread-specific.

This commit is contained in:
Jordan Bancino 2023-05-11 02:17:04 +00:00
parent 609890654e
commit c1c57fd4cf

View file

@ -25,6 +25,7 @@
#include <Int.h> #include <Int.h>
#include <Util.h> #include <Util.h>
#include <Memory.h>
#include <stdlib.h> #include <stdlib.h>
#include <pthread.h> #include <pthread.h>
@ -97,6 +98,12 @@ RandGenerate(RandState * state)
return result; return result;
} }
static void
RandDestructor(void *p)
{
Free(p);
}
/* Generate random numbers using rejection sampling. The basic idea is /* Generate random numbers using rejection sampling. The basic idea is
* to "reroll" if a number happens to be outside the range. However * to "reroll" if a number happens to be outside the range. However
* this could be extremely inefficient. * this could be extremely inefficient.
@ -112,23 +119,33 @@ RandGenerate(RandState * state)
void void
RandIntN(int *buf, size_t size, unsigned int max) RandIntN(int *buf, size_t size, unsigned int max)
{ {
static pthread_mutex_t stateLock = PTHREAD_MUTEX_INITIALIZER; static pthread_key_t stateKey;
static UInt32 seed = 0; static int createdKey = 0;
static RandState state;
/* Limit the range to banish all previously biased results */ /* Limit the range to banish all previously biased results */
const int allowed = RAND_MAX - RAND_MAX % max; const int allowed = RAND_MAX - RAND_MAX % max;
RandState *state;
int tmp; int tmp;
size_t i; size_t i;
pthread_mutex_lock(&stateLock); if (!createdKey)
{
pthread_key_create(&stateKey, RandDestructor);
createdKey = 1;
}
if (!seed) state = pthread_getspecific(stateKey);
if (!state)
{ {
/* Generate a seed from the system time, PID, and TID */ /* Generate a seed from the system time, PID, and TID */
seed = UtilServerTs() ^ getpid() ^ (unsigned long) pthread_self(); UInt32 seed = UtilServerTs() ^ getpid() ^ (unsigned long) pthread_self();
RandSeed(&state, seed);
state = Malloc(sizeof(RandState));
RandSeed(state, seed);
pthread_setspecific(stateKey, state);
} }
/* Generate {size} random numbers. */ /* Generate {size} random numbers. */
@ -137,13 +154,11 @@ RandIntN(int *buf, size_t size, unsigned int max)
/* Most of the time, this will take about 1 loop */ /* Most of the time, this will take about 1 loop */
do do
{ {
tmp = RandGenerate(&state); tmp = RandGenerate(state);
} while (tmp > allowed); } while (tmp > allowed);
buf[i] = tmp % max; buf[i] = tmp % max;
} }
pthread_mutex_unlock(&stateLock);
} }
/* Generate just 1 random number */ /* Generate just 1 random number */