Fix GuardPageAllocator to do mprotect lazily
[folly.git] / folly / experimental / fibers / test / FibersTest.cpp
index ed6156f1058e59472e076c53c14ecb99352b1ff7..4fe936455ef7046d80e3ba7a139653e7546172e8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015 Facebook, Inc.
+ * Copyright 2016 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 
 #include <folly/Benchmark.h>
 #include <folly/Memory.h>
+#include <folly/futures/Future.h>
 
 #include <folly/experimental/fibers/AddTasks.h>
 #include <folly/experimental/fibers/EventBaseLoopController.h>
 #include <folly/experimental/fibers/FiberManager.h>
+#include <folly/experimental/fibers/FiberManagerMap.h>
 #include <folly/experimental/fibers/GenericBaton.h>
 #include <folly/experimental/fibers/SimpleLoopController.h>
 #include <folly/experimental/fibers/WhenN.h>
@@ -936,16 +938,22 @@ TEST(FiberManager, runInMainContext) {
 
   checkRan = false;
 
-  manager.addTask(
-    [&]() {
-      int stackLocation;
-      runInMainContext(
-        [&]() {
-          expectMainContext(checkRan, &mainLocation, &stackLocation);
-        });
-      EXPECT_TRUE(checkRan);
-    }
-  );
+  manager.addTask([&]() {
+    struct A {
+      explicit A(int value_) : value(value_) {}
+      A(const A&) = delete;
+      A(A&&) = default;
+
+      int value;
+    };
+    int stackLocation;
+    auto ret = runInMainContext([&]() {
+      expectMainContext(checkRan, &mainLocation, &stackLocation);
+      return A(42);
+    });
+    EXPECT_TRUE(checkRan);
+    EXPECT_EQ(42, ret.value);
+  });
 
   loopController.loop(
     [&]() {
@@ -1366,17 +1374,18 @@ TEST(FiberManager, RequestContext) {
 
   folly::RequestContext::create();
   auto rcontext3 = folly::RequestContext::get();
-  fm.addTaskFinally([&]() {
-      EXPECT_EQ(rcontext3, folly::RequestContext::get());
-      baton3.wait();
-      EXPECT_EQ(rcontext3, folly::RequestContext::get());
-
-      return folly::Unit();
-    },
-    [&](Try<folly::Unit>&& t) {
-      EXPECT_EQ(rcontext3, folly::RequestContext::get());
-      checkRun3 = true;
-    });
+  fm.addTaskFinally(
+      [&]() {
+        EXPECT_EQ(rcontext3, folly::RequestContext::get());
+        baton3.wait();
+        EXPECT_EQ(rcontext3, folly::RequestContext::get());
+
+        return folly::Unit();
+      },
+      [&](Try<folly::Unit>&& /* t */) {
+        EXPECT_EQ(rcontext3, folly::RequestContext::get());
+        checkRun3 = true;
+      });
 
   folly::RequestContext::create();
   auto rcontext = folly::RequestContext::get();
@@ -1465,6 +1474,113 @@ TEST(FiberManager, resizePeriodically) {
   EXPECT_EQ(5, manager.fibersPoolSize());
 }
 
+TEST(FiberManager, batonWaitTimeoutHandler) {
+  FiberManager manager(folly::make_unique<EventBaseLoopController>());
+
+  folly::EventBase evb;
+  dynamic_cast<EventBaseLoopController&>(manager.loopController())
+    .attachEventBase(evb);
+
+  size_t fibersRun = 0;
+  Baton baton;
+  Baton::TimeoutHandler timeoutHandler;
+
+  manager.addTask([&]() {
+    baton.wait(timeoutHandler);
+    ++fibersRun;
+  });
+  manager.loopUntilNoReady();
+
+  EXPECT_FALSE(baton.try_wait());
+  EXPECT_EQ(0, fibersRun);
+
+  timeoutHandler.scheduleTimeout(std::chrono::milliseconds(250));
+  std::this_thread::sleep_for(std::chrono::milliseconds(500));
+
+  EXPECT_FALSE(baton.try_wait());
+  EXPECT_EQ(0, fibersRun);
+
+  evb.loopOnce();
+  manager.loopUntilNoReady();
+
+  EXPECT_EQ(1, fibersRun);
+}
+
+TEST(FiberManager, batonWaitTimeoutMany) {
+  FiberManager manager(folly::make_unique<EventBaseLoopController>());
+
+  folly::EventBase evb;
+  dynamic_cast<EventBaseLoopController&>(manager.loopController())
+    .attachEventBase(evb);
+
+  constexpr size_t kNumTimeoutTasks = 10000;
+  size_t tasksCount = kNumTimeoutTasks;
+
+  // We add many tasks to hit timeout queue deallocation logic.
+  for (size_t i = 0; i < kNumTimeoutTasks; ++i) {
+    manager.addTask([&]() {
+      Baton baton;
+      Baton::TimeoutHandler timeoutHandler;
+
+      folly::fibers::addTask([&] {
+        timeoutHandler.scheduleTimeout(std::chrono::milliseconds(1000));
+      });
+
+      baton.wait(timeoutHandler);
+      if (--tasksCount == 0) {
+        evb.terminateLoopSoon();
+      }
+    });
+  }
+
+  evb.loopForever();
+}
+
+TEST(FiberManager, remoteFutureTest) {
+  FiberManager fiberManager(folly::make_unique<SimpleLoopController>());
+  auto& loopController =
+      dynamic_cast<SimpleLoopController&>(fiberManager.loopController());
+
+  int testValue1 = 5;
+  int testValue2 = 7;
+  auto f1 = fiberManager.addTaskFuture([&]() { return testValue1; });
+  auto f2 = fiberManager.addTaskRemoteFuture([&]() { return testValue2; });
+  loopController.loop([&]() { loopController.stop(); });
+  auto v1 = f1.get();
+  auto v2 = f2.get();
+
+  EXPECT_EQ(v1, testValue1);
+  EXPECT_EQ(v2, testValue2);
+}
+
+TEST(FiberManager, nestedFiberManagers) {
+  folly::EventBase outerEvb;
+  folly::EventBase innerEvb;
+
+  getFiberManager(outerEvb).addTask([&]() {
+    EXPECT_EQ(&getFiberManager(outerEvb),
+              FiberManager::getFiberManagerUnsafe());
+
+    runInMainContext([&]() {
+      getFiberManager(innerEvb).addTask([&]() {
+        EXPECT_EQ(&getFiberManager(innerEvb),
+                  FiberManager::getFiberManagerUnsafe());
+
+        innerEvb.terminateLoopSoon();
+      });
+
+      innerEvb.loopForever();
+    });
+
+    EXPECT_EQ(&getFiberManager(outerEvb),
+              FiberManager::getFiberManagerUnsafe());
+
+    outerEvb.terminateLoopSoon();
+  });
+
+  outerEvb.loopForever();
+}
+
 static size_t sNumAwaits;
 
 void runBenchmark(size_t numAwaits, size_t toSend) {
@@ -1512,6 +1628,15 @@ BENCHMARK(FiberManagerBasicFiveAwaits, iters) {
   runBenchmark(5, iters);
 }
 
+BENCHMARK(FiberManagerCreateDestroy, iters) {
+  for (size_t i = 0; i < iters; ++i) {
+    folly::EventBase evb;
+    auto& fm = folly::fibers::getFiberManager(evb);
+    fm.addTask([]() {});
+    evb.loop();
+  }
+}
+
 BENCHMARK(FiberManagerAllocateDeallocatePattern, iters) {
   static const size_t kNumAllocations = 10000;