2 * Copyright 2016 Facebook, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
20 #include <gtest/gtest.h>
22 #include <folly/Benchmark.h>
23 #include <folly/Memory.h>
24 #include <folly/futures/Future.h>
26 #include <folly/experimental/fibers/AddTasks.h>
27 #include <folly/experimental/fibers/EventBaseLoopController.h>
28 #include <folly/experimental/fibers/FiberManager.h>
29 #include <folly/experimental/fibers/FiberManagerMap.h>
30 #include <folly/experimental/fibers/GenericBaton.h>
31 #include <folly/experimental/fibers/SimpleLoopController.h>
32 #include <folly/experimental/fibers/WhenN.h>
34 using namespace folly::fibers;
38 TEST(FiberManager, batonTimedWaitTimeout) {
39 bool taskAdded = false;
40 size_t iterations = 0;
42 FiberManager manager(folly::make_unique<SimpleLoopController>());
43 auto& loopController =
44 dynamic_cast<SimpleLoopController&>(manager.loopController());
46 auto loopFunc = [&]() {
52 auto res = baton.timed_wait(std::chrono::milliseconds(230));
55 EXPECT_EQ(5, iterations);
57 loopController.stop();
64 auto res = baton.timed_wait(std::chrono::milliseconds(130));
67 EXPECT_EQ(3, iterations);
69 loopController.stop();
74 std::this_thread::sleep_for(std::chrono::milliseconds(50));
79 loopController.loop(std::move(loopFunc));
82 TEST(FiberManager, batonTimedWaitPost) {
83 bool taskAdded = false;
84 size_t iterations = 0;
87 FiberManager manager(folly::make_unique<SimpleLoopController>());
88 auto& loopController =
89 dynamic_cast<SimpleLoopController&>(manager.loopController());
91 auto loopFunc = [&]() {
98 auto res = baton.timed_wait(std::chrono::milliseconds(130));
101 EXPECT_EQ(2, iterations);
103 loopController.stop();
108 std::this_thread::sleep_for(std::chrono::milliseconds(50));
110 if (iterations == 2) {
116 loopController.loop(std::move(loopFunc));
119 TEST(FiberManager, batonTimedWaitTimeoutEvb) {
120 size_t tasksComplete = 0;
122 folly::EventBase evb;
124 FiberManager manager(folly::make_unique<EventBaseLoopController>());
125 dynamic_cast<EventBaseLoopController&>(
126 manager.loopController()).attachEventBase(evb);
128 auto task = [&](size_t timeout_ms) {
131 auto start = EventBaseLoopController::Clock::now();
132 auto res = baton.timed_wait(std::chrono::milliseconds(timeout_ms));
133 auto finish = EventBaseLoopController::Clock::now();
138 std::chrono::duration_cast<std::chrono::milliseconds>(finish - start);
140 EXPECT_GT(duration_ms.count(), timeout_ms - 50);
141 EXPECT_LT(duration_ms.count(), timeout_ms + 50);
143 if (++tasksComplete == 2) {
144 evb.terminateLoopSoon();
148 evb.runInEventBaseThread([&]() {
163 EXPECT_EQ(2, tasksComplete);
166 TEST(FiberManager, batonTimedWaitPostEvb) {
167 size_t tasksComplete = 0;
169 folly::EventBase evb;
171 FiberManager manager(folly::make_unique<EventBaseLoopController>());
172 dynamic_cast<EventBaseLoopController&>(
173 manager.loopController()).attachEventBase(evb);
175 evb.runInEventBaseThread([&]() {
176 manager.addTask([&]() {
179 evb.tryRunAfterDelay([&]() {
184 auto start = EventBaseLoopController::Clock::now();
185 auto res = baton.timed_wait(std::chrono::milliseconds(130));
186 auto finish = EventBaseLoopController::Clock::now();
190 auto duration_ms = std::chrono::duration_cast<
191 std::chrono::milliseconds>(finish - start);
193 EXPECT_TRUE(duration_ms.count() > 95 &&
194 duration_ms.count() < 110);
196 if (++tasksComplete == 1) {
197 evb.terminateLoopSoon();
204 EXPECT_EQ(1, tasksComplete);
207 TEST(FiberManager, batonTryWait) {
209 FiberManager manager(folly::make_unique<SimpleLoopController>());
211 // Check if try_wait and post work as expected
214 manager.addTask([&](){
215 while (!b.try_wait()) {
218 auto thr = std::thread([&](){
219 std::this_thread::sleep_for(std::chrono::milliseconds(300));
223 manager.loopUntilNoReady();
228 // Check try_wait without post
229 manager.addTask([&](){
231 while (cnt && !c.try_wait()) {
234 EXPECT_TRUE(!c.try_wait()); // must still hold
238 manager.loopUntilNoReady();
241 TEST(FiberManager, genericBatonFiberWait) {
242 FiberManager manager(folly::make_unique<SimpleLoopController>());
245 bool fiberRunning = false;
247 manager.addTask([&](){
248 EXPECT_EQ(manager.hasActiveFiber(), true);
251 fiberRunning = false;
254 EXPECT_FALSE(fiberRunning);
255 manager.loopUntilNoReady();
256 EXPECT_TRUE(fiberRunning); // ensure fiber still active
258 auto thr = std::thread([&](){
259 std::this_thread::sleep_for(std::chrono::milliseconds(300));
263 while (fiberRunning) {
264 manager.loopUntilNoReady();
270 TEST(FiberManager, genericBatonThreadWait) {
271 FiberManager manager(folly::make_unique<SimpleLoopController>());
273 std::atomic<bool> threadWaiting(false);
275 auto thr = std::thread([&](){
276 threadWaiting = true;
278 threadWaiting = false;
281 while (!threadWaiting) {}
282 std::this_thread::sleep_for(std::chrono::milliseconds(300));
284 manager.addTask([&](){
285 EXPECT_EQ(manager.hasActiveFiber(), true);
286 EXPECT_TRUE(threadWaiting);
288 while(threadWaiting) {}
291 manager.loopUntilNoReady();
295 TEST(FiberManager, addTasksNoncopyable) {
296 std::vector<Promise<int>> pendingFibers;
297 bool taskAdded = false;
299 FiberManager manager(folly::make_unique<SimpleLoopController>());
300 auto& loopController =
301 dynamic_cast<SimpleLoopController&>(manager.loopController());
303 auto loopFunc = [&]() {
307 std::vector<std::function<std::unique_ptr<int>()>> funcs;
308 for (size_t i = 0; i < 3; ++i) {
310 [i, &pendingFibers]() {
311 await([&pendingFibers](Promise<int> promise) {
312 pendingFibers.push_back(std::move(promise));
314 return folly::make_unique<int>(i*2 + 1);
319 auto iter = addTasks(funcs.begin(), funcs.end());
322 while (iter.hasNext()) {
323 auto result = iter.awaitNext();
324 EXPECT_EQ(2 * iter.getTaskID() + 1, *result);
325 EXPECT_GE(2 - n, pendingFibers.size());
332 } else if (pendingFibers.size()) {
333 pendingFibers.back().setValue(0);
334 pendingFibers.pop_back();
336 loopController.stop();
340 loopController.loop(std::move(loopFunc));
343 TEST(FiberManager, addTasksThrow) {
344 std::vector<Promise<int>> pendingFibers;
345 bool taskAdded = false;
347 FiberManager manager(folly::make_unique<SimpleLoopController>());
348 auto& loopController =
349 dynamic_cast<SimpleLoopController&>(manager.loopController());
351 auto loopFunc = [&]() {
355 std::vector<std::function<int()>> funcs;
356 for (size_t i = 0; i < 3; ++i) {
358 [i, &pendingFibers]() {
359 await([&pendingFibers](Promise<int> promise) {
360 pendingFibers.push_back(std::move(promise));
363 throw std::runtime_error("Runtime");
370 auto iter = addTasks(funcs.begin(), funcs.end());
373 while (iter.hasNext()) {
375 int result = iter.awaitNext();
376 EXPECT_EQ(1, iter.getTaskID() % 2);
377 EXPECT_EQ(2 * iter.getTaskID() + 1, result);
379 EXPECT_EQ(0, iter.getTaskID() % 2);
381 EXPECT_GE(2 - n, pendingFibers.size());
388 } else if (pendingFibers.size()) {
389 pendingFibers.back().setValue(0);
390 pendingFibers.pop_back();
392 loopController.stop();
396 loopController.loop(std::move(loopFunc));
399 TEST(FiberManager, addTasksVoid) {
400 std::vector<Promise<int>> pendingFibers;
401 bool taskAdded = false;
403 FiberManager manager(folly::make_unique<SimpleLoopController>());
404 auto& loopController =
405 dynamic_cast<SimpleLoopController&>(manager.loopController());
407 auto loopFunc = [&]() {
411 std::vector<std::function<void()>> funcs;
412 for (size_t i = 0; i < 3; ++i) {
414 [i, &pendingFibers]() {
415 await([&pendingFibers](Promise<int> promise) {
416 pendingFibers.push_back(std::move(promise));
422 auto iter = addTasks(funcs.begin(), funcs.end());
425 while (iter.hasNext()) {
427 EXPECT_GE(2 - n, pendingFibers.size());
434 } else if (pendingFibers.size()) {
435 pendingFibers.back().setValue(0);
436 pendingFibers.pop_back();
438 loopController.stop();
442 loopController.loop(std::move(loopFunc));
445 TEST(FiberManager, addTasksVoidThrow) {
446 std::vector<Promise<int>> pendingFibers;
447 bool taskAdded = false;
449 FiberManager manager(folly::make_unique<SimpleLoopController>());
450 auto& loopController =
451 dynamic_cast<SimpleLoopController&>(manager.loopController());
453 auto loopFunc = [&]() {
457 std::vector<std::function<void()>> funcs;
458 for (size_t i = 0; i < 3; ++i) {
460 [i, &pendingFibers]() {
461 await([&pendingFibers](Promise<int> promise) {
462 pendingFibers.push_back(std::move(promise));
465 throw std::runtime_error("");
471 auto iter = addTasks(funcs.begin(), funcs.end());
474 while (iter.hasNext()) {
477 EXPECT_EQ(1, iter.getTaskID() % 2);
479 EXPECT_EQ(0, iter.getTaskID() % 2);
481 EXPECT_GE(2 - n, pendingFibers.size());
488 } else if (pendingFibers.size()) {
489 pendingFibers.back().setValue(0);
490 pendingFibers.pop_back();
492 loopController.stop();
496 loopController.loop(std::move(loopFunc));
499 TEST(FiberManager, reserve) {
500 std::vector<Promise<int>> pendingFibers;
501 bool taskAdded = false;
503 FiberManager manager(folly::make_unique<SimpleLoopController>());
504 auto& loopController =
505 dynamic_cast<SimpleLoopController&>(manager.loopController());
507 auto loopFunc = [&]() {
511 std::vector<std::function<void()>> funcs;
512 for (size_t i = 0; i < 3; ++i) {
515 await([&pendingFibers](Promise<int> promise) {
516 pendingFibers.push_back(std::move(promise));
522 auto iter = addTasks(funcs.begin(), funcs.end());
525 EXPECT_TRUE(iter.hasCompleted());
526 EXPECT_TRUE(iter.hasPending());
527 EXPECT_TRUE(iter.hasNext());
530 EXPECT_TRUE(iter.hasCompleted());
531 EXPECT_TRUE(iter.hasPending());
532 EXPECT_TRUE(iter.hasNext());
535 EXPECT_FALSE(iter.hasCompleted());
536 EXPECT_TRUE(iter.hasPending());
537 EXPECT_TRUE(iter.hasNext());
540 EXPECT_FALSE(iter.hasCompleted());
541 EXPECT_FALSE(iter.hasPending());
542 EXPECT_FALSE(iter.hasNext());
546 } else if (pendingFibers.size()) {
547 pendingFibers.back().setValue(0);
548 pendingFibers.pop_back();
550 loopController.stop();
554 loopController.loop(std::move(loopFunc));
557 TEST(FiberManager, forEach) {
558 std::vector<Promise<int>> pendingFibers;
559 bool taskAdded = false;
561 FiberManager manager(folly::make_unique<SimpleLoopController>());
562 auto& loopController =
563 dynamic_cast<SimpleLoopController&>(manager.loopController());
565 auto loopFunc = [&]() {
569 std::vector<std::function<int()>> funcs;
570 for (size_t i = 0; i < 3; ++i) {
572 [i, &pendingFibers]() {
573 await([&pendingFibers](Promise<int> promise) {
574 pendingFibers.push_back(std::move(promise));
581 std::vector<std::pair<size_t, int>> results;
582 forEach(funcs.begin(), funcs.end(),
583 [&results](size_t id, int result) {
584 results.emplace_back(id, result);
586 EXPECT_EQ(3, results.size());
587 EXPECT_TRUE(pendingFibers.empty());
588 for (size_t i = 0; i < 3; ++i) {
589 EXPECT_EQ(results[i].first * 2 + 1, results[i].second);
594 } else if (pendingFibers.size()) {
595 pendingFibers.back().setValue(0);
596 pendingFibers.pop_back();
598 loopController.stop();
602 loopController.loop(std::move(loopFunc));
605 TEST(FiberManager, collectN) {
606 std::vector<Promise<int>> pendingFibers;
607 bool taskAdded = false;
609 FiberManager manager(folly::make_unique<SimpleLoopController>());
610 auto& loopController =
611 dynamic_cast<SimpleLoopController&>(manager.loopController());
613 auto loopFunc = [&]() {
617 std::vector<std::function<int()>> funcs;
618 for (size_t i = 0; i < 3; ++i) {
620 [i, &pendingFibers]() {
621 await([&pendingFibers](Promise<int> promise) {
622 pendingFibers.push_back(std::move(promise));
629 auto results = collectN(funcs.begin(), funcs.end(), 2);
630 EXPECT_EQ(2, results.size());
631 EXPECT_EQ(1, pendingFibers.size());
632 for (size_t i = 0; i < 2; ++i) {
633 EXPECT_EQ(results[i].first*2 + 1, results[i].second);
638 } else if (pendingFibers.size()) {
639 pendingFibers.back().setValue(0);
640 pendingFibers.pop_back();
642 loopController.stop();
646 loopController.loop(std::move(loopFunc));
649 TEST(FiberManager, collectNThrow) {
650 std::vector<Promise<int>> pendingFibers;
651 bool taskAdded = false;
653 FiberManager manager(folly::make_unique<SimpleLoopController>());
654 auto& loopController =
655 dynamic_cast<SimpleLoopController&>(manager.loopController());
657 auto loopFunc = [&]() {
661 std::vector<std::function<int()>> funcs;
662 for (size_t i = 0; i < 3; ++i) {
664 [i, &pendingFibers]() {
665 await([&pendingFibers](Promise<int> promise) {
666 pendingFibers.push_back(std::move(promise));
668 throw std::runtime_error("Runtime");
675 collectN(funcs.begin(), funcs.end(), 2);
677 EXPECT_EQ(1, pendingFibers.size());
682 } else if (pendingFibers.size()) {
683 pendingFibers.back().setValue(0);
684 pendingFibers.pop_back();
686 loopController.stop();
690 loopController.loop(std::move(loopFunc));
693 TEST(FiberManager, collectNVoid) {
694 std::vector<Promise<int>> pendingFibers;
695 bool taskAdded = false;
697 FiberManager manager(folly::make_unique<SimpleLoopController>());
698 auto& loopController =
699 dynamic_cast<SimpleLoopController&>(manager.loopController());
701 auto loopFunc = [&]() {
705 std::vector<std::function<void()>> funcs;
706 for (size_t i = 0; i < 3; ++i) {
708 [i, &pendingFibers]() {
709 await([&pendingFibers](Promise<int> promise) {
710 pendingFibers.push_back(std::move(promise));
716 auto results = collectN(funcs.begin(), funcs.end(), 2);
717 EXPECT_EQ(2, results.size());
718 EXPECT_EQ(1, pendingFibers.size());
722 } else if (pendingFibers.size()) {
723 pendingFibers.back().setValue(0);
724 pendingFibers.pop_back();
726 loopController.stop();
730 loopController.loop(std::move(loopFunc));
733 TEST(FiberManager, collectNVoidThrow) {
734 std::vector<Promise<int>> pendingFibers;
735 bool taskAdded = false;
737 FiberManager manager(folly::make_unique<SimpleLoopController>());
738 auto& loopController =
739 dynamic_cast<SimpleLoopController&>(manager.loopController());
741 auto loopFunc = [&]() {
745 std::vector<std::function<void()>> funcs;
746 for (size_t i = 0; i < 3; ++i) {
748 [i, &pendingFibers]() {
749 await([&pendingFibers](Promise<int> promise) {
750 pendingFibers.push_back(std::move(promise));
752 throw std::runtime_error("Runtime");
758 collectN(funcs.begin(), funcs.end(), 2);
760 EXPECT_EQ(1, pendingFibers.size());
765 } else if (pendingFibers.size()) {
766 pendingFibers.back().setValue(0);
767 pendingFibers.pop_back();
769 loopController.stop();
773 loopController.loop(std::move(loopFunc));
776 TEST(FiberManager, collectAll) {
777 std::vector<Promise<int>> pendingFibers;
778 bool taskAdded = false;
780 FiberManager manager(folly::make_unique<SimpleLoopController>());
781 auto& loopController =
782 dynamic_cast<SimpleLoopController&>(manager.loopController());
784 auto loopFunc = [&]() {
788 std::vector<std::function<int()>> funcs;
789 for (size_t i = 0; i < 3; ++i) {
791 [i, &pendingFibers]() {
792 await([&pendingFibers](Promise<int> promise) {
793 pendingFibers.push_back(std::move(promise));
800 auto results = collectAll(funcs.begin(), funcs.end());
801 EXPECT_TRUE(pendingFibers.empty());
802 for (size_t i = 0; i < 3; ++i) {
803 EXPECT_EQ(i*2+1, results[i]);
808 } else if (pendingFibers.size()) {
809 pendingFibers.back().setValue(0);
810 pendingFibers.pop_back();
812 loopController.stop();
816 loopController.loop(std::move(loopFunc));
819 TEST(FiberManager, collectAllVoid) {
820 std::vector<Promise<int>> pendingFibers;
821 bool taskAdded = false;
823 FiberManager manager(folly::make_unique<SimpleLoopController>());
824 auto& loopController =
825 dynamic_cast<SimpleLoopController&>(manager.loopController());
827 auto loopFunc = [&]() {
831 std::vector<std::function<void()>> funcs;
832 for (size_t i = 0; i < 3; ++ i) {
834 [i, &pendingFibers]() {
835 await([&pendingFibers](Promise<int> promise) {
836 pendingFibers.push_back(std::move(promise));
842 collectAll(funcs.begin(), funcs.end());
843 EXPECT_TRUE(pendingFibers.empty());
847 } else if (pendingFibers.size()) {
848 pendingFibers.back().setValue(0);
849 pendingFibers.pop_back();
851 loopController.stop();
855 loopController.loop(std::move(loopFunc));
858 TEST(FiberManager, collectAny) {
859 std::vector<Promise<int>> pendingFibers;
860 bool taskAdded = false;
862 FiberManager manager(folly::make_unique<SimpleLoopController>());
863 auto& loopController =
864 dynamic_cast<SimpleLoopController&>(manager.loopController());
866 auto loopFunc = [&]() {
870 std::vector<std::function<int()> > funcs;
871 for (size_t i = 0; i < 3; ++ i) {
873 [i, &pendingFibers]() {
874 await([&pendingFibers](Promise<int> promise) {
875 pendingFibers.push_back(std::move(promise));
878 throw std::runtime_error("This exception will be ignored");
885 auto result = collectAny(funcs.begin(), funcs.end());
886 EXPECT_EQ(2, pendingFibers.size());
887 EXPECT_EQ(2, result.first);
888 EXPECT_EQ(2*2+1, result.second);
892 } else if (pendingFibers.size()) {
893 pendingFibers.back().setValue(0);
894 pendingFibers.pop_back();
896 loopController.stop();
900 loopController.loop(std::move(loopFunc));
904 /* Checks that this function was run from a main context,
905 by comparing an address on a stack to a known main stack address
906 and a known related fiber stack address. The assumption
907 is that fiber stack and main stack will be far enough apart,
908 while any two values on the same stack will be close. */
909 void expectMainContext(bool& ran, int* mainLocation, int* fiberLocation) {
911 /* 2 pages is a good guess */
912 constexpr ssize_t DISTANCE = 0x2000 / sizeof(int);
914 EXPECT_TRUE(std::abs(&here - fiberLocation) > DISTANCE);
917 EXPECT_TRUE(std::abs(&here - mainLocation) < DISTANCE);
925 TEST(FiberManager, runInMainContext) {
926 FiberManager manager(folly::make_unique<SimpleLoopController>());
927 auto& loopController =
928 dynamic_cast<SimpleLoopController&>(manager.loopController());
930 bool checkRan = false;
933 manager.runInMainContext(
935 expectMainContext(checkRan, &mainLocation, nullptr);
937 EXPECT_TRUE(checkRan);
941 manager.addTask([&]() {
943 explicit A(int value_) : value(value_) {}
944 A(const A&) = delete;
950 auto ret = runInMainContext([&]() {
951 expectMainContext(checkRan, &mainLocation, &stackLocation);
954 EXPECT_TRUE(checkRan);
955 EXPECT_EQ(42, ret.value);
960 loopController.stop();
964 EXPECT_TRUE(checkRan);
967 TEST(FiberManager, addTaskFinally) {
968 FiberManager manager(folly::make_unique<SimpleLoopController>());
969 auto& loopController =
970 dynamic_cast<SimpleLoopController&>(manager.loopController());
972 bool checkRan = false;
976 manager.addTaskFinally(
980 [&](Try<int>&& result) {
981 EXPECT_EQ(result.value(), 1234);
983 expectMainContext(checkRan, &mainLocation, nullptr);
987 EXPECT_FALSE(checkRan);
991 loopController.stop();
995 EXPECT_TRUE(checkRan);
998 TEST(FiberManager, fibersPoolWithinLimit) {
999 FiberManager::Options opts;
1000 opts.maxFibersPoolSize = 5;
1002 FiberManager manager(folly::make_unique<SimpleLoopController>(), opts);
1003 auto& loopController =
1004 dynamic_cast<SimpleLoopController&>(manager.loopController());
1006 size_t fibersRun = 0;
1008 for (size_t i = 0; i < 5; ++i) {
1015 loopController.loop(
1017 loopController.stop();
1021 EXPECT_EQ(5, fibersRun);
1022 EXPECT_EQ(5, manager.fibersAllocated());
1023 EXPECT_EQ(5, manager.fibersPoolSize());
1025 for (size_t i = 0; i < 5; ++i) {
1032 loopController.loop(
1034 loopController.stop();
1038 EXPECT_EQ(10, fibersRun);
1039 EXPECT_EQ(5, manager.fibersAllocated());
1040 EXPECT_EQ(5, manager.fibersPoolSize());
1043 TEST(FiberManager, fibersPoolOverLimit) {
1044 FiberManager::Options opts;
1045 opts.maxFibersPoolSize = 5;
1047 FiberManager manager(folly::make_unique<SimpleLoopController>(), opts);
1048 auto& loopController =
1049 dynamic_cast<SimpleLoopController&>(manager.loopController());
1051 size_t fibersRun = 0;
1053 for (size_t i = 0; i < 10; ++i) {
1061 EXPECT_EQ(0, fibersRun);
1062 EXPECT_EQ(10, manager.fibersAllocated());
1063 EXPECT_EQ(0, manager.fibersPoolSize());
1065 loopController.loop(
1067 loopController.stop();
1071 EXPECT_EQ(10, fibersRun);
1072 EXPECT_EQ(5, manager.fibersAllocated());
1073 EXPECT_EQ(5, manager.fibersPoolSize());
1076 TEST(FiberManager, remoteFiberBasic) {
1077 FiberManager manager(folly::make_unique<SimpleLoopController>());
1078 auto& loopController =
1079 dynamic_cast<SimpleLoopController&>(manager.loopController());
1082 result[0] = result[1] = 0;
1083 folly::Optional<Promise<int>> savedPromise[2];
1086 result[0] = await([&] (Promise<int> promise) {
1087 savedPromise[0] = std::move(promise);
1092 result[1] = await([&] (Promise<int> promise) {
1093 savedPromise[1] = std::move(promise);
1097 manager.loopUntilNoReady();
1099 EXPECT_TRUE(savedPromise[0].hasValue());
1100 EXPECT_TRUE(savedPromise[1].hasValue());
1101 EXPECT_EQ(0, result[0]);
1102 EXPECT_EQ(0, result[1]);
1104 std::thread remoteThread0{
1106 savedPromise[0]->setValue(42);
1109 std::thread remoteThread1{
1111 savedPromise[1]->setValue(43);
1114 remoteThread0.join();
1115 remoteThread1.join();
1116 EXPECT_EQ(0, result[0]);
1117 EXPECT_EQ(0, result[1]);
1118 /* Should only have scheduled once */
1119 EXPECT_EQ(1, loopController.remoteScheduleCalled());
1121 manager.loopUntilNoReady();
1122 EXPECT_EQ(42, result[0]);
1123 EXPECT_EQ(43, result[1]);
1126 TEST(FiberManager, addTaskRemoteBasic) {
1127 FiberManager manager(folly::make_unique<SimpleLoopController>());
1130 result[0] = result[1] = 0;
1131 folly::Optional<Promise<int>> savedPromise[2];
1133 std::thread remoteThread0{
1135 manager.addTaskRemote(
1137 result[0] = await([&] (Promise<int> promise) {
1138 savedPromise[0] = std::move(promise);
1143 std::thread remoteThread1{
1145 manager.addTaskRemote(
1147 result[1] = await([&] (Promise<int> promise) {
1148 savedPromise[1] = std::move(promise);
1153 remoteThread0.join();
1154 remoteThread1.join();
1156 manager.loopUntilNoReady();
1158 EXPECT_TRUE(savedPromise[0].hasValue());
1159 EXPECT_TRUE(savedPromise[1].hasValue());
1160 EXPECT_EQ(0, result[0]);
1161 EXPECT_EQ(0, result[1]);
1163 savedPromise[0]->setValue(42);
1164 savedPromise[1]->setValue(43);
1166 EXPECT_EQ(0, result[0]);
1167 EXPECT_EQ(0, result[1]);
1169 manager.loopUntilNoReady();
1170 EXPECT_EQ(42, result[0]);
1171 EXPECT_EQ(43, result[1]);
1174 TEST(FiberManager, remoteHasTasks) {
1176 FiberManager fm(folly::make_unique<SimpleLoopController>());
1177 std::thread remote([&]() {
1178 fm.addTaskRemote([&]() {
1185 while (fm.hasTasks()) {
1186 fm.loopUntilNoReady();
1189 EXPECT_FALSE(fm.hasTasks());
1190 EXPECT_EQ(counter, 1);
1193 TEST(FiberManager, remoteHasReadyTasks) {
1195 folly::Optional<Promise<int>> savedPromise;
1196 FiberManager fm(folly::make_unique<SimpleLoopController>());
1197 std::thread remote([&]() {
1198 fm.addTaskRemote([&]() {
1199 result = await([&](Promise<int> promise) {
1200 savedPromise = std::move(promise);
1202 EXPECT_TRUE(fm.hasTasks());
1207 EXPECT_TRUE(fm.hasTasks());
1209 fm.loopUntilNoReady();
1210 EXPECT_TRUE(fm.hasTasks());
1212 std::thread remote2([&](){
1213 savedPromise->setValue(47);
1216 EXPECT_TRUE(fm.hasTasks());
1218 fm.loopUntilNoReady();
1219 EXPECT_FALSE(fm.hasTasks());
1221 EXPECT_EQ(result, 47);
1224 template <typename Data>
1225 void testFiberLocal() {
1226 FiberManager fm(LocalType<Data>(),
1227 folly::make_unique<SimpleLoopController>());
1230 EXPECT_EQ(42, local<Data>().value);
1232 local<Data>().value = 43;
1235 EXPECT_EQ(43, local<Data>().value);
1237 local<Data>().value = 44;
1240 EXPECT_EQ(44, local<Data>().value);
1246 EXPECT_EQ(42, local<Data>().value);
1248 local<Data>().value = 43;
1250 fm.addTaskRemote([]() {
1251 EXPECT_EQ(43, local<Data>().value);
1256 EXPECT_EQ(42, local<Data>().value);
1257 local<Data>().value = 43;
1260 EXPECT_EQ(43, local<Data>().value);
1261 local<Data>().value = 44;
1263 std::vector<std::function<void()>> tasks{task};
1264 collectAny(tasks.begin(), tasks.end());
1266 EXPECT_EQ(43, local<Data>().value);
1269 fm.loopUntilNoReady();
1270 EXPECT_FALSE(fm.hasTasks());
1273 TEST(FiberManager, fiberLocal) {
1278 testFiberLocal<SimpleData>();
1281 TEST(FiberManager, fiberLocalHeap) {
1287 testFiberLocal<LargeData>();
1290 TEST(FiberManager, fiberLocalDestructor) {
1297 EXPECT_EQ(42, local<CrazyData>().data);
1298 // Make sure we don't have infinite loop
1299 local<CrazyData>().data = 0;
1305 FiberManager fm(LocalType<CrazyData>(),
1306 folly::make_unique<SimpleLoopController>());
1309 local<CrazyData>().data = 41;
1312 fm.loopUntilNoReady();
1313 EXPECT_FALSE(fm.hasTasks());
1316 TEST(FiberManager, yieldTest) {
1317 FiberManager manager(folly::make_unique<SimpleLoopController>());
1318 auto& loopController =
1319 dynamic_cast<SimpleLoopController&>(manager.loopController());
1321 bool checkRan = false;
1330 loopController.loop(
1333 loopController.stop();
1338 EXPECT_TRUE(checkRan);
1341 TEST(FiberManager, RequestContext) {
1342 FiberManager fm(folly::make_unique<SimpleLoopController>());
1344 bool checkRun1 = false;
1345 bool checkRun2 = false;
1346 bool checkRun3 = false;
1348 folly::fibers::Baton baton1;
1349 folly::fibers::Baton baton2;
1350 folly::fibers::Baton baton3;
1352 folly::RequestContext::create();
1353 auto rcontext1 = folly::RequestContext::get();
1355 EXPECT_EQ(rcontext1, folly::RequestContext::get());
1357 EXPECT_EQ(rcontext1, folly::RequestContext::get());
1359 EXPECT_EQ(rcontext1, folly::RequestContext::get());
1360 runInMainContext([&]() {
1361 EXPECT_EQ(rcontext1, folly::RequestContext::get());
1366 folly::RequestContext::create();
1367 auto rcontext2 = folly::RequestContext::get();
1368 fm.addTaskRemote([&]() {
1369 EXPECT_EQ(rcontext2, folly::RequestContext::get());
1371 EXPECT_EQ(rcontext2, folly::RequestContext::get());
1375 folly::RequestContext::create();
1376 auto rcontext3 = folly::RequestContext::get();
1379 EXPECT_EQ(rcontext3, folly::RequestContext::get());
1381 EXPECT_EQ(rcontext3, folly::RequestContext::get());
1383 return folly::Unit();
1385 [&](Try<folly::Unit>&& /* t */) {
1386 EXPECT_EQ(rcontext3, folly::RequestContext::get());
1390 folly::RequestContext::create();
1391 auto rcontext = folly::RequestContext::get();
1393 fm.loopUntilNoReady();
1394 EXPECT_EQ(rcontext, folly::RequestContext::get());
1397 EXPECT_EQ(rcontext, folly::RequestContext::get());
1398 fm.loopUntilNoReady();
1399 EXPECT_TRUE(checkRun1);
1400 EXPECT_EQ(rcontext, folly::RequestContext::get());
1403 EXPECT_EQ(rcontext, folly::RequestContext::get());
1404 fm.loopUntilNoReady();
1405 EXPECT_TRUE(checkRun2);
1406 EXPECT_EQ(rcontext, folly::RequestContext::get());
1409 EXPECT_EQ(rcontext, folly::RequestContext::get());
1410 fm.loopUntilNoReady();
1411 EXPECT_TRUE(checkRun3);
1412 EXPECT_EQ(rcontext, folly::RequestContext::get());
1415 TEST(FiberManager, resizePeriodically) {
1416 FiberManager::Options opts;
1417 opts.fibersPoolResizePeriodMs = 300;
1418 opts.maxFibersPoolSize = 5;
1420 FiberManager manager(folly::make_unique<EventBaseLoopController>(), opts);
1422 folly::EventBase evb;
1423 dynamic_cast<EventBaseLoopController&>(manager.loopController())
1424 .attachEventBase(evb);
1426 std::vector<Baton> batons(10);
1428 size_t tasksRun = 0;
1429 for (size_t i = 0; i < 30; ++i) {
1430 manager.addTask([i, &batons, &tasksRun]() {
1432 // Keep some fibers active indefinitely
1433 if (i < batons.size()) {
1439 EXPECT_EQ(0, tasksRun);
1440 EXPECT_EQ(30, manager.fibersAllocated());
1441 EXPECT_EQ(0, manager.fibersPoolSize());
1444 EXPECT_EQ(30, tasksRun);
1445 EXPECT_EQ(30, manager.fibersAllocated());
1446 // Can go over maxFibersPoolSize, 10 of 30 fibers still active
1447 EXPECT_EQ(20, manager.fibersPoolSize());
1449 std::this_thread::sleep_for(std::chrono::milliseconds(400));
1450 evb.loopOnce(); // no fibers active in this period
1451 EXPECT_EQ(30, manager.fibersAllocated());
1452 EXPECT_EQ(20, manager.fibersPoolSize());
1454 std::this_thread::sleep_for(std::chrono::milliseconds(400));
1455 evb.loopOnce(); // should shrink fibers pool to maxFibersPoolSize
1456 EXPECT_EQ(15, manager.fibersAllocated());
1457 EXPECT_EQ(5, manager.fibersPoolSize());
1459 for (size_t i = 0; i < batons.size(); ++i) {
1463 EXPECT_EQ(15, manager.fibersAllocated());
1464 EXPECT_EQ(15, manager.fibersPoolSize());
1466 std::this_thread::sleep_for(std::chrono::milliseconds(400));
1467 evb.loopOnce(); // 10 fibers active in last period
1468 EXPECT_EQ(10, manager.fibersAllocated());
1469 EXPECT_EQ(10, manager.fibersPoolSize());
1471 std::this_thread::sleep_for(std::chrono::milliseconds(400));
1473 EXPECT_EQ(5, manager.fibersAllocated());
1474 EXPECT_EQ(5, manager.fibersPoolSize());
1477 TEST(FiberManager, batonWaitTimeoutHandler) {
1478 FiberManager manager(folly::make_unique<EventBaseLoopController>());
1480 folly::EventBase evb;
1481 dynamic_cast<EventBaseLoopController&>(manager.loopController())
1482 .attachEventBase(evb);
1484 size_t fibersRun = 0;
1486 Baton::TimeoutHandler timeoutHandler;
1488 manager.addTask([&]() {
1489 baton.wait(timeoutHandler);
1492 manager.loopUntilNoReady();
1494 EXPECT_FALSE(baton.try_wait());
1495 EXPECT_EQ(0, fibersRun);
1497 timeoutHandler.scheduleTimeout(std::chrono::milliseconds(250));
1498 std::this_thread::sleep_for(std::chrono::milliseconds(500));
1500 EXPECT_FALSE(baton.try_wait());
1501 EXPECT_EQ(0, fibersRun);
1504 manager.loopUntilNoReady();
1506 EXPECT_EQ(1, fibersRun);
1509 TEST(FiberManager, batonWaitTimeoutMany) {
1510 FiberManager manager(folly::make_unique<EventBaseLoopController>());
1512 folly::EventBase evb;
1513 dynamic_cast<EventBaseLoopController&>(manager.loopController())
1514 .attachEventBase(evb);
1516 constexpr size_t kNumTimeoutTasks = 10000;
1517 size_t tasksCount = kNumTimeoutTasks;
1519 // We add many tasks to hit timeout queue deallocation logic.
1520 for (size_t i = 0; i < kNumTimeoutTasks; ++i) {
1521 manager.addTask([&]() {
1523 Baton::TimeoutHandler timeoutHandler;
1525 folly::fibers::addTask([&] {
1526 timeoutHandler.scheduleTimeout(std::chrono::milliseconds(1000));
1529 baton.wait(timeoutHandler);
1530 if (--tasksCount == 0) {
1531 evb.terminateLoopSoon();
1539 TEST(FiberManager, remoteFutureTest) {
1540 FiberManager fiberManager(folly::make_unique<SimpleLoopController>());
1541 auto& loopController =
1542 dynamic_cast<SimpleLoopController&>(fiberManager.loopController());
1546 auto f1 = fiberManager.addTaskFuture([&]() { return testValue1; });
1547 auto f2 = fiberManager.addTaskRemoteFuture([&]() { return testValue2; });
1548 loopController.loop([&]() { loopController.stop(); });
1552 EXPECT_EQ(v1, testValue1);
1553 EXPECT_EQ(v2, testValue2);
1556 TEST(FiberManager, nestedFiberManagers) {
1557 folly::EventBase outerEvb;
1558 folly::EventBase innerEvb;
1560 getFiberManager(outerEvb).addTask([&]() {
1561 EXPECT_EQ(&getFiberManager(outerEvb),
1562 FiberManager::getFiberManagerUnsafe());
1564 runInMainContext([&]() {
1565 getFiberManager(innerEvb).addTask([&]() {
1566 EXPECT_EQ(&getFiberManager(innerEvb),
1567 FiberManager::getFiberManagerUnsafe());
1569 innerEvb.terminateLoopSoon();
1572 innerEvb.loopForever();
1575 EXPECT_EQ(&getFiberManager(outerEvb),
1576 FiberManager::getFiberManagerUnsafe());
1578 outerEvb.terminateLoopSoon();
1581 outerEvb.loopForever();
1584 static size_t sNumAwaits;
1586 void runBenchmark(size_t numAwaits, size_t toSend) {
1587 sNumAwaits = numAwaits;
1589 FiberManager fiberManager(folly::make_unique<SimpleLoopController>());
1590 auto& loopController =
1591 dynamic_cast<SimpleLoopController&>(fiberManager.loopController());
1593 std::queue<Promise<int>> pendingRequests;
1594 static const size_t maxOutstanding = 5;
1596 auto loop = [&fiberManager, &loopController, &pendingRequests, &toSend]() {
1597 if (pendingRequests.size() == maxOutstanding || toSend == 0) {
1598 if (pendingRequests.empty()) {
1601 pendingRequests.front().setValue(0);
1602 pendingRequests.pop();
1604 fiberManager.addTask([&pendingRequests]() {
1605 for (size_t i = 0; i < sNumAwaits; ++i) {
1606 auto result = await(
1607 [&pendingRequests](Promise<int> promise) {
1608 pendingRequests.push(std::move(promise));
1610 DCHECK_EQ(result, 0);
1614 if (--toSend == 0) {
1615 loopController.stop();
1620 loopController.loop(std::move(loop));
1623 BENCHMARK(FiberManagerBasicOneAwait, iters) {
1624 runBenchmark(1, iters);
1627 BENCHMARK(FiberManagerBasicFiveAwaits, iters) {
1628 runBenchmark(5, iters);
1631 BENCHMARK(FiberManagerAllocateDeallocatePattern, iters) {
1632 static const size_t kNumAllocations = 10000;
1634 FiberManager::Options opts;
1635 opts.maxFibersPoolSize = 0;
1637 FiberManager fiberManager(folly::make_unique<SimpleLoopController>(), opts);
1639 for (size_t iter = 0; iter < iters; ++iter) {
1640 EXPECT_EQ(0, fiberManager.fibersPoolSize());
1642 size_t fibersRun = 0;
1644 for (size_t i = 0; i < kNumAllocations; ++i) {
1645 fiberManager.addTask(
1650 fiberManager.loopUntilNoReady();
1653 EXPECT_EQ(10000, fibersRun);
1654 EXPECT_EQ(0, fiberManager.fibersPoolSize());
1658 BENCHMARK(FiberManagerAllocateLargeChunk, iters) {
1659 static const size_t kNumAllocations = 10000;
1661 FiberManager::Options opts;
1662 opts.maxFibersPoolSize = 0;
1664 FiberManager fiberManager(folly::make_unique<SimpleLoopController>(), opts);
1666 for (size_t iter = 0; iter < iters; ++iter) {
1667 EXPECT_EQ(0, fiberManager.fibersPoolSize());
1669 size_t fibersRun = 0;
1671 for (size_t i = 0; i < kNumAllocations; ++i) {
1672 fiberManager.addTask(
1679 fiberManager.loopUntilNoReady();
1681 EXPECT_EQ(10000, fibersRun);
1682 EXPECT_EQ(0, fiberManager.fibersPoolSize());