git » libfiu » commit 242a627

Seed the prng at init/fork time

author Alberto Bertogli
2009-05-22 03:05:09 UTC
committer Alberto Bertogli
2009-05-22 03:17:50 UTC
parent fad96ca2ab378b2ff86b8dbe5b6433afa2ac850c

Seed the prng at init/fork time

Instead of calling gettimeofday() for each randd() call, we use a seed and
re-seed at fork time, which is much faster.

Signed-off-by: Alberto Bertogli <albertito@blitiri.com.ar>

libfiu/fiu.c +17 -14

diff --git a/libfiu/fiu.c b/libfiu/fiu.c
index f00ef8f..cb1d8de 100644
--- a/libfiu/fiu.c
+++ b/libfiu/fiu.c
@@ -152,33 +152,34 @@ static int shrink_enabled_fails(void)
 	return 0;
 }
 
-/* Returns a random double.
+/* Pseudorandom number generator.
  *
- * We can't just use drand48() or similar and seed at initialization because a
- * lot of normal scenarios involve forking.
+ * The performance of the PRNG is very sensitive to us, so we implement our
+ * own instead of just use drand48() or similar.
  *
  * As we don't really need a very good, thread-safe or secure random source,
  * we use an algorithm similar to the one used in rand() and drand48() (a
  * linear congruential generator, see
  * http://en.wikipedia.org/wiki/Linear_congruential_generator for more
- * information), but also taking into account the microseconds of the current
- * epoch time. Coefficients are the ones used in rand(), so we assume
+ * information). Coefficients are the ones used in rand(), so we assume
  * sizeof(int) >= 4.
  *
- * Microseconds are multiplied because normally they're < 1000000 and they
- * wouldn't really affect the initial outcome. A power of 2 was chosen as the
- * multiplier for efficiency reasons.
- *
- * That change makes the PRNG theoretically worse, but good enough for our
- * purposes. */
+ * To seed it, we use the current microseconds. To prevent seed reuse, we
+ * re-seed after each fork (see atfork_child()). */
 static unsigned int randd_xn = 0xA673F42D;
-static double randd(void)
+
+static void prng_seed(void)
 {
 	struct timeval tv;
 
 	gettimeofday(&tv, NULL);
 
-	randd_xn = (1103515245 * randd_xn + 12345) + tv.tv_usec * 16384;
+	randd_xn = tv.tv_usec;
+}
+
+static double randd(void)
+{
+	randd_xn = 1103515245 * randd_xn + 12345;
 
 	return (double) randd_xn / UINT_MAX;
 }
@@ -187,7 +188,7 @@ static double randd(void)
  * registered via pthread_atfork() in fiu_init(). */
 static void atfork_child(void)
 {
-
+	prng_seed();
 }
 
 
@@ -218,6 +219,8 @@ int fiu_init(unsigned int flags)
 		return -1;
 	}
 
+	prng_seed();
+
 	initialized = 1;
 
 	ef_wunlock();