Replace the rand() which reads from /dev/random with a Mersenne PRNG.
Much better now. Also, it is seeded by reading from /dev/random at startup. Not sure if that's the best idea, but we'll see.
This commit is contained in:
parent
18f1f8b7ca
commit
45afd3e243
@ -117,25 +117,7 @@ int main()
|
||||
|
||||
if (fclose(config) < 0) { perror("fclose"); }
|
||||
|
||||
FILE* fp = fopen("/dev/random", "rw");
|
||||
if (!fp)
|
||||
{
|
||||
perror("fopen");
|
||||
return 1;
|
||||
}
|
||||
|
||||
long int random = 0;
|
||||
|
||||
fread(&random, sizeof(random), 1, fp);
|
||||
if (ferror(fp))
|
||||
{
|
||||
perror("fread");
|
||||
return 1;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
printf("\n\nGot random number %ld\n\n", random);
|
||||
printf("\n\nGot random number %d\n\n", rand());
|
||||
|
||||
sleep(2);
|
||||
|
||||
|
@ -53,7 +53,7 @@ extern "C"
|
||||
/* Returns a random number. */
|
||||
int rand(void);
|
||||
|
||||
/* Does nothing. */
|
||||
/* Seeds the random number generator with the specified seed. */
|
||||
void srand(unsigned int seed);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -10,6 +10,33 @@ static void terminate_libc()
|
||||
fclose(stderr);
|
||||
}
|
||||
|
||||
static void initialize_random()
|
||||
{
|
||||
unsigned int seed = 3735928559U;
|
||||
|
||||
FILE* fp = fopen("/dev/random", "rw");
|
||||
if (!fp)
|
||||
{
|
||||
errno = 0;
|
||||
goto failed_to_read_dev_random;
|
||||
}
|
||||
|
||||
fread(&seed, sizeof(seed), 1, fp);
|
||||
if (ferror(fp))
|
||||
{
|
||||
errno = 0;
|
||||
fclose(fp);
|
||||
goto failed_to_read_dev_random;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
failed_to_read_dev_random:
|
||||
srand(seed); // If we failed, this will be seeded with a known value. Else, it will be seeded with a random value
|
||||
// from the kernel.
|
||||
return;
|
||||
}
|
||||
|
||||
static void check_for_file(int fd, FILE** target_stream, const char* path, const char* mode)
|
||||
{
|
||||
if (lseek(fd, 0, SEEK_CUR) < 0)
|
||||
@ -27,5 +54,7 @@ extern "C" void initialize_libc()
|
||||
{
|
||||
check_for_file(STDOUT_FILENO, &stdout, "/dev/console", "rw");
|
||||
check_for_file(STDERR_FILENO, &stderr, "/dev/console", "rw");
|
||||
|
||||
initialize_random();
|
||||
atexit(terminate_libc);
|
||||
}
|
@ -1,37 +1,64 @@
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static FILE* randfp = nullptr;
|
||||
typedef uint32_t word_t;
|
||||
#define STATE_SIZE 624
|
||||
#define MIDDLE 397
|
||||
#define INIT_SHIFT 30
|
||||
#define INIT_FACT 1812433253
|
||||
#define TWIST_MASK 0x9908b0df
|
||||
#define SHIFT1 11
|
||||
#define MASK1 0xffffffff
|
||||
#define SHIFT2 7
|
||||
#define MASK2 0x9d2c5680
|
||||
#define SHIFT3 15
|
||||
#define MASK3 0xefc60000
|
||||
#define SHIFT4 18
|
||||
|
||||
void close_randfp()
|
||||
#define LOWER_MASK 0x7fffffff
|
||||
#define UPPER_MASK (~(word_t)LOWER_MASK)
|
||||
|
||||
static word_t state[STATE_SIZE];
|
||||
static size_t index = STATE_SIZE + 1;
|
||||
|
||||
static void twist()
|
||||
{
|
||||
fclose(randfp);
|
||||
for (size_t i = 0; i < STATE_SIZE; i++)
|
||||
{
|
||||
word_t x = (state[i] & UPPER_MASK) | (state[(i + 1) % STATE_SIZE] & LOWER_MASK);
|
||||
x = (x >> 1) ^ (x & 1 ? TWIST_MASK : 0);
|
||||
state[i] = state[(i + MIDDLE) % STATE_SIZE] ^ x;
|
||||
}
|
||||
index = 0;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
{
|
||||
int rand() // FIXME: This function is a dirty and extremely hacky way to get going, /dev/random should only be used
|
||||
// for initial seeding, userspace should do their own random calculations.
|
||||
int rand()
|
||||
{
|
||||
if (!randfp)
|
||||
if (index >= STATE_SIZE)
|
||||
{
|
||||
randfp = fopen("/dev/random", "rw");
|
||||
assert(randfp != nullptr);
|
||||
atexit(close_randfp);
|
||||
assert(index == STATE_SIZE && "Mersenne generator was never seeded");
|
||||
twist();
|
||||
}
|
||||
int result;
|
||||
fread(&result, sizeof(result), 1, randfp);
|
||||
if (ferror(randfp))
|
||||
{
|
||||
perror("read(randfp)");
|
||||
abort();
|
||||
}
|
||||
return result;
|
||||
|
||||
word_t y = state[index];
|
||||
y ^= (y >> SHIFT1) & MASK1;
|
||||
y ^= (y << SHIFT2) & MASK2;
|
||||
y ^= (y << SHIFT3) & MASK3;
|
||||
y ^= y >> SHIFT4;
|
||||
|
||||
index++;
|
||||
return y;
|
||||
}
|
||||
|
||||
void srand(unsigned int)
|
||||
void srand(unsigned int seed)
|
||||
{
|
||||
return;
|
||||
index = STATE_SIZE;
|
||||
state[0] = seed;
|
||||
for (size_t i = 1; i < STATE_SIZE; i++)
|
||||
state[i] = (word_t)((INIT_FACT * (state[i - 1] ^ (state[i - 1] >> INIT_SHIFT))) + i);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user