ThreadPool unittest: reimplement concurrency test, deterministically this time.
authorMehdi Amini <mehdi.amini@apple.com>
Sat, 19 Dec 2015 05:12:07 +0000 (05:12 +0000)
committerMehdi Amini <mehdi.amini@apple.com>
Sat, 19 Dec 2015 05:12:07 +0000 (05:12 +0000)
Follow-up to r256056.

From: Mehdi Amini <mehdi.amini@apple.com>

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@256087 91177308-0d34-0410-b5e6-96231b3b80d8

unittests/Support/ThreadPool.cpp

index b0e33c1..ca55237 100644 (file)
@@ -54,6 +54,18 @@ protected:
     UnsupportedArchs.push_back(Triple::ppc64le);
     UnsupportedArchs.push_back(Triple::ppc64);
   }
     UnsupportedArchs.push_back(Triple::ppc64le);
     UnsupportedArchs.push_back(Triple::ppc64);
   }
+
+  /// Make sure this thread not progress faster than the main thread.
+  void waitForMainThread() {
+    while (!MainThreadReady) {
+      std::unique_lock<std::mutex> LockGuard(WaitMainThreadMutex);
+      WaitMainThread.wait(LockGuard, [&] { return MainThreadReady; });
+    }
+  }
+  std::condition_variable WaitMainThread;
+  std::mutex WaitMainThreadMutex;
+  bool MainThreadReady;
+
 };
 
 #define CHECK_UNSUPPORTED() \
 };
 
 #define CHECK_UNSUPPORTED() \
@@ -68,12 +80,17 @@ TEST_F(ThreadPoolTest, AsyncBarrier) {
 
   std::atomic_int checked_in{0};
 
 
   std::atomic_int checked_in{0};
 
+  MainThreadReady = false;
   ThreadPool Pool;
   for (size_t i = 0; i < 5; ++i) {
   ThreadPool Pool;
   for (size_t i = 0; i < 5; ++i) {
-    Pool.async([&checked_in, i] {
+    Pool.async([this, &checked_in, i] {
+      waitForMainThread();
       ++checked_in;
     });
   }
       ++checked_in;
     });
   }
+  ASSERT_EQ(0, checked_in);
+  MainThreadReady = true;
+  WaitMainThread.notify_all();
   Pool.wait();
   ASSERT_EQ(5, checked_in);
 }
   Pool.wait();
   ASSERT_EQ(5, checked_in);
 }
@@ -97,10 +114,15 @@ TEST_F(ThreadPoolTest, Async) {
   CHECK_UNSUPPORTED();
   ThreadPool Pool;
   std::atomic_int i{0};
   CHECK_UNSUPPORTED();
   ThreadPool Pool;
   std::atomic_int i{0};
-  Pool.async([&i] {
+  MainThreadReady = false;
+  Pool.async([this, &i] {
+    waitForMainThread();
     ++i;
   });
   Pool.async([&i] { ++i; });
     ++i;
   });
   Pool.async([&i] { ++i; });
+  ASSERT_NE(2, i.load());
+  MainThreadReady = true;
+  WaitMainThread.notify_all();
   Pool.wait();
   ASSERT_EQ(2, i.load());
 }
   Pool.wait();
   ASSERT_EQ(2, i.load());
 }
@@ -109,11 +131,16 @@ TEST_F(ThreadPoolTest, GetFuture) {
   CHECK_UNSUPPORTED();
   ThreadPool Pool;
   std::atomic_int i{0};
   CHECK_UNSUPPORTED();
   ThreadPool Pool;
   std::atomic_int i{0};
-  Pool.async([&i] {
+  MainThreadReady = false;
+  Pool.async([this, &i] {
+    waitForMainThread();
     ++i;
   });
   // Force the future using get()
   Pool.async([&i] { ++i; }).get();
     ++i;
   });
   // Force the future using get()
   Pool.async([&i] { ++i; }).get();
+  ASSERT_NE(2, i.load());
+  MainThreadReady = true;
+  WaitMainThread.notify_all();
   Pool.wait();
   ASSERT_EQ(2, i.load());
 }
   Pool.wait();
   ASSERT_EQ(2, i.load());
 }
@@ -122,14 +149,18 @@ TEST_F(ThreadPoolTest, PoolDestruction) {
   CHECK_UNSUPPORTED();
   // Test that we are waiting on destruction
   std::atomic_int checked_in{0};
   CHECK_UNSUPPORTED();
   // Test that we are waiting on destruction
   std::atomic_int checked_in{0};
-
   {
   {
+    MainThreadReady = false;
     ThreadPool Pool;
     for (size_t i = 0; i < 5; ++i) {
     ThreadPool Pool;
     for (size_t i = 0; i < 5; ++i) {
-      Pool.async([&checked_in, i] {
+      Pool.async([this, &checked_in, i] {
+        waitForMainThread();
         ++checked_in;
       });
     }
         ++checked_in;
       });
     }
+    ASSERT_EQ(0, checked_in);
+    MainThreadReady = true;
+    WaitMainThread.notify_all();
   }
   ASSERT_EQ(5, checked_in);
 }
   }
   ASSERT_EQ(5, checked_in);
 }