Fix pthread.pthread_barrier_smoke test.

pthread_barrier_smoke test uses WaitUntilThreadSleep() to wait until
BarrierTestHelper threads sleep in pthread_barrier_wait(). But this
is flaky as there a two futex_wait places in pthread_barrier_wait.
This patch modifies this test to avoid using WaitUntilThreadSleep().

Bug: 27780937
Change-Id: I4c36b82cce9345d5088f8854b289dc5bf7a08e8c
diff --git a/tests/pthread_test.cpp b/tests/pthread_test.cpp
index aab78ad..0313171 100755
--- a/tests/pthread_test.cpp
+++ b/tests/pthread_test.cpp
@@ -1818,55 +1818,82 @@
   ASSERT_EQ(0, pthread_barrierattr_destroy(&attr));
 }
 
-struct BarrierTestHelperArg {
-  std::atomic<pid_t> tid;
-  pthread_barrier_t* barrier;
+struct BarrierTestHelperData {
+  size_t thread_count;
+  pthread_barrier_t barrier;
+  std::atomic<int> finished_mask;
+  std::atomic<int> serial_thread_count;
   size_t iteration_count;
+  std::atomic<size_t> finished_iteration_count;
+
+  BarrierTestHelperData(size_t thread_count, size_t iteration_count)
+      : thread_count(thread_count), finished_mask(0), serial_thread_count(0),
+        iteration_count(iteration_count), finished_iteration_count(0) {
+  }
+};
+
+struct BarrierTestHelperArg {
+  int id;
+  BarrierTestHelperData* data;
 };
 
 static void BarrierTestHelper(BarrierTestHelperArg* arg) {
-  arg->tid = gettid();
-  for (size_t i = 0; i < arg->iteration_count; ++i) {
-    ASSERT_EQ(0, pthread_barrier_wait(arg->barrier));
+  for (size_t i = 0; i < arg->data->iteration_count; ++i) {
+    int result = pthread_barrier_wait(&arg->data->barrier);
+    if (result == PTHREAD_BARRIER_SERIAL_THREAD) {
+      arg->data->serial_thread_count++;
+    } else {
+      ASSERT_EQ(0, result);
+    }
+    arg->data->finished_mask |= (1 << arg->id);
+    if (arg->data->finished_mask == ((1 << arg->data->thread_count) - 1)) {
+      ASSERT_EQ(1, arg->data->serial_thread_count);
+      arg->data->finished_iteration_count++;
+      arg->data->finished_mask = 0;
+      arg->data->serial_thread_count = 0;
+    }
   }
 }
 
 TEST(pthread, pthread_barrier_smoke) {
   const size_t BARRIER_ITERATION_COUNT = 10;
   const size_t BARRIER_THREAD_COUNT = 10;
-  pthread_barrier_t barrier;
-  ASSERT_EQ(0, pthread_barrier_init(&barrier, nullptr, BARRIER_THREAD_COUNT + 1));
-  std::vector<pthread_t> threads(BARRIER_THREAD_COUNT);
+  BarrierTestHelperData data(BARRIER_THREAD_COUNT, BARRIER_ITERATION_COUNT);
+  ASSERT_EQ(0, pthread_barrier_init(&data.barrier, nullptr, data.thread_count));
+  std::vector<pthread_t> threads(data.thread_count);
   std::vector<BarrierTestHelperArg> args(threads.size());
   for (size_t i = 0; i < threads.size(); ++i) {
-    args[i].tid = 0;
-    args[i].barrier = &barrier;
-    args[i].iteration_count = BARRIER_ITERATION_COUNT;
+    args[i].id = i;
+    args[i].data = &data;
     ASSERT_EQ(0, pthread_create(&threads[i], nullptr,
                                 reinterpret_cast<void* (*)(void*)>(BarrierTestHelper), &args[i]));
   }
-  for (size_t iteration = 0; iteration < BARRIER_ITERATION_COUNT; ++iteration) {
-    for (size_t i = 0; i < threads.size(); ++i) {
-      WaitUntilThreadSleep(args[i].tid);
-    }
-    ASSERT_EQ(PTHREAD_BARRIER_SERIAL_THREAD, pthread_barrier_wait(&barrier));
-  }
   for (size_t i = 0; i < threads.size(); ++i) {
     ASSERT_EQ(0, pthread_join(threads[i], nullptr));
   }
-  ASSERT_EQ(0, pthread_barrier_destroy(&barrier));
+  ASSERT_EQ(data.iteration_count, data.finished_iteration_count);
+  ASSERT_EQ(0, pthread_barrier_destroy(&data.barrier));
+}
+
+struct BarrierDestroyTestArg {
+  std::atomic<int> tid;
+  pthread_barrier_t* barrier;
+};
+
+static void BarrierDestroyTestHelper(BarrierDestroyTestArg* arg) {
+  arg->tid = gettid();
+  ASSERT_EQ(0, pthread_barrier_wait(arg->barrier));
 }
 
 TEST(pthread, pthread_barrier_destroy) {
   pthread_barrier_t barrier;
   ASSERT_EQ(0, pthread_barrier_init(&barrier, nullptr, 2));
   pthread_t thread;
-  BarrierTestHelperArg arg;
+  BarrierDestroyTestArg arg;
   arg.tid = 0;
   arg.barrier = &barrier;
-  arg.iteration_count = 1;
   ASSERT_EQ(0, pthread_create(&thread, nullptr,
-                              reinterpret_cast<void* (*)(void*)>(BarrierTestHelper), &arg));
+                              reinterpret_cast<void* (*)(void*)>(BarrierDestroyTestHelper), &arg));
   WaitUntilThreadSleep(arg.tid);
   ASSERT_EQ(EBUSY, pthread_barrier_destroy(&barrier));
   ASSERT_EQ(PTHREAD_BARRIER_SERIAL_THREAD, pthread_barrier_wait(&barrier));