diff --git a/include/haproxy/tools.h b/include/haproxy/tools.h index 46fef67c5..ae900adfb 100644 --- a/include/haproxy/tools.h +++ b/include/haproxy/tools.h @@ -1055,4 +1055,20 @@ static inline int32_t ha_random() return ha_random32() >> 1; } +extern THREAD_LOCAL unsigned int statistical_prng_state; + +/* Xorshift RNGs from http://www.jstatsoft.org/v08/i14/paper. + * This has a (2^32)-1 period, only zero is never returned. + */ +static inline unsigned int statistical_prng() +{ + unsigned int x = statistical_prng_state; + + x ^= x << 13; + x ^= x >> 17; + x ^= x << 5; + return statistical_prng_state = x; +} + + #endif /* _HAPROXY_TOOLS_H */ diff --git a/src/debug.c b/src/debug.c index 209199ab0..914c80de8 100644 --- a/src/debug.c +++ b/src/debug.c @@ -42,16 +42,6 @@ volatile unsigned long threads_to_dump = 0; unsigned int debug_commands_issued = 0; -/* Xorshift RNGs from http://www.jstatsoft.org/v08/i14/paper */ -static THREAD_LOCAL unsigned int y = 2463534242U; -static unsigned int debug_prng() -{ - y ^= y << 13; - y ^= y >> 17; - y ^= y << 5; - return y; -} - /* dumps a backtrace of the current thread that is appended to buffer . * Lines are prefixed with the string which may be empty (used for * indenting). It is recommended to use this at a function's tail so that @@ -748,7 +738,7 @@ static struct task *debug_task_handler(struct task *t, void *ctx, unsigned short t->expire = tick_add(now_ms, inter); /* half of the calls will wake up another entry */ - rnd = debug_prng(); + rnd = statistical_prng(); if (rnd & 1) { rnd >>= 1; rnd %= tctx[0]; @@ -770,7 +760,7 @@ static struct task *debug_tasklet_handler(struct task *t, void *ctx, unsigned sh /* wake up two random entries */ for (i = 0; i < 2; i++) { - rnd = debug_prng() % tctx[0]; + rnd = statistical_prng() % tctx[0]; rnd = tctx[rnd + 2]; if (rnd & 1) diff --git a/src/tools.c b/src/tools.c index 1c43354bd..d3ee4265b 100644 --- a/src/tools.c +++ b/src/tools.c @@ -78,6 +78,12 @@ THREAD_LOCAL int itoa_idx = 0; /* index of next itoa_str to use */ THREAD_LOCAL char quoted_str[NB_QSTR][QSTR_SIZE + 1]; THREAD_LOCAL int quoted_idx = 0; +/* thread-local PRNG state. It's modified to start from a different sequence + * on all threads upon startup. It must not be used or anything beyond getting + * statistical values as it's 100% predictable. + */ +THREAD_LOCAL unsigned int statistical_prng_state = 2463534242U; + /* * unsigned long long ASCII representation * @@ -5363,6 +5369,16 @@ size_t sanitize_for_printing(char *line, size_t pos, size_t width) return pos - shift; } +static int init_tools_per_thread() +{ + /* Let's make each thread start from a different position */ + statistical_prng_state += tid * MAX_THREADS; + if (!statistical_prng_state) + statistical_prng_state++; + return 1; +} +REGISTER_PER_THREAD_INIT(init_tools_per_thread); + /* * Local variables: * c-indent-level: 8