Default VirtualEventBase
[folly.git] / folly / fibers / test / FibersTest.cpp
index 1577b5d30c695eb60d90008cae52f7c12ca09d28..b3d32303c91441a475e2256ea4b152a7f49e995b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016 Facebook, Inc.
+ * Copyright 2017 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -31,6 +31,7 @@
 #include <folly/fibers/GenericBaton.h>
 #include <folly/fibers/Semaphore.h>
 #include <folly/fibers/SimpleLoopController.h>
+#include <folly/fibers/TimedMutex.h>
 #include <folly/fibers/WhenN.h>
 #include <folly/io/async/ScopedEventBaseThread.h>
 #include <folly/portability/GTest.h>
@@ -291,7 +292,7 @@ TEST(FiberManager, addTasksNoncopyable) {
     if (!taskAdded) {
       manager.addTask([&]() {
         std::vector<std::function<std::unique_ptr<int>()>> funcs;
-        for (size_t i = 0; i < 3; ++i) {
+        for (int i = 0; i < 3; ++i) {
           funcs.push_back([i, &pendingFibers]() {
             await([&pendingFibers](Promise<int> promise) {
               pendingFibers.push_back(std::move(promise));
@@ -1863,7 +1864,7 @@ void dispatchJobs(
 
             if (dispatchProblem == DispatchProblem::DuplicateDispatch) {
               if (i == problemIndex) {
-                EXPECT_THROW(job.token.dispatch(job.input), std::logic_error);
+                EXPECT_THROW(job.token.dispatch(job.input), ABDUsageException);
               }
             }
           } catch (...) {
@@ -1968,7 +1969,7 @@ TEST(FiberManager, ABD_DispatcherDestroyedBeforeCallingCommit) {
     /* User code handles the exception and does not exit process */
   }
   evb.loop();
-  validateResults<std::logic_error>(results, COUNT);
+  validateResults<ABDCommitNotCalledException>(results, COUNT);
 }
 
 TEST(FiberManager, ABD_PreprocessingFailureTest) {
@@ -1984,7 +1985,7 @@ TEST(FiberManager, ABD_PreprocessingFailureTest) {
   dispatchJobs(executor, jobs, results, DispatchProblem::PreprocessThrows, 8);
   atomicBatchDispatcher.commit();
   evb.loop();
-  validateResults<std::logic_error>(results, COUNT - 1);
+  validateResults<ABDTokenNotDispatchedException>(results, COUNT - 1);
 }
 
 TEST(FiberManager, ABD_MultipleDispatchOnSameTokenErrorTest) {
@@ -2013,12 +2014,12 @@ TEST(FiberManager, ABD_GetTokenCalledAfterCommitTest) {
       createAtomicBatchDispatcher(std::move(dispatchFunc));
   createJobs(atomicBatchDispatcher, jobs, COUNT);
   atomicBatchDispatcher.commit();
-  EXPECT_THROW(atomicBatchDispatcher.getToken(), std::logic_error);
+  EXPECT_THROW(atomicBatchDispatcher.getToken(), ABDUsageException);
   dispatchJobs(executor, jobs, results);
-  EXPECT_THROW(atomicBatchDispatcher.getToken(), std::logic_error);
+  EXPECT_THROW(atomicBatchDispatcher.getToken(), ABDUsageException);
   evb.loop();
   validateResults(results, COUNT);
-  EXPECT_THROW(atomicBatchDispatcher.getToken(), std::logic_error);
+  EXPECT_THROW(atomicBatchDispatcher.getToken(), ABDUsageException);
 }
 
 TEST(FiberManager, ABD_UserProvidedBatchDispatchThrowsTest) {
@@ -2041,37 +2042,97 @@ TEST(FiberManager, ABD_UserProvidedBatchDispatchThrowsTest) {
 }
 
 TEST(FiberManager, VirtualEventBase) {
-  folly::ScopedEventBaseThread thread;
-
-  auto evb1 =
-      folly::make_unique<folly::VirtualEventBase>(*thread.getEventBase());
-  auto evb2 =
-      folly::make_unique<folly::VirtualEventBase>(*thread.getEventBase());
-
   bool done1{false};
   bool done2{false};
+  {
+    folly::ScopedEventBaseThread thread;
 
-  getFiberManager(*evb1).addTaskRemote([&] {
-    Baton baton;
-    baton.timed_wait(std::chrono::milliseconds{100});
+    auto evb1 =
+        folly::make_unique<folly::VirtualEventBase>(*thread.getEventBase());
+    auto& evb2 = thread.getEventBase()->getVirtualEventBase();
 
-    done1 = true;
-  });
+    getFiberManager(*evb1).addTaskRemote([&] {
+      Baton baton;
+      baton.timed_wait(std::chrono::milliseconds{100});
 
-  getFiberManager(*evb2).addTaskRemote([&] {
-    Baton baton;
-    baton.timed_wait(std::chrono::milliseconds{200});
+      done1 = true;
+    });
 
-    done2 = true;
-  });
+    getFiberManager(evb2).addTaskRemote([&] {
+      Baton baton;
+      baton.timed_wait(std::chrono::milliseconds{200});
+
+      done2 = true;
+    });
 
-  evb1.reset();
-  EXPECT_TRUE(done1);
+    EXPECT_FALSE(done1);
+    EXPECT_FALSE(done2);
 
-  evb2.reset();
+    evb1.reset();
+    EXPECT_TRUE(done1);
+    EXPECT_FALSE(done2);
+  }
   EXPECT_TRUE(done2);
 }
 
+TEST(TimedMutex, ThreadFiberDeadlockOrder) {
+  folly::EventBase evb;
+  auto& fm = getFiberManager(evb);
+  TimedMutex mutex;
+
+  mutex.lock();
+  std::thread unlockThread([&] {
+    /* sleep override */ std::this_thread::sleep_for(
+        std::chrono::milliseconds{100});
+    mutex.unlock();
+  });
+
+  fm.addTask([&] { std::lock_guard<TimedMutex> lg(mutex); });
+  fm.addTask([&] {
+    runInMainContext([&] {
+      auto locked = mutex.timed_lock(std::chrono::seconds{1});
+      EXPECT_TRUE(locked);
+      if (locked) {
+        mutex.unlock();
+      }
+    });
+  });
+
+  evb.loopOnce();
+  EXPECT_EQ(0, fm.hasTasks());
+
+  unlockThread.join();
+}
+
+TEST(TimedMutex, ThreadFiberDeadlockRace) {
+  folly::EventBase evb;
+  auto& fm = getFiberManager(evb);
+  TimedMutex mutex;
+
+  mutex.lock();
+
+  fm.addTask([&] {
+    auto locked = mutex.timed_lock(std::chrono::seconds{1});
+    EXPECT_TRUE(locked);
+    if (locked) {
+      mutex.unlock();
+    }
+  });
+  fm.addTask([&] {
+    mutex.unlock();
+    runInMainContext([&] {
+      auto locked = mutex.timed_lock(std::chrono::seconds{1});
+      EXPECT_TRUE(locked);
+      if (locked) {
+        mutex.unlock();
+      }
+    });
+  });
+
+  evb.loopOnce();
+  EXPECT_EQ(0, fm.hasTasks());
+}
+
 /**
  * Test that we can properly track fiber stack usage.
  *