[PATCH v3 01/14] test: add pause to synchronization spinloops

Stephen Hemminger
2026-01-22T00:54:10Z

The atomic and thread tests use tight spinloops to synchronize.
These spinloops lack rte_pause() which causes problems on high core
count systems, particularly AMD Zen architectures where:

- Tight spinloops without pause can starve SMT sibling threads
- Memory ordering and store-buffer forwarding behave differently
- Higher core counts amplify timing windows for race conditions

This manifests as sporadic test failures on systems with 32+ cores
that don't reproduce on smaller core count systems.

Add rte_pause() to all seven synchronization spinloops to allow
proper CPU resource sharing and improve memory ordering behavior.

Fixes: af75078fece3 ("first public release")
Cc: stable@dpdk.org

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
Acked-by: Bruce Richardson <bruce.richardson@intel.com>
---
app/test/test_atomic.c | 15 ++++++++-------
app/test/test_threads.c | 17 +++++++++--------
2 files changed, 17 insertions(+), 15 deletions(-)

diff --git a/app/test/test_atomic.c b/app/test/test_atomic.c
index 8160a33e0e..b1a0d40ece 100644
--- a/app/test/test_atomic.c
+++ b/app/test/test_atomic.c
@@ -15,6 +15,7 @@
#include <rte_atomic.h>
#include <rte_eal.h>
#include <rte_lcore.h>
+#include <rte_pause.h>
#include <rte_random.h>
#include <rte_hash_crc.h>

@@ -114,7 +115,7 @@ test_atomic_usual(__rte_unused void *arg)
unsigned i;

while (rte_atomic32_read(&synchro) == 0)
- ;
+ rte_pause();

for (i = 0; i < N; i++)
rte_atomic16_inc(&a16);
@@ -150,7 +151,7 @@ static int
test_atomic_tas(__rte_unused void *arg)
{
while (rte_atomic32_read(&synchro) == 0)
- ;
+ rte_pause();

if (rte_atomic16_test_and_set(&a16))
rte_atomic64_inc(&count);
@@ -171,7 +172,7 @@ test_atomic_addsub_and_return(__rte_unused void *arg)
unsigned i;

while (rte_atomic32_read(&synchro) == 0)
- ;
+ rte_pause();

for (i = 0; i < N; i++) {
tmp16 = rte_atomic16_add_return(&a16, 1);
@@ -210,7 +211,7 @@ static int
test_atomic_inc_and_test(__rte_unused void *arg)
{
while (rte_atomic32_read(&synchro) == 0)
- ;
+ rte_pause();

if (rte_atomic16_inc_and_test(&a16)) {
rte_atomic64_inc(&count);
@@ -237,7 +238,7 @@ static int
test_atomic_dec_and_test(__rte_unused void *arg)
{
while (rte_atomic32_read(&synchro) == 0)
- ;
+ rte_pause();

if (rte_atomic16_dec_and_test(&a16))
rte_atomic64_inc(&count);
@@ -269,7 +270,7 @@ test_atomic128_cmp_exchange(__rte_unused void *arg)
unsigned int i;

while (rte_atomic32_read(&synchro) == 0)
- ;
+ rte_pause();

expected = count128;

@@ -407,7 +408,7 @@ test_atomic_exchange(__rte_unused void *arg)

/* Wait until all of the other threads have been dispatched */
while (rte_atomic32_read(&synchro) == 0)
- ;
+ rte_pause();

/*
* Let the battle begin! Every thread attempts to steal the current
diff --git a/app/test/test_threads.c b/app/test/test_threads.c
index 5cd8bd4559..e2700b4a92 100644
--- a/app/test/test_threads.c
+++ b/app/test/test_threads.c
@@ -7,6 +7,7 @@
#include <rte_thread.h>
#include <rte_debug.h>
#include <rte_stdatomic.h>
+#include <rte_pause.h>

#include "test.h"

@@ -23,7 +24,7 @@ thread_main(void *arg)
rte_atomic_store_explicit(&thread_id_ready, 1, rte_memory_order_release);

while (rte_atomic_load_explicit(&thread_id_ready, rte_memory_order_acquire) == 1)
- ;
+ rte_pause();

return 0;
}
@@ -39,7 +40,7 @@ test_thread_create_join(void)
"Failed to create thread.");

while (rte_atomic_load_explicit(&thread_id_ready, rte_memory_order_acquire) == 0)
- ;
+ rte_pause();

RTE_TEST_ASSERT(rte_thread_equal(thread_id, thread_main_id) != 0,
"Unexpected thread id.");
@@ -63,7 +64,7 @@ test_thread_create_detach(void)
&thread_main_id) == 0, "Failed to create thread.");

while (rte_atomic_load_explicit(&thread_id_ready, rte_memory_order_acquire) == 0)
- ;
+ rte_pause();

RTE_TEST_ASSERT(rte_thread_equal(thread_id, thread_main_id) != 0,
"Unexpected thread id.");
@@ -87,7 +88,7 @@ test_thread_priority(void)
"Failed to create thread");

while (rte_atomic_load_explicit(&thread_id_ready, rte_memory_order_acquire) == 0)
- ;
+ rte_pause();

priority = RTE_THREAD_PRIORITY_NORMAL;
RTE_TEST_ASSERT(rte_thread_set_priority(thread_id, priority) == 0,
@@ -139,7 +140,7 @@ test_thread_affinity(void)
"Failed to create thread");

while (rte_atomic_load_explicit(&thread_id_ready, rte_memory_order_acquire) == 0)
- ;
+ rte_pause();

RTE_TEST_ASSERT(rte_thread_get_affinity_by_id(thread_id, &cpuset0) == 0,
"Failed to get thread affinity");
@@ -192,7 +193,7 @@ test_thread_attributes_affinity(void)
"Failed to create attributes affinity thread.");

while (rte_atomic_load_explicit(&thread_id_ready, rte_memory_order_acquire) == 0)
- ;
+ rte_pause();

RTE_TEST_ASSERT(rte_thread_get_affinity_by_id(thread_id, &cpuset1) == 0,
"Failed to get attributes thread affinity");
@@ -221,7 +222,7 @@ test_thread_attributes_priority(void)
"Failed to create attributes priority thread.");

while (rte_atomic_load_explicit(&thread_id_ready, rte_memory_order_acquire) == 0)
- ;
+ rte_pause();

RTE_TEST_ASSERT(rte_thread_get_priority(thread_id, &priority) == 0,
"Failed to get thread priority");
@@ -245,7 +246,7 @@ test_thread_control_create_join(void)
"Failed to create thread.");

while (rte_atomic_load_explicit(&thread_id_ready, rte_memory_order_acquire) == 0)
- ;
+ rte_pause();

RTE_TEST_ASSERT(rte_thread_equal(thread_id, thread_main_id) != 0,
"Unexpected thread id.");
--
2.51.0