summaryrefslogtreecommitdiff
path: root/random.c
diff options
context:
space:
mode:
Diffstat (limited to 'random.c')
-rw-r--r--random.c76
1 files changed, 60 insertions, 16 deletions
diff --git a/random.c b/random.c
index d0849ebc93..921ec7c52d 100644
--- a/random.c
+++ b/random.c
@@ -199,6 +199,7 @@ rb_genrand_real(void)
return genrand_real();
}
+static int seed_initialized = 0;
static VALUE saved_seed = INT2FIX(0);
static VALUE
@@ -259,27 +260,21 @@ rand_init(VALUE vseed)
return old;
}
-static VALUE
-random_seed(void)
+#define DEFAULT_SEED_LEN (4 * sizeof(long))
+
+static void
+fill_random_seed(char *ptr)
{
static int n = 0;
+ unsigned long *seed;
struct timeval tv;
int fd;
struct stat statbuf;
+ char *buf = (char*)ptr;
- int seed_len;
- BDIGIT *digits;
- unsigned long *seed;
- NEWOBJ(big, struct RBignum);
- OBJSETUP(big, rb_cBignum, T_BIGNUM);
+ seed = (unsigned long *)buf;
- seed_len = 4 * sizeof(long);
- RBIGNUM_SET_SIGN(big, 1);
- rb_big_resize((VALUE)big, seed_len / SIZEOF_BDIGITS + 1);
- digits = RBIGNUM_DIGITS(big);
- seed = (unsigned long *)RBIGNUM_DIGITS(big);
-
- memset(digits, 0, RBIGNUM_LEN(big) * SIZEOF_BDIGITS);
+ memset(buf, 0, DEFAULT_SEED_LEN);
#ifdef S_ISCHR
if ((fd = open("/dev/urandom", O_RDONLY
@@ -294,7 +289,7 @@ random_seed(void)
#endif
)) >= 0) {
if (fstat(fd, &statbuf) == 0 && S_ISCHR(statbuf.st_mode)) {
- read(fd, seed, seed_len);
+ read(fd, seed, DEFAULT_SEED_LEN);
}
close(fd);
}
@@ -305,6 +300,20 @@ random_seed(void)
seed[1] ^= tv.tv_sec;
seed[2] ^= getpid() ^ (n++ << 16);
seed[3] ^= (unsigned long)&seed;
+}
+
+static VALUE
+make_seed_value(char *ptr)
+{
+ BDIGIT *digits;
+ NEWOBJ(big, struct RBignum);
+ OBJSETUP(big, rb_cBignum, T_BIGNUM);
+
+ RBIGNUM_SET_SIGN(big, 1);
+ rb_big_resize((VALUE)big, DEFAULT_SEED_LEN / SIZEOF_BDIGITS + 1);
+ digits = RBIGNUM_DIGITS(big);
+
+ MEMCPY((char *)RBIGNUM_DIGITS(big), ptr, char, DEFAULT_SEED_LEN);
/* set leading-zero-guard if need. */
digits[RBIGNUM_LEN(big)-1] = digits[RBIGNUM_LEN(big)-2] <= 1 ? 1 : 0;
@@ -312,6 +321,14 @@ random_seed(void)
return rb_big_norm((VALUE)big);
}
+static VALUE
+random_seed(void)
+{
+ char buf[DEFAULT_SEED_LEN];
+ fill_random_seed(buf);
+ return make_seed_value(buf);
+}
+
/*
* call-seq:
* srand(number=0) => old_seed
@@ -453,6 +470,9 @@ rb_f_rand(int argc, VALUE *argv, VALUE obj)
long val, max;
rb_scan_args(argc, argv, "01", &vmax);
+ if (!seed_initialized) {
+ rand_init(random_seed());
+ }
switch (TYPE(vmax)) {
case T_FLOAT:
if (RFLOAT_VALUE(vmax) <= LONG_MAX && RFLOAT_VALUE(vmax) >= LONG_MIN) {
@@ -499,10 +519,34 @@ rb_f_rand(int argc, VALUE *argv, VALUE obj)
return LONG2NUM(val);
}
+static char initial_seed[DEFAULT_SEED_LEN];
+
+void
+Init_RandomSeed(void)
+{
+ fill_random_seed(initial_seed);
+ init_by_array((unsigned long*)initial_seed, DEFAULT_SEED_LEN/sizeof(unsigned long));
+ seed_initialized = 1;
+}
+
+static void
+Init_RandomSeed2(void)
+{
+ saved_seed = make_seed_value(initial_seed);
+ memset(initial_seed, 0, DEFAULT_SEED_LEN);
+}
+
+void
+rb_reset_random_seed(void)
+{
+ seed_initialized = 0;
+ saved_seed = INT2FIX(0);
+}
+
void
Init_Random(void)
{
- rand_init(random_seed());
+ Init_RandomSeed2();
rb_define_global_function("srand", rb_f_srand, -1);
rb_define_global_function("rand", rb_f_rand, -1);
rb_global_variable(&saved_seed);