Remove multi-poster support from Baton v2017.12.11.00
authorYedidya Feldblum <yfeldblum@fb.com>
Sun, 10 Dec 2017 20:39:24 +0000 (12:39 -0800)
committerFacebook Github Bot <facebook-github-bot@users.noreply.github.com>
Sun, 10 Dec 2017 20:50:22 +0000 (12:50 -0800)
Summary:
[Folly] Remove multi-poster support from `Baton`.

Code which needs multi-poster support may use `SaturatingSemaphore` instead.

Reviewed By: magedm

Differential Revision: D6529661

fbshipit-source-id: d9dc053ca984ef3a404e9361910b0044817d4905

folly/synchronization/Baton.h
folly/synchronization/test/BatonBenchmark.cpp
folly/synchronization/test/BatonTest.cpp
folly/synchronization/test/BatonTestHelpers.h

index ef87125..379f902 100644 (file)
 
 namespace folly {
 
-/// A Baton allows a thread to block once and be awoken. The single
-/// poster version (with SinglePoster == true) captures a single
-/// handoff, and during its lifecycle (from construction/reset to
-/// destruction/reset) a baton must either be post()ed and wait()ed
+/// A Baton allows a thread to block once and be awoken. Captures a
+/// single handoff, and during its lifecycle (from construction/reset
+/// to destruction/reset) a baton must either be post()ed and wait()ed
 /// exactly once each, or not at all.
 ///
-/// The multi-poster version (SinglePoster == false) allows multiple
-/// concurrent handoff attempts, the first of which completes the
-/// handoff and the rest if any are idempotent.
-///
 /// Baton includes no internal padding, and is only 4 bytes in size.
 /// Any alignment or padding to avoid false sharing is up to the user.
 ///
-/// This is basically a stripped-down semaphore that supports (only a
-/// single call to sem_post, when SinglePoster == true) and a single
-/// call to sem_wait.
+/// This is basically a stripped-down semaphore that supports only a
+/// single call to sem_post and a single call to sem_wait.
 ///
 /// The non-blocking version (Blocking == false) provides more speed
 /// by using only load acquire and store release operations in the
@@ -58,7 +52,6 @@ namespace folly {
 /// catch race conditions ahead of time.
 template <
     template <typename> class Atom = std::atomic,
-    bool SinglePoster = true, //  single vs multiple posters
     bool Blocking = true> // blocking vs spinning
 struct Baton {
   constexpr Baton() : state_(INIT) {}
@@ -130,65 +123,24 @@ struct Baton {
 
     /// Blocking versions
     ///
-    if (SinglePoster) {
-      /// Single poster version
-      ///
-      uint32_t before = state_.load(std::memory_order_acquire);
+    uint32_t before = state_.load(std::memory_order_acquire);
 
-      assert(before == INIT || before == WAITING || before == TIMED_OUT);
+    assert(before == INIT || before == WAITING || before == TIMED_OUT);
 
-      if (before == INIT &&
-          state_.compare_exchange_strong(before, EARLY_DELIVERY)) {
-        return;
-      }
-
-      assert(before == WAITING || before == TIMED_OUT);
+    if (before == INIT &&
+        state_.compare_exchange_strong(before, EARLY_DELIVERY)) {
+      return;
+    }
 
-      if (before == TIMED_OUT) {
-        return;
-      }
+    assert(before == WAITING || before == TIMED_OUT);
 
-      assert(before == WAITING);
-      state_.store(LATE_DELIVERY, std::memory_order_release);
-      state_.futexWake(1);
-    } else {
-      /// Multi-poster version
-      ///
-      while (true) {
-        uint32_t before = state_.load(std::memory_order_acquire);
-
-        if (before == INIT &&
-            state_.compare_exchange_strong(before, EARLY_DELIVERY)) {
-          return;
-        }
-
-        if (before == TIMED_OUT) {
-          return;
-        }
-
-        if (before == EARLY_DELIVERY || before == LATE_DELIVERY) {
-          // The reason for not simply returning (without the following
-          // atomic operation) is to avoid the following case:
-          //
-          //  T1:             T2:             T3:
-          //  local1.post();  local2.post();  global.wait();
-          //  global.post();  global.post();  local1.try_wait() == true;
-          //                                  local2.try_wait() == false;
-          //
-          if (state_.fetch_add(0) != before) {
-            continue;
-          }
-          return;
-        }
-
-        assert(before == WAITING);
-        if (!state_.compare_exchange_weak(before, LATE_DELIVERY)) {
-          continue;
-        }
-        state_.futexWake(1);
-        return;
-      }
+    if (before == TIMED_OUT) {
+      return;
     }
+
+    assert(before == WAITING);
+    state_.store(LATE_DELIVERY, std::memory_order_release);
+    state_.futexWake(1);
   }
 
   /// Waits until post() has been called in the current Baton lifetime.
index 2512628..1c3c884 100644 (file)
@@ -19,8 +19,6 @@
 #include <thread>
 
 #include <folly/Benchmark.h>
-#include <folly/portability/GFlags.h>
-#include <folly/portability/GTest.h>
 #include <folly/portability/Semaphore.h>
 #include <folly/synchronization/test/BatonTestHelpers.h>
 #include <folly/test/DeterministicSchedule.h>
@@ -31,38 +29,22 @@ using folly::detail::EmulatedFutexAtomic;
 
 typedef DeterministicSchedule DSched;
 
-BENCHMARK(baton_pingpong_single_poster_blocking, iters) {
-  run_pingpong_test<std::atomic, true, true>(iters);
+BENCHMARK(baton_pingpong_blocking, iters) {
+  run_pingpong_test<std::atomic, true>(iters);
 }
 
-BENCHMARK(baton_pingpong_multi_poster_blocking, iters) {
-  run_pingpong_test<std::atomic, false, true>(iters);
-}
-
-BENCHMARK(baton_pingpong_single_poster_nonblocking, iters) {
-  run_pingpong_test<std::atomic, true, false>(iters);
-}
-
-BENCHMARK(baton_pingpong_multi_poster_nonblocking, iters) {
-  run_pingpong_test<std::atomic, false, false>(iters);
+BENCHMARK(baton_pingpong_nonblocking, iters) {
+  run_pingpong_test<std::atomic, false>(iters);
 }
 
 BENCHMARK_DRAW_LINE()
 
-BENCHMARK(baton_pingpong_emulated_futex_single_poster_blocking, iters) {
-  run_pingpong_test<EmulatedFutexAtomic, true, true>(iters);
-}
-
-BENCHMARK(baton_pingpong_emulated_futex_multi_poster_blocking, iters) {
-  run_pingpong_test<EmulatedFutexAtomic, false, true>(iters);
-}
-
-BENCHMARK(baton_pingpong_emulated_futex_single_poster_nonblocking, iters) {
-  run_pingpong_test<EmulatedFutexAtomic, true, false>(iters);
+BENCHMARK(baton_pingpong_emulated_futex_blocking, iters) {
+  run_pingpong_test<EmulatedFutexAtomic, true>(iters);
 }
 
-BENCHMARK(baton_pingpong_emulated_futex_multi_poster_nonblocking, iters) {
-  run_pingpong_test<EmulatedFutexAtomic, false, false>(iters);
+BENCHMARK(baton_pingpong_emulated_futex_nonblocking, iters) {
+  run_pingpong_test<EmulatedFutexAtomic, false>(iters);
 }
 
 BENCHMARK_DRAW_LINE()
@@ -93,12 +75,7 @@ BENCHMARK(posix_sem_pingpong, iters) {
 // to the required futex calls for the blocking case
 
 int main(int argc, char** argv) {
-  testing::InitGoogleTest(&argc, argv);
   gflags::ParseCommandLineFlags(&argc, &argv, true);
-
-  auto rv = RUN_ALL_TESTS();
-  if (!rv && FLAGS_benchmark) {
-    folly::runBenchmarks();
-  }
-  return rv;
+  folly::runBenchmarks();
+  return 0;
 }
index 2e6f516..955f29b 100644 (file)
@@ -28,258 +28,92 @@ using folly::detail::EmulatedFutexAtomic;
 
 /// Basic test
 
-TEST(Baton, basic_single_poster_blocking) {
-  run_basic_test<std::atomic, true, true>();
-  run_basic_test<EmulatedFutexAtomic, true, true>();
-  run_basic_test<DeterministicAtomic, true, true>();
+TEST(Baton, basic_blocking) {
+  run_basic_test<std::atomic, true>();
+  run_basic_test<EmulatedFutexAtomic, true>();
+  run_basic_test<DeterministicAtomic, true>();
 }
 
-TEST(Baton, basic_single_poster_nonblocking) {
-  run_basic_test<std::atomic, true, false>();
-  run_basic_test<EmulatedFutexAtomic, true, false>();
-  run_basic_test<DeterministicAtomic, true, false>();
-}
-
-TEST(Baton, basic_multi_poster_blocking) {
-  run_basic_test<std::atomic, false, true>();
-}
-
-TEST(Baton, basic_multi_poster_nonblocking) {
-  run_basic_test<std::atomic, false, false>();
+TEST(Baton, basic_nonblocking) {
+  run_basic_test<std::atomic, false>();
+  run_basic_test<EmulatedFutexAtomic, false>();
+  run_basic_test<DeterministicAtomic, false>();
 }
 
 /// Ping pong tests
 
-TEST(Baton, pingpong_single_poster_blocking) {
-  DSched sched(DSched::uniform(0));
-
-  run_pingpong_test<DeterministicAtomic, true, true>(1000);
-}
-
-TEST(Baton, pingpong_single_poster_nonblocking) {
+TEST(Baton, pingpong_blocking) {
   DSched sched(DSched::uniform(0));
 
-  run_pingpong_test<DeterministicAtomic, true, false>(1000);
+  run_pingpong_test<DeterministicAtomic, true>(1000);
 }
 
-TEST(Baton, pingpong_multi_poster_blocking) {
+TEST(Baton, pingpong_nonblocking) {
   DSched sched(DSched::uniform(0));
 
-  run_pingpong_test<DeterministicAtomic, false, true>(1000);
-}
-
-TEST(Baton, pingpong_multi_poster_nonblocking) {
-  DSched sched(DSched::uniform(0));
-
-  run_pingpong_test<DeterministicAtomic, false, false>(1000);
+  run_pingpong_test<DeterministicAtomic, false>(1000);
 }
 
 /// Timed wait tests - Nonblocking Baton does not support timed_wait()
 
 // Timed wait basic system clock tests
 
-TEST(Baton, timed_wait_basic_system_clock_single_poster) {
-  run_basic_timed_wait_tests<std::atomic, std::chrono::system_clock, true>();
-  run_basic_timed_wait_tests<
-      EmulatedFutexAtomic,
-      std::chrono::system_clock,
-      true>();
-  run_basic_timed_wait_tests<
-      DeterministicAtomic,
-      std::chrono::system_clock,
-      true>();
-}
-
-TEST(Baton, timed_wait_basic_system_clock_multi_poster) {
-  run_basic_timed_wait_tests<std::atomic, std::chrono::system_clock, false>();
-  run_basic_timed_wait_tests<
-      EmulatedFutexAtomic,
-      std::chrono::system_clock,
-      false>();
-  run_basic_timed_wait_tests<
-      DeterministicAtomic,
-      std::chrono::system_clock,
-      false>();
+TEST(Baton, timed_wait_basic_system_clock) {
+  run_basic_timed_wait_tests<std::atomic, std::chrono::system_clock>();
+  run_basic_timed_wait_tests<EmulatedFutexAtomic, std::chrono::system_clock>();
+  run_basic_timed_wait_tests<DeterministicAtomic, std::chrono::system_clock>();
 }
 
 // Timed wait timeout system clock tests
 
-TEST(Baton, timed_wait_timeout_system_clock_single_poster) {
-  run_timed_wait_tmo_tests<std::atomic, std::chrono::system_clock, true>();
-  run_timed_wait_tmo_tests<
-      EmulatedFutexAtomic,
-      std::chrono::system_clock,
-      true>();
-  run_timed_wait_tmo_tests<
-      DeterministicAtomic,
-      std::chrono::system_clock,
-      true>();
-}
-
-TEST(Baton, timed_wait_timeout_system_clock_multi_poster) {
-  run_timed_wait_tmo_tests<std::atomic, std::chrono::system_clock, false>();
-  run_timed_wait_tmo_tests<
-      EmulatedFutexAtomic,
-      std::chrono::system_clock,
-      false>();
-  run_timed_wait_tmo_tests<
-      DeterministicAtomic,
-      std::chrono::system_clock,
-      false>();
+TEST(Baton, timed_wait_timeout_system_clock) {
+  run_timed_wait_tmo_tests<std::atomic, std::chrono::system_clock>();
+  run_timed_wait_tmo_tests<EmulatedFutexAtomic, std::chrono::system_clock>();
+  run_timed_wait_tmo_tests<DeterministicAtomic, std::chrono::system_clock>();
 }
 
 // Timed wait regular system clock tests
 
-TEST(Baton, timed_wait_system_clock_single_poster) {
-  run_timed_wait_regular_test<std::atomic, std::chrono::system_clock, true>();
-  run_timed_wait_regular_test<
-      EmulatedFutexAtomic,
-      std::chrono::system_clock,
-      true>();
-  run_timed_wait_regular_test<
-      DeterministicAtomic,
-      std::chrono::system_clock,
-      true>();
-}
-
-TEST(Baton, timed_wait_system_clock_multi_poster) {
-  run_timed_wait_regular_test<std::atomic, std::chrono::system_clock, false>();
-  run_timed_wait_regular_test<
-      EmulatedFutexAtomic,
-      std::chrono::system_clock,
-      false>();
-  run_timed_wait_regular_test<
-      DeterministicAtomic,
-      std::chrono::system_clock,
-      false>();
+TEST(Baton, timed_wait_system_clock) {
+  run_timed_wait_regular_test<std::atomic, std::chrono::system_clock>();
+  run_timed_wait_regular_test<EmulatedFutexAtomic, std::chrono::system_clock>();
+  run_timed_wait_regular_test<DeterministicAtomic, std::chrono::system_clock>();
 }
 
 // Timed wait basic steady clock tests
 
-TEST(Baton, timed_wait_basic_steady_clock_single_poster) {
-  run_basic_timed_wait_tests<std::atomic, std::chrono::steady_clock, true>();
-  run_basic_timed_wait_tests<
-      EmulatedFutexAtomic,
-      std::chrono::steady_clock,
-      true>();
-  run_basic_timed_wait_tests<
-      DeterministicAtomic,
-      std::chrono::steady_clock,
-      true>();
-}
-
-TEST(Baton, timed_wait_basic_steady_clock_multi_poster) {
-  run_basic_timed_wait_tests<std::atomic, std::chrono::steady_clock, false>();
-  run_basic_timed_wait_tests<
-      EmulatedFutexAtomic,
-      std::chrono::steady_clock,
-      false>();
-  run_basic_timed_wait_tests<
-      DeterministicAtomic,
-      std::chrono::steady_clock,
-      false>();
+TEST(Baton, timed_wait_basic_steady_clock) {
+  run_basic_timed_wait_tests<std::atomic, std::chrono::steady_clock>();
+  run_basic_timed_wait_tests<EmulatedFutexAtomic, std::chrono::steady_clock>();
+  run_basic_timed_wait_tests<DeterministicAtomic, std::chrono::steady_clock>();
 }
 
 // Timed wait timeout steady clock tests
 
-TEST(Baton, timed_wait_timeout_steady_clock_single_poster) {
-  run_timed_wait_tmo_tests<std::atomic, std::chrono::steady_clock, true>();
-  run_timed_wait_tmo_tests<
-      EmulatedFutexAtomic,
-      std::chrono::steady_clock,
-      true>();
-  run_timed_wait_tmo_tests<
-      DeterministicAtomic,
-      std::chrono::steady_clock,
-      true>();
-}
-
-TEST(Baton, timed_wait_timeout_steady_clock_multi_poster) {
-  run_timed_wait_tmo_tests<std::atomic, std::chrono::steady_clock, false>();
-  run_timed_wait_tmo_tests<
-      EmulatedFutexAtomic,
-      std::chrono::steady_clock,
-      false>();
-  run_timed_wait_tmo_tests<
-      DeterministicAtomic,
-      std::chrono::steady_clock,
-      false>();
+TEST(Baton, timed_wait_timeout_steady_clock) {
+  run_timed_wait_tmo_tests<std::atomic, std::chrono::steady_clock>();
+  run_timed_wait_tmo_tests<EmulatedFutexAtomic, std::chrono::steady_clock>();
+  run_timed_wait_tmo_tests<DeterministicAtomic, std::chrono::steady_clock>();
 }
 
 // Timed wait regular steady clock tests
 
-TEST(Baton, timed_wait_steady_clock_single_poster) {
-  run_timed_wait_regular_test<std::atomic, std::chrono::steady_clock, true>();
-  run_timed_wait_regular_test<
-      EmulatedFutexAtomic,
-      std::chrono::steady_clock,
-      true>();
-  run_timed_wait_regular_test<
-      DeterministicAtomic,
-      std::chrono::steady_clock,
-      true>();
-}
-
-TEST(Baton, timed_wait_steady_clock_multi_poster) {
-  run_timed_wait_regular_test<std::atomic, std::chrono::steady_clock, false>();
-  run_timed_wait_regular_test<
-      EmulatedFutexAtomic,
-      std::chrono::steady_clock,
-      false>();
-  run_timed_wait_regular_test<
-      DeterministicAtomic,
-      std::chrono::steady_clock,
-      false>();
+TEST(Baton, timed_wait_steady_clock) {
+  run_timed_wait_regular_test<std::atomic, std::chrono::steady_clock>();
+  run_timed_wait_regular_test<EmulatedFutexAtomic, std::chrono::steady_clock>();
+  run_timed_wait_regular_test<DeterministicAtomic, std::chrono::steady_clock>();
 }
 
 /// Try wait tests
 
-TEST(Baton, try_wait_single_poster_blocking) {
-  run_try_wait_tests<std::atomic, true, true>();
-  run_try_wait_tests<EmulatedFutexAtomic, true, true>();
-  run_try_wait_tests<DeterministicAtomic, true, true>();
-}
-
-TEST(Baton, try_wait_single_poster_nonblocking) {
-  run_try_wait_tests<std::atomic, true, false>();
-  run_try_wait_tests<EmulatedFutexAtomic, true, false>();
-  run_try_wait_tests<DeterministicAtomic, true, false>();
-}
-
-TEST(Baton, try_wait_multi_poster_blocking) {
-  run_try_wait_tests<std::atomic, false, true>();
-  run_try_wait_tests<EmulatedFutexAtomic, false, true>();
-  run_try_wait_tests<DeterministicAtomic, false, true>();
-}
-
-TEST(Baton, try_wait_multi_poster_nonblocking) {
-  run_try_wait_tests<std::atomic, false, false>();
-  run_try_wait_tests<EmulatedFutexAtomic, false, false>();
-  run_try_wait_tests<DeterministicAtomic, false, false>();
-}
-
-/// Multi-producer tests
-
-TEST(Baton, multi_producer_single_poster_blocking) {
-  run_try_wait_tests<std::atomic, true, true>();
-  run_try_wait_tests<EmulatedFutexAtomic, true, true>();
-  run_try_wait_tests<DeterministicAtomic, true, true>();
-}
-
-TEST(Baton, multi_producer_single_poster_nonblocking) {
-  run_try_wait_tests<std::atomic, true, false>();
-  run_try_wait_tests<EmulatedFutexAtomic, true, false>();
-  run_try_wait_tests<DeterministicAtomic, true, false>();
-}
-
-TEST(Baton, multi_producer_multi_poster_blocking) {
-  run_try_wait_tests<std::atomic, false, true>();
-  run_try_wait_tests<EmulatedFutexAtomic, false, true>();
-  run_try_wait_tests<DeterministicAtomic, false, true>();
+TEST(Baton, try_wait_blocking) {
+  run_try_wait_tests<std::atomic, true>();
+  run_try_wait_tests<EmulatedFutexAtomic, true>();
+  run_try_wait_tests<DeterministicAtomic, true>();
 }
 
-TEST(Baton, multi_producer_multi_poster_nonblocking) {
-  run_try_wait_tests<std::atomic, false, false>();
-  run_try_wait_tests<EmulatedFutexAtomic, false, false>();
-  run_try_wait_tests<DeterministicAtomic, false, false>();
+TEST(Baton, try_wait_nonblocking) {
+  run_try_wait_tests<std::atomic, false>();
+  run_try_wait_tests<EmulatedFutexAtomic, false>();
+  run_try_wait_tests<DeterministicAtomic, false>();
 }
index 6e242e2..1f07a2a 100644 (file)
@@ -25,16 +25,16 @@ namespace test {
 
 typedef DeterministicSchedule DSched;
 
-template <template <typename> class Atom, bool SinglePoster, bool Blocking>
+template <template <typename> class Atom, bool Blocking>
 void run_basic_test() {
-  Baton<Atom, SinglePoster, Blocking> b;
+  Baton<Atom, Blocking> b;
   b.post();
   b.wait();
 }
 
-template <template <typename> class Atom, bool SinglePoster, bool Blocking>
+template <template <typename> class Atom, bool Blocking>
 void run_pingpong_test(int numRounds) {
-  using B = Baton<Atom, SinglePoster, Blocking>;
+  using B = Baton<Atom, Blocking>;
   B batons[17];
   B& a = batons[0];
   B& b = batons[16]; // to get it on a different cache line
@@ -53,17 +53,17 @@ void run_pingpong_test(int numRounds) {
   DSched::join(thr);
 }
 
-template <template <typename> class Atom, typename Clock, bool SinglePoster>
+template <template <typename> class Atom, typename Clock>
 void run_basic_timed_wait_tests() {
-  Baton<Atom, SinglePoster> b;
+  Baton<Atom> b;
   b.post();
   // tests if early delivery works fine
   EXPECT_TRUE(b.timed_wait(Clock::now()));
 }
 
-template <template <typename> class Atom, typename Clock, bool SinglePoster>
+template <template <typename> class Atom, typename Clock>
 void run_timed_wait_tmo_tests() {
-  Baton<Atom, SinglePoster> b;
+  Baton<Atom> b;
 
   auto thr = DSched::thread([&] {
     bool rv = b.timed_wait(Clock::now() + std::chrono::milliseconds(1));
@@ -73,9 +73,9 @@ void run_timed_wait_tmo_tests() {
   DSched::join(thr);
 }
 
-template <template <typename> class Atom, typename Clock, bool SinglePoster>
+template <template <typename> class Atom, typename Clock>
 void run_timed_wait_regular_test() {
-  Baton<Atom, SinglePoster> b;
+  Baton<Atom> b;
 
   auto thr = DSched::thread([&] {
     // To wait forever we'd like to use time_point<Clock>::max, but
@@ -104,68 +104,13 @@ void run_timed_wait_regular_test() {
   DSched::join(thr);
 }
 
-template <template <typename> class Atom, bool SinglePoster, bool Blocking>
+template <template <typename> class Atom, bool Blocking>
 void run_try_wait_tests() {
-  Baton<Atom, SinglePoster, Blocking> b;
+  Baton<Atom, Blocking> b;
   EXPECT_FALSE(b.try_wait());
   b.post();
   EXPECT_TRUE(b.try_wait());
 }
 
-template <template <typename> class Atom, bool SinglePoster, bool Blocking>
-void run_multi_producer_tests() {
-  constexpr int NPROD = 5;
-  Baton<Atom, SinglePoster, Blocking> local_ping[NPROD];
-  Baton<Atom, SinglePoster, Blocking> local_pong[NPROD];
-  Baton<Atom, /* SingleProducer = */ false, Blocking> global;
-  Baton<Atom, SinglePoster, Blocking> shutdown;
-
-  std::thread prod[NPROD];
-  for (int i = 0; i < NPROD; ++i) {
-    prod[i] = DSched::thread([&, i] {
-      if (!std::is_same<Atom<int>, DeterministicAtomic<int>>::value) {
-        // If we are using std::atomic (or EmulatedFutexAtomic) then
-        // a variable sleep here will make it more likely that
-        // global.post()-s will span more than one global.wait() by
-        // the consumer thread and for the latter to block (if the
-        // global baton is blocking). For DeterministicAtomic, we just
-        // rely on DeterministicSchedule to do the scheduling.  The
-        // test won't fail if we lose the race, we just don't get
-        // coverage.
-        for (int j = 0; j < i; ++j) {
-          std::this_thread::sleep_for(std::chrono::microseconds(1));
-        }
-      }
-      local_ping[i].post();
-      global.post();
-      local_pong[i].wait();
-    });
-  }
-
-  auto cons = DSched::thread([&] {
-    while (true) {
-      global.wait();
-      global.reset();
-      if (shutdown.try_wait()) {
-        return;
-      }
-      for (int i = 0; i < NPROD; ++i) {
-        if (local_ping.try_wait()) {
-          local_ping.reset();
-          local_pong.post();
-        }
-      }
-    }
-  });
-
-  for (auto& t : prod) {
-    DSched::join(t);
-  }
-
-  global.post();
-  shutdown.post();
-  DSched::join(cons);
-}
-
 } // namespace test
 } // namespace folly