[waffle] [PATCH v2 3/3] wcore_error_unittest: Fix race condition leading to forever loop

Pauli Nieminen pauli.nieminen at linux.intel.com
Wed May 30 08:52:10 PDT 2012


Reading non-volatile value in loop without function calls allows C
compiler to generate forever loop without checking the memory value. To
avoid the problem locking or atomic operations could be used.

But there is better solution of using pthread_barrier_t that test case
was trying to simulate with mutex and conditional. Barrier promises that
all threads are released when requested number of threads are blocked in
pthread_barrier_wait.

Signed-off-by: Pauli Nieminen <pauli.nieminen at linux.intel.com>
---
 tests/unittests/waffle/core/wcore_error_unittest.c |   37 ++++----------------
 1 file changed, 7 insertions(+), 30 deletions(-)

diff --git a/tests/unittests/waffle/core/wcore_error_unittest.c b/tests/unittests/waffle/core/wcore_error_unittest.c
index 2a1f5c1..0098450 100644
--- a/tests/unittests/waffle/core/wcore_error_unittest.c
+++ b/tests/unittests/waffle/core/wcore_error_unittest.c
@@ -131,13 +131,7 @@ struct thread_arg {
     int thread_id;
 
     /// Protects `num_threads_waiting` and `cond`.
-    pthread_mutex_t *mutex;
-
-    /// Satisfied when `num_threads_waiting == TOTAL_THREADS`.
-    pthread_cond_t *cond;
-
-    /// Number of threads waiting on `cond`.
-    int *num_threads_waiting;
+    pthread_barrier_t *barrier;
 };
 
 /// The start routine given to threads in test wcore_error.thread_local.
@@ -159,13 +153,7 @@ thread_start(struct thread_arg *a)
     // Each thread sets its error code.
     wcore_error(error_code);
 
-    // Wait for all threads to set their error codes, thus giving
-    // the threads opportunity to clobber each other's codes.
-    pthread_mutex_lock(a->mutex); {
-        *a->num_threads_waiting += 1;
-        pthread_cond_wait(a->cond, a->mutex);
-        pthread_mutex_unlock(a->mutex);
-    }
+    pthread_barrier_wait(a->barrier);
 
     // Verify that the threads did not clobber each other's
     // error codes.
@@ -177,23 +165,18 @@ thread_start(struct thread_arg *a)
 // Test that threads do not clobber each other's error codes.
 TEST(wcore_error, thread_local)
 {
-    pthread_mutex_t mutex;
-    pthread_cond_t cond;
-    int num_threads_waiting = 0;
+    pthread_barrier_t barrier;
 
     pthread_t threads[NUM_THREADS];
     struct thread_arg thread_args[NUM_THREADS];
     bool exit_codes[NUM_THREADS];
 
-    pthread_mutex_init(&mutex, NULL);
-    pthread_cond_init(&cond, NULL);
+    pthread_barrier_init(&barrier, NULL, NUM_THREADS + 1);
 
     for (intptr_t i = 0; i < NUM_THREADS; ++i) {
         struct thread_arg *a = &thread_args[i];
         a->thread_id = i;
-        a->mutex = &mutex;
-        a->cond = &cond;
-        a->num_threads_waiting = &num_threads_waiting;
+        a->barrier = &barrier;
 
         pthread_create(&threads[i], NULL,
                       (void* (*)(void*)) thread_start,
@@ -202,20 +185,14 @@ TEST(wcore_error, thread_local)
 
     // Wait for all threads to set their error codes, thus giving
     // the threads opportunity to clobber each other's codes.
-    while (num_threads_waiting < NUM_THREADS)
-        ;;
-    pthread_mutex_lock(&mutex); {
-        pthread_cond_broadcast(&cond);
-        pthread_mutex_unlock(&mutex);
-    }
+    pthread_barrier_wait(&barrier);
 
     for (int i = 0; i < NUM_THREADS; ++i) {
         pthread_join(threads[i], (void**) &exit_codes[i]);
         EXPECT_TRUE(exit_codes[i] == true);
     }
 
-    pthread_cond_destroy(&cond);
-    pthread_mutex_destroy(&mutex);
+    pthread_barrier_destroy(&barrier);
 }
 
 void
-- 
1.7.9.5



More information about the waffle mailing list