Skip to contentSkip to conversation

random: initialize the random state for non-eal lcores

PATCH Superseded Stephen Hemminger 4 participants 16 messages Sep 6, 2023 – Oct 4, 2023

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 random: initialize the random state for non-eal lcores

The per-lcore PRNG was not initializing the rand_state of all the lcores. Any usage of rte_random by a non-EAL lcore would use rand_states[RTE_MAX_LCORE] which was never initialized.

Fix by using RTE_DIM() which will get all lcores.

Fixes 3f002f069612 ("eal: replace libc-based random generation with LFSR")
---
 drivers/common/mlx5/linux/mlx5_common_os.c | 2 +-
 lib/eal/common/rte_random.c                | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)
drivers/common/mlx5/linux/mlx5_common_os.c +1 -1
index 2ebb8ac8b6e5..7260c1a19fd3 100644
@@ -266,7 +266,7 @@ mlx5_glue_path(char *buf, size_t size)
 		goto error;
 	return buf;
 error:
-	RTE_LOG(ERR, PMD, "unable to append \"-glue\" to last component of"
+	DRV_LOG(ERR, "unable to append \"-glue\" to last component of"
 		" RTE_EAL_PMD_PATH (\"" RTE_EAL_PMD_PATH "\"), please"
 		" re-configure DPDK");
 	return NULL;
lib/eal/common/rte_random.c +1 -1
index 53636331a27b..812e5b4757b5 100644
@@ -84,7 +84,7 @@ rte_srand(uint64_t seed)
 	unsigned int lcore_id;
 
 	/* add lcore_id to seed to avoid having the same sequence */
-	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++)
+	for (lcore_id = 0; lcore_id < RTE_DIM(rand_states); lcore_id++)
 		__rte_srand_lfsr258(seed + lcore_id, &rand_states[lcore_id]);
 }
 
Signature · 1 line
2.39.2
Acked-by on v1 1/1
#1 lore raw
Quoted 7 lines

From: Stephen Hemminger [mailto:[email protected]]
Sent: Wednesday, 6 September 2023 17.53

The per-lcore PRNG was not initializing the rand_state of all the lcores. Any usage of rte_random by a non-EAL lcore would use rand_states[RTE_MAX_LCORE] which was never initialized.

Quoted 7 lines

Fix by using RTE_DIM() which will get all lcores.

Fixes 3f002f069612 ("eal: replace libc-based random generation with LFSR")
---
 drivers/common/mlx5/linux/mlx5_common_os.c | 2 +-

With the unrelated MLX5 stuff removed,

Quoted 2 lines
 lib/eal/common/rte_random.c                | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)
#2 lore raw
In reply to Stephen Hemminger

drivers/common/mlx5/linux/mlx5_common_os.c mlx5_glue_path(char *buf, size_t size) · line 272

Quoted 13 lines · On Wed, 6 Sep 2023 08:53:02 -0700 Stephen Hemminger…
drivers/common/mlx5/linux/mlx5_common_os.c +1 -1
index 2ebb8ac8b6e5..7260c1a19fd3 100644
@@ -266,7 +266,7 @@ mlx5_glue_path(char *buf, size_t size)
 		goto error;
 	return buf;
 error:
-	RTE_LOG(ERR, PMD, "unable to append \"-glue\" to last component of"
+	DRV_LOG(ERR, "unable to append \"-glue\" to last component of"
 		" RTE_EAL_PMD_PATH (\"" RTE_EAL_PMD_PATH "\"), please"
 		" re-configure DPDK");
 	return NULL;

Not sure how that got in, ignore it.

#3 lore raw

v2 cover fixes to rte_random for non-EAL threads

In reply to Stephen Hemminger

While examining the code for rte_random, noticed a couple of existing bugs around use of rte_rand() by non-EAL threads

Stephen Hemminger (2):
random: initialize the random state for non-EAL threads
random: make rte_rand() thread safe for non-EAL threads

 lib/eal/common/rte_random.c | 56 ++++++++++++++++++++++++-------------
 1 file changed, 37 insertions(+), 19 deletions(-)
Signature · 1 line
2.39.2
#4 lore raw

PATCH v2 1/2 random: initialize the random state for non-EAL threads

The per-lcore PRNG was not initializing the rand_state of all the lcores. Any usage of rte_random by a non-EAL lcore would use rand_states[RTE_MAX_LCORE] which was never initialized.

Fix by using RTE_DIM() which will get all lcores.

Fixes 3f002f069612 ("eal: replace libc-based random generation with LFSR")
---
 lib/eal/common/rte_random.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
lib/eal/common/rte_random.c +1 -1
index 53636331a27b..812e5b4757b5 100644
@@ -84,7 +84,7 @@ rte_srand(uint64_t seed)
 	unsigned int lcore_id;
 
 	/* add lcore_id to seed to avoid having the same sequence */
-	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++)
+	for (lcore_id = 0; lcore_id < RTE_DIM(rand_states); lcore_id++)
 		__rte_srand_lfsr258(seed + lcore_id, &rand_states[lcore_id]);
 }
 
Signature · 1 line
2.39.2
Reviewed-by on v2 1/2
#5 lore raw

RE: [PATCH v2 1/2] random: initialize the random state for non-EAL threads

Quoted 31 lines

From: Stephen Hemminger [mailto:[email protected]]
Sent: Thursday, 7 September 2023 17.25

The per-lcore PRNG was not initializing the rand_state of all the lcores. Any usage of rte_random by a non-EAL lcore would use rand_states[RTE_MAX_LCORE] which was never initialized.

Fix by using RTE_DIM() which will get all lcores.

Fixes 3f002f069612 ("eal: replace libc-based random generation with LFSR")
---
 lib/eal/common/rte_random.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
lib/eal/common/rte_random.c +1 -2
index 53636331a27b..812e5b4757b5 100644
@@ -84,7 +84,7 @@ rte_srand(uint64_t seed)
 	unsigned int lcore_id;
 
 	/* add lcore_id to seed to avoid having the same sequence */
-	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++)
+	for (lcore_id = 0; lcore_id < RTE_DIM(rand_states); lcore_id++)
 		__rte_srand_lfsr258(seed + lcore_id, &rand_states[lcore_id]);
 }
 
--
Quoted 1 line

2.39.2

Now also...

Acked-by on v2 1/2
#6 lore raw

Re: [PATCH v2 1/2] random: initialize the random state for non-EAL threads

In reply to Stephen Hemminger
Quoted 2 lines · Stephen Hemminger

The per-lcore PRNG was not initializing the rand_state of all the lcores. Any usage of rte_random by a non-EAL lcore would

"/../ by an unregistered non-EAL thread /../"

Quoted 17 lines

use rand_states[RTE_MAX_LCORE] which was never initialized.

Fix by using RTE_DIM() which will get all lcores.

Fixes 3f002f069612 ("eal: replace libc-based random generation with LFSR")
---
  lib/eal/common/rte_random.c | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)
lib/eal/common/rte_random.c +0 -0
index 53636331a27b..812e5b4757b5 100644

lib/eal/common/rte_random.c rte_srand(uint64_t seed) · line 90

Quoted 8 lines
lib/eal/common/rte_random.c +1 -1
@@ -84,7 +84,7 @@ rte_srand(uint64_t seed)
  	unsigned int lcore_id;
 
  	/* add lcore_id to seed to avoid having the same sequence */
-	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++)
+	for (lcore_id = 0; lcore_id < RTE_DIM(rand_states); lcore_id++)
  		__rte_srand_lfsr258(seed + lcore_id, &rand_states[lcore_id]);
  }
 

With the above-mentioned commit message rewording:

#7 lore raw

Re: [PATCH v2 1/2] random: initialize the random state for non-EAL threads

Quoted 7 lines · On Mon, 2 Oct 2023 14:27:48 +0200 Mattias Rönnblom <[email protected]>…
Quoted 2 lines · Stephen Hemminger

The per-lcore PRNG was not initializing the rand_state of all the lcores. Any usage of rte_random by a non-EAL lcore would

"/../ by an unregistered non-EAL thread /../"

Quoted 1 line

use rand_states[RTE_MAX_LCORE] which was never initialized.

Sure, that is a more precise wording.

#8 lore raw

Re: [PATCH v2 1/2] random: initialize the random state for non-EAL threads

In reply to Mattias Rönnblom
Quoted 35 lines · Mattias Rönnblom
Quoted 2 lines · Stephen Hemminger

The per-lcore PRNG was not initializing the rand_state of all the lcores. Any usage of rte_random by a non-EAL lcore would

"/../ by an unregistered non-EAL thread /../"

Quoted 17 lines

use rand_states[RTE_MAX_LCORE] which was never initialized.

Fix by using RTE_DIM() which will get all lcores.

Fixes 3f002f069612 ("eal: replace libc-based random generation with LFSR")
---
  lib/eal/common/rte_random.c | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)
lib/eal/common/rte_random.c +0 -0
index 53636331a27b..812e5b4757b5 100644

lib/eal/common/rte_random.c rte_srand(uint64_t seed) · line 90

Quoted 8 lines
lib/eal/common/rte_random.c +1 -1
@@ -84,7 +84,7 @@ rte_srand(uint64_t seed)
      unsigned int lcore_id;
 
      /* add lcore_id to seed to avoid having the same sequence */
-     for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++)
+     for (lcore_id = 0; lcore_id < RTE_DIM(rand_states); lcore_id++)
              __rte_srand_lfsr258(seed + lcore_id, &rand_states[lcore_id]);
  }
 

With the above-mentioned commit message rewording:

Quoted 2 lines

Applied this patch.
The second patch is marked as rejected in pw, in favor of a followup doc patch.

Thanks.

Signature · 1 line
David Marchand
#9 lore raw

PATCH v2 2/2 random: make rte_rand() thread safe for non-EAL threads

In reply to Stephen Hemminger

Add missing locking so that if two non-EAL threads call rte_rand() they will not corrupt the per-thread state.

Fixes 3f002f069612 ("eal: replace libc-based random generation with LFSR")
---
 lib/eal/common/rte_random.c | 54 ++++++++++++++++++++++++-------------
 1 file changed, 36 insertions(+), 18 deletions(-)
lib/eal/common/rte_random.c +36 -18
index 812e5b4757b5..02b6b6b97bc0 100644
@@ -11,6 +11,7 @@
 #include <rte_branch_prediction.h>
 #include <rte_cycles.h>
 #include <rte_lcore.h>
+#include <rte_spinlock.h>
 #include <rte_random.h>
 
 struct rte_rand_state {
@@ -21,6 +22,9 @@ struct rte_rand_state {
 	uint64_t z5;
 } __rte_cache_aligned;
 
+/* Used for thread safety for non EAL threads. */
+static rte_spinlock_t rte_rand_lock = RTE_SPINLOCK_INITIALIZER;
+
 /* One instance each for every lcore id-equipped thread, and one
  * additional instance to be shared by all others threads (i.e., all
  * unregistered non-EAL threads).
@@ -124,20 +128,32 @@ struct rte_rand_state *__rte_rand_get_state(void)
 	idx = rte_lcore_id();
 
 	/* last instance reserved for unregistered non-EAL threads */
-	if (unlikely(idx == LCORE_ID_ANY))
+	if (unlikely(idx == LCORE_ID_ANY)) {
 		idx = RTE_MAX_LCORE;
+		rte_spinlock_lock(&rte_rand_lock);
+	}
 
 	return &rand_states[idx];
 }
 
+static __rte_always_inline
+void __rte_rand_put_state(struct rte_rand_state *state)
+{
+	if (state == &rand_states[RTE_MAX_LCORE])
+		rte_spinlock_unlock(&rte_rand_lock);
+}
+
 uint64_t
 rte_rand(void)
 {
 	struct rte_rand_state *state;
+	uint64_t res;
 
 	state = __rte_rand_get_state();
+	res = __rte_rand_lfsr258(state);
+	__rte_rand_put_state(state);
 
-	return __rte_rand_lfsr258(state);
+	return res;
 }
 
 uint64_t
@@ -159,22 +175,24 @@ rte_rand_max(uint64_t upper_bound)
 	/* Handle power-of-2 upper_bound as a special case, since it
 	 * has no bias issues.
 	 */
-	if (unlikely(ones == 1))
-		return __rte_rand_lfsr258(state) & (upper_bound - 1);
-
-	/* The approach to avoiding bias is to create a mask that
-	 * stretches beyond the request value range, and up to the
-	 * next power-of-2. In case the masked generated random value
-	 * is equal to or greater than the upper bound, just discard
-	 * the value and generate a new one.
-	 */
-
-	leading_zeros = rte_clz64(upper_bound);
-	mask >>= leading_zeros;
-
-	do {
-		res = __rte_rand_lfsr258(state) & mask;
-	} while (unlikely(res >= upper_bound));
+	if (unlikely(ones == 1)) {
+		res = __rte_rand_lfsr258(state) & (upper_bound - 1);
+	} else {
+		/* The approach to avoiding bias is to create a mask that
+		 * stretches beyond the request value range, and up to the
+		 * next power-of-2. In case the masked generated random value
+		 * is equal to or greater than the upper bound, just discard
+		 * the value and generate a new one.
+		 */
+
+		leading_zeros = rte_clz64(upper_bound);
+		mask >>= leading_zeros;
+
+		do {
+			res = __rte_rand_lfsr258(state) & mask;
+		} while (unlikely(res >= upper_bound));
+	}
+	__rte_rand_put_state(state);
 
 	return res;
 }
Signature · 1 line
2.39.2
#10 lore raw

Re: [PATCH v2 2/2] random: make rte_rand() thread safe for non-EAL threads

lib/eal/common/rte_random.c struct rte_rand_state *__rte_rand_get_state(void) · line 144

Quoted 7 lines · On Thu, 7 Sep 2023 08:24:56 -0700 Stephen Hemminger…
lib/eal/common/rte_random.c +6 -0
+static __rte_always_inline
+void __rte_rand_put_state(struct rte_rand_state *state)
+{
+	if (state == &rand_states[RTE_MAX_LCORE])
+		rte_spinlock_unlock(&rte_rand_lock);
+}

Conditional locking like this make clang lock analyzer unhappy though.

#11 lore raw

Re: [PATCH v2 2/2] random: make rte_rand() thread safe for non-EAL threads

Quoted 5 lines · Stephen Hemminger
Quoted 1 line · On Thu, 7 Sep 2023 08:24:56 -0700 Stephen Hemminger…
Quoted 8 lines

Review

Quoted 6 lines
(quoted diff) +6 -0
+static __rte_always_inline
+void __rte_rand_put_state(struct rte_rand_state *state)
+{
+     if (state == &rand_states[RTE_MAX_LCORE])
+             rte_spinlock_unlock(&rte_rand_lock);
+}

Conditional locking like this make clang lock analyzer unhappy though.

Ugly, but some macro can do the job...

lib/eal/common/rte_random.c +15 -11
index 02b6b6b97b..3f2a4830fd 100644
@@ -128,20 +128,22 @@ struct rte_rand_state *__rte_rand_get_state(void)
        idx = rte_lcore_id();
 
        /* last instance reserved for unregistered non-EAL threads */
-       if (unlikely(idx == LCORE_ID_ANY)) {
+       if (unlikely(idx == LCORE_ID_ANY))
                idx = RTE_MAX_LCORE;
-               rte_spinlock_lock(&rte_rand_lock);
-       }
 
        return &rand_states[idx];
 }
 
-static __rte_always_inline
-void __rte_rand_put_state(struct rte_rand_state *state)
-{
-       if (state == &rand_states[RTE_MAX_LCORE])
-               rte_spinlock_unlock(&rte_rand_lock);
-}
+#define PROTECT_NON_EAL_THREADS(...) do { \
+       unsigned int idx = rte_lcore_id(); \
+       if (idx == LCORE_ID_ANY) { \
+               rte_spinlock_lock(&rte_rand_lock); \
+               __VA_ARGS__ \
+               rte_spinlock_unlock(&rte_rand_lock); \
+       } else { \
+               __VA_ARGS__ \
+       } \
+} while (0)
 
 uint64_t
 rte_rand(void)
@@ -149,9 +151,10 @@ rte_rand(void)
        struct rte_rand_state *state;
        uint64_t res;
 
+       PROTECT_NON_EAL_THREADS(
        state = __rte_rand_get_state();
        res = __rte_rand_lfsr258(state);
-       __rte_rand_put_state(state);
+       );
 
        return res;
 }
@@ -168,6 +171,7 @@ rte_rand_max(uint64_t upper_bound)
        if (unlikely(upper_bound < 2))
                return 0;
 
+       PROTECT_NON_EAL_THREADS(
        state = __rte_rand_get_state();
 
        ones = rte_popcount64(upper_bound);
@@ -192,7 +196,7 @@ rte_rand_max(uint64_t upper_bound)
                        res = __rte_rand_lfsr258(state) & mask;
                } while (unlikely(res >= upper_bound));
        }
-       __rte_rand_put_state(state);
+       );
 
        return res;
 }
Signature · 1 line
David Marchand
#12 lore raw

Re: [PATCH v2 2/2] random: make rte_rand() thread safe for non-EAL threads

In reply to Stephen Hemminger
Quoted 4 lines · Stephen Hemminger

Add missing locking so that if two non-EAL threads call rte_rand() they will not corrupt the per-thread state.

Fixes 3f002f069612 ("eal: replace libc-based random generation with LFSR")

The API documentation clearly states that no MT safety guarantees are given for unregistered non-EAL threads. So this patch doesn't fix anything.

rte_rand() is MT safe for *registered* non-EAL threads.

Quoted 28 lines
---
  lib/eal/common/rte_random.c | 54 ++++++++++++++++++++++++-------------
  1 file changed, 36 insertions(+), 18 deletions(-)
lib/eal/common/rte_random.c +4 -0
index 812e5b4757b5..02b6b6b97bc0 100644
@@ -11,6 +11,7 @@
  #include <rte_branch_prediction.h>
  #include <rte_cycles.h>
  #include <rte_lcore.h>
+#include <rte_spinlock.h>
  #include <rte_random.h>
 
  struct rte_rand_state {
@@ -21,6 +22,9 @@ struct rte_rand_state {
  	uint64_t z5;
  } __rte_cache_aligned;
 
+/* Used for thread safety for non EAL threads. */
+static rte_spinlock_t rte_rand_lock = RTE_SPINLOCK_INITIALIZER;
+
  /* One instance each for every lcore id-equipped thread, and one
   * additional instance to be shared by all others threads (i.e., all
   * unregistered non-EAL threads).

lib/eal/common/rte_random.c struct rte_rand_state *__rte_rand_get_state(void) · line 133

Quoted 7 lines
lib/eal/common/rte_random.c +2 -1
@@ -124,20 +128,32 @@ struct rte_rand_state *__rte_rand_get_state(void)
  	idx = rte_lcore_id();
 
  	/* last instance reserved for unregistered non-EAL threads */
-	if (unlikely(idx == LCORE_ID_ANY))
+	if (unlikely(idx == LCORE_ID_ANY)) {
  		idx = RTE_MAX_LCORE;
+		rte_spinlock_lock(&rte_rand_lock);

Non-EAL threads are very likely to be "regular" threads, which won't have a dedicated core all for themselves, and thus may well be preempted by the kernel. Such threads should not use spinlocks.

If a lock is to be added to achieve MT safety for parallel calls from unregistered non-EAL threads, it should be a regular mutex.

Quoted 68 lines
lib/eal/common/rte_random.c +30 -17
+	}
 
  	return &rand_states[idx];
  }
 
+static __rte_always_inline
+void __rte_rand_put_state(struct rte_rand_state *state)
+{
+	if (state == &rand_states[RTE_MAX_LCORE])
+		rte_spinlock_unlock(&rte_rand_lock);
+}
+
  uint64_t
  rte_rand(void)
  {
  	struct rte_rand_state *state;
+	uint64_t res;
 
  	state = __rte_rand_get_state();
+	res = __rte_rand_lfsr258(state);
+	__rte_rand_put_state(state);
 
-	return __rte_rand_lfsr258(state);
+	return res;
  }
 
  uint64_t
@@ -159,22 +175,24 @@ rte_rand_max(uint64_t upper_bound)
  	/* Handle power-of-2 upper_bound as a special case, since it
  	 * has no bias issues.
  	 */
-	if (unlikely(ones == 1))
-		return __rte_rand_lfsr258(state) & (upper_bound - 1);
-
-	/* The approach to avoiding bias is to create a mask that
-	 * stretches beyond the request value range, and up to the
-	 * next power-of-2. In case the masked generated random value
-	 * is equal to or greater than the upper bound, just discard
-	 * the value and generate a new one.
-	 */
-
-	leading_zeros = rte_clz64(upper_bound);
-	mask >>= leading_zeros;
-
-	do {
-		res = __rte_rand_lfsr258(state) & mask;
-	} while (unlikely(res >= upper_bound));
+	if (unlikely(ones == 1)) {
+		res = __rte_rand_lfsr258(state) & (upper_bound - 1);
+	} else {
+		/* The approach to avoiding bias is to create a mask that
+		 * stretches beyond the request value range, and up to the
+		 * next power-of-2. In case the masked generated random value
+		 * is equal to or greater than the upper bound, just discard
+		 * the value and generate a new one.
+		 */
+
+		leading_zeros = rte_clz64(upper_bound);
+		mask >>= leading_zeros;
+
+		do {
+			res = __rte_rand_lfsr258(state) & mask;
+		} while (unlikely(res >= upper_bound));
+	}
+	__rte_rand_put_state(state);
 
  	return res;
  }
#13 lore raw

Re: [PATCH v2 2/2] random: make rte_rand() thread safe for non-EAL threads

Quoted 10 lines · On Fri, 8 Sep 2023 22:48:54 +0200 Mattias Rönnblom <[email protected]>…
Quoted 4 lines · Stephen Hemminger

Add missing locking so that if two non-EAL threads call rte_rand() they will not corrupt the per-thread state.

Fixes 3f002f069612 ("eal: replace libc-based random generation with LFSR")

The API documentation clearly states that no MT safety guarantees are given for unregistered non-EAL threads. So this patch doesn't fix anything.

rte_rand() is MT safe for *registered* non-EAL threads.

Reading the documentation, it only guarantees safety if registered. We should add an otherwise clause rather than leaving case as undefined.

#14 lore raw

Re: [PATCH v2 2/2] random: make rte_rand() thread safe for non-EAL threads

Quoted 9 lines · Stephen Hemminger
Quoted 6 lines · On Fri, 8 Sep 2023 22:48:54 +0200 Mattias Rönnblom <[email protected]>…
Quoted 4 lines · Stephen Hemminger

Add missing locking so that if two non-EAL threads call rte_rand() they will not corrupt the per-thread state.

Fixes 3f002f069612 ("eal: replace libc-based random generation with LFSR")
Quoted 7 lines
Quoted 4 lines

The API documentation clearly states that no MT safety guarantees are given for unregistered non-EAL threads. So this patch doesn't fix anything.

rte_rand() is MT safe for *registered* non-EAL threads.

Reading the documentation, it only guarantees safety if registered. We should add an otherwise clause rather than leaving case as undefined.

I agree. It is MT safe in case only single unregistered non-EAL thread uses the API (or multiple such threads, provided they are properly [externally] serialized).

"If called from EAL threads, registered non-EAL threads or a *single* unregistered non-EAL thread, this function is thread-safe. Multiple unregistered non-EAL threads may not safely call this function in parallel (i.e., must use external serialization)."

A lot of words, unfortunately. Maybe this is better:

"rte_xxx() is MT safe, with the exception it may not be called from multiple *unregistered* non-EAL threads in parallel."

Then of course comes the issue that nobody knows what is an registered non-EAL thread is. DPDK threading terminology is a big mess, so no wonder.

#15 lore raw

Re: [PATCH v2 2/2] random: make rte_rand() thread safe for non-EAL threads

In reply to Stephen Hemminger
Quoted 5 lines · On Thu, 7 Sep 2023 08:24:56 -0700 Stephen Hemminger…

Add missing locking so that if two non-EAL threads call rte_rand() they will not corrupt the per-thread state.

Fixes 3f002f069612 ("eal: replace libc-based random generation with LFSR")

Drop this patch in favor of fixing the documentation and leaving any thread issues up to application to sort out.