2 * Copyright 2015 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/GenericBaton.h>
30 #include <folly/experimental/fibers/SimpleLoopController.h>
31 #include <folly/experimental/fibers/WhenN.h>
33 using namespace folly::fibers;
37 TEST(FiberManager, batonTimedWaitTimeout) {
38 bool taskAdded = false;
39 size_t iterations = 0;
41 FiberManager manager(folly::make_unique<SimpleLoopController>());
42 auto& loopController =
43 dynamic_cast<SimpleLoopController&>(manager.loopController());
45 auto loopFunc = [&]() {
51 auto res = baton.timed_wait(std::chrono::milliseconds(230));
54 EXPECT_EQ(5, iterations);
56 loopController.stop();
63 auto res = baton.timed_wait(std::chrono::milliseconds(130));
66 EXPECT_EQ(3, iterations);
68 loopController.stop();
73 std::this_thread::sleep_for(std::chrono::milliseconds(50));
78 loopController.loop(std::move(loopFunc));
81 TEST(FiberManager, batonTimedWaitPost) {
82 bool taskAdded = false;
83 size_t iterations = 0;
86 FiberManager manager(folly::make_unique<SimpleLoopController>());
87 auto& loopController =
88 dynamic_cast<SimpleLoopController&>(manager.loopController());
90 auto loopFunc = [&]() {
97 auto res = baton.timed_wait(std::chrono::milliseconds(130));
100 EXPECT_EQ(2, iterations);
102 loopController.stop();
107 std::this_thread::sleep_for(std::chrono::milliseconds(50));
109 if (iterations == 2) {
115 loopController.loop(std::move(loopFunc));
118 TEST(FiberManager, batonTimedWaitTimeoutEvb) {
119 size_t tasksComplete = 0;
121 folly::EventBase evb;
123 FiberManager manager(folly::make_unique<EventBaseLoopController>());
124 dynamic_cast<EventBaseLoopController&>(
125 manager.loopController()).attachEventBase(evb);
127 auto task = [&](size_t timeout_ms) {
130 auto start = EventBaseLoopController::Clock::now();
131 auto res = baton.timed_wait(std::chrono::milliseconds(timeout_ms));
132 auto finish = EventBaseLoopController::Clock::now();
137 std::chrono::duration_cast<std::chrono::milliseconds>(finish - start);
139 EXPECT_GT(duration_ms.count(), timeout_ms - 50);
140 EXPECT_LT(duration_ms.count(), timeout_ms + 50);
142 if (++tasksComplete == 2) {
143 evb.terminateLoopSoon();
147 evb.runInEventBaseThread([&]() {
162 EXPECT_EQ(2, tasksComplete);
165 TEST(FiberManager, batonTimedWaitPostEvb) {
166 size_t tasksComplete = 0;
168 folly::EventBase evb;
170 FiberManager manager(folly::make_unique<EventBaseLoopController>());
171 dynamic_cast<EventBaseLoopController&>(
172 manager.loopController()).attachEventBase(evb);
174 evb.runInEventBaseThread([&]() {
175 manager.addTask([&]() {
178 evb.tryRunAfterDelay([&]() {
183 auto start = EventBaseLoopController::Clock::now();
184 auto res = baton.timed_wait(std::chrono::milliseconds(130));
185 auto finish = EventBaseLoopController::Clock::now();
189 auto duration_ms = std::chrono::duration_cast<
190 std::chrono::milliseconds>(finish - start);
192 EXPECT_TRUE(duration_ms.count() > 95 &&
193 duration_ms.count() < 110);
195 if (++tasksComplete == 1) {
196 evb.terminateLoopSoon();
203 EXPECT_EQ(1, tasksComplete);
206 TEST(FiberManager, batonTryWait) {
208 FiberManager manager(folly::make_unique<SimpleLoopController>());
210 // Check if try_wait and post work as expected
213 manager.addTask([&](){
214 while (!b.try_wait()) {
217 auto thr = std::thread([&](){
218 std::this_thread::sleep_for(std::chrono::milliseconds(300));
222 manager.loopUntilNoReady();
227 // Check try_wait without post
228 manager.addTask([&](){
230 while (cnt && !c.try_wait()) {
233 EXPECT_TRUE(!c.try_wait()); // must still hold
237 manager.loopUntilNoReady();
240 TEST(FiberManager, genericBatonFiberWait) {
241 FiberManager manager(folly::make_unique<SimpleLoopController>());
244 bool fiberRunning = false;
246 manager.addTask([&](){
247 EXPECT_EQ(manager.hasActiveFiber(), true);
250 fiberRunning = false;
253 EXPECT_FALSE(fiberRunning);
254 manager.loopUntilNoReady();
255 EXPECT_TRUE(fiberRunning); // ensure fiber still active
257 auto thr = std::thread([&](){
258 std::this_thread::sleep_for(std::chrono::milliseconds(300));
262 while (fiberRunning) {
263 manager.loopUntilNoReady();
269 TEST(FiberManager, genericBatonThreadWait) {
270 FiberManager manager(folly::make_unique<SimpleLoopController>());
272 std::atomic<bool> threadWaiting(false);
274 auto thr = std::thread([&](){
275 threadWaiting = true;
277 threadWaiting = false;
280 while (!threadWaiting) {}
281 std::this_thread::sleep_for(std::chrono::milliseconds(300));
283 manager.addTask([&](){
284 EXPECT_EQ(manager.hasActiveFiber(), true);
285 EXPECT_TRUE(threadWaiting);
287 while(threadWaiting) {}
290 manager.loopUntilNoReady();
294 TEST(FiberManager, addTasksNoncopyable) {
295 std::vector<Promise<int>> pendingFibers;
296 bool taskAdded = false;
298 FiberManager manager(folly::make_unique<SimpleLoopController>());
299 auto& loopController =
300 dynamic_cast<SimpleLoopController&>(manager.loopController());
302 auto loopFunc = [&]() {
306 std::vector<std::function<std::unique_ptr<int>()>> funcs;
307 for (size_t i = 0; i < 3; ++i) {
309 [i, &pendingFibers]() {
310 await([&pendingFibers](Promise<int> promise) {
311 pendingFibers.push_back(std::move(promise));
313 return folly::make_unique<int>(i*2 + 1);
318 auto iter = addTasks(funcs.begin(), funcs.end());
321 while (iter.hasNext()) {
322 auto result = iter.awaitNext();
323 EXPECT_EQ(2 * iter.getTaskID() + 1, *result);
324 EXPECT_GE(2 - n, pendingFibers.size());
331 } else if (pendingFibers.size()) {
332 pendingFibers.back().setValue(0);
333 pendingFibers.pop_back();
335 loopController.stop();
339 loopController.loop(std::move(loopFunc));
342 TEST(FiberManager, addTasksThrow) {
343 std::vector<Promise<int>> pendingFibers;
344 bool taskAdded = false;
346 FiberManager manager(folly::make_unique<SimpleLoopController>());
347 auto& loopController =
348 dynamic_cast<SimpleLoopController&>(manager.loopController());
350 auto loopFunc = [&]() {
354 std::vector<std::function<int()>> funcs;
355 for (size_t i = 0; i < 3; ++i) {
357 [i, &pendingFibers]() {
358 await([&pendingFibers](Promise<int> promise) {
359 pendingFibers.push_back(std::move(promise));
362 throw std::runtime_error("Runtime");
369 auto iter = addTasks(funcs.begin(), funcs.end());
372 while (iter.hasNext()) {
374 int result = iter.awaitNext();
375 EXPECT_EQ(1, iter.getTaskID() % 2);
376 EXPECT_EQ(2 * iter.getTaskID() + 1, result);
378 EXPECT_EQ(0, iter.getTaskID() % 2);
380 EXPECT_GE(2 - n, pendingFibers.size());
387 } else if (pendingFibers.size()) {
388 pendingFibers.back().setValue(0);
389 pendingFibers.pop_back();
391 loopController.stop();
395 loopController.loop(std::move(loopFunc));
398 TEST(FiberManager, addTasksVoid) {
399 std::vector<Promise<int>> pendingFibers;
400 bool taskAdded = false;
402 FiberManager manager(folly::make_unique<SimpleLoopController>());
403 auto& loopController =
404 dynamic_cast<SimpleLoopController&>(manager.loopController());
406 auto loopFunc = [&]() {
410 std::vector<std::function<void()>> funcs;
411 for (size_t i = 0; i < 3; ++i) {
413 [i, &pendingFibers]() {
414 await([&pendingFibers](Promise<int> promise) {
415 pendingFibers.push_back(std::move(promise));
421 auto iter = addTasks(funcs.begin(), funcs.end());
424 while (iter.hasNext()) {
426 EXPECT_GE(2 - n, pendingFibers.size());
433 } else if (pendingFibers.size()) {
434 pendingFibers.back().setValue(0);
435 pendingFibers.pop_back();
437 loopController.stop();
441 loopController.loop(std::move(loopFunc));
444 TEST(FiberManager, addTasksVoidThrow) {
445 std::vector<Promise<int>> pendingFibers;
446 bool taskAdded = false;
448 FiberManager manager(folly::make_unique<SimpleLoopController>());
449 auto& loopController =
450 dynamic_cast<SimpleLoopController&>(manager.loopController());
452 auto loopFunc = [&]() {
456 std::vector<std::function<void()>> funcs;
457 for (size_t i = 0; i < 3; ++i) {
459 [i, &pendingFibers]() {
460 await([&pendingFibers](Promise<int> promise) {
461 pendingFibers.push_back(std::move(promise));
464 throw std::runtime_error("");
470 auto iter = addTasks(funcs.begin(), funcs.end());
473 while (iter.hasNext()) {
476 EXPECT_EQ(1, iter.getTaskID() % 2);
478 EXPECT_EQ(0, iter.getTaskID() % 2);
480 EXPECT_GE(2 - n, pendingFibers.size());
487 } else if (pendingFibers.size()) {
488 pendingFibers.back().setValue(0);
489 pendingFibers.pop_back();
491 loopController.stop();
495 loopController.loop(std::move(loopFunc));
498 TEST(FiberManager, reserve) {
499 std::vector<Promise<int>> pendingFibers;
500 bool taskAdded = false;
502 FiberManager manager(folly::make_unique<SimpleLoopController>());
503 auto& loopController =
504 dynamic_cast<SimpleLoopController&>(manager.loopController());
506 auto loopFunc = [&]() {
510 std::vector<std::function<void()>> funcs;
511 for (size_t i = 0; i < 3; ++i) {
514 await([&pendingFibers](Promise<int> promise) {
515 pendingFibers.push_back(std::move(promise));
521 auto iter = addTasks(funcs.begin(), funcs.end());
524 EXPECT_TRUE(iter.hasCompleted());
525 EXPECT_TRUE(iter.hasPending());
526 EXPECT_TRUE(iter.hasNext());
529 EXPECT_TRUE(iter.hasCompleted());
530 EXPECT_TRUE(iter.hasPending());
531 EXPECT_TRUE(iter.hasNext());
534 EXPECT_FALSE(iter.hasCompleted());
535 EXPECT_TRUE(iter.hasPending());
536 EXPECT_TRUE(iter.hasNext());
539 EXPECT_FALSE(iter.hasCompleted());
540 EXPECT_FALSE(iter.hasPending());
541 EXPECT_FALSE(iter.hasNext());
545 } else if (pendingFibers.size()) {
546 pendingFibers.back().setValue(0);
547 pendingFibers.pop_back();
549 loopController.stop();
553 loopController.loop(std::move(loopFunc));
556 TEST(FiberManager, forEach) {
557 std::vector<Promise<int>> pendingFibers;
558 bool taskAdded = false;
560 FiberManager manager(folly::make_unique<SimpleLoopController>());
561 auto& loopController =
562 dynamic_cast<SimpleLoopController&>(manager.loopController());
564 auto loopFunc = [&]() {
568 std::vector<std::function<int()>> funcs;
569 for (size_t i = 0; i < 3; ++i) {
571 [i, &pendingFibers]() {
572 await([&pendingFibers](Promise<int> promise) {
573 pendingFibers.push_back(std::move(promise));
580 std::vector<std::pair<size_t, int>> results;
581 forEach(funcs.begin(), funcs.end(),
582 [&results](size_t id, int result) {
583 results.emplace_back(id, result);
585 EXPECT_EQ(3, results.size());
586 EXPECT_TRUE(pendingFibers.empty());
587 for (size_t i = 0; i < 3; ++i) {
588 EXPECT_EQ(results[i].first * 2 + 1, results[i].second);
593 } else if (pendingFibers.size()) {
594 pendingFibers.back().setValue(0);
595 pendingFibers.pop_back();
597 loopController.stop();
601 loopController.loop(std::move(loopFunc));
604 TEST(FiberManager, collectN) {
605 std::vector<Promise<int>> pendingFibers;
606 bool taskAdded = false;
608 FiberManager manager(folly::make_unique<SimpleLoopController>());
609 auto& loopController =
610 dynamic_cast<SimpleLoopController&>(manager.loopController());
612 auto loopFunc = [&]() {
616 std::vector<std::function<int()>> funcs;
617 for (size_t i = 0; i < 3; ++i) {
619 [i, &pendingFibers]() {
620 await([&pendingFibers](Promise<int> promise) {
621 pendingFibers.push_back(std::move(promise));
628 auto results = collectN(funcs.begin(), funcs.end(), 2);
629 EXPECT_EQ(2, results.size());
630 EXPECT_EQ(1, pendingFibers.size());
631 for (size_t i = 0; i < 2; ++i) {
632 EXPECT_EQ(results[i].first*2 + 1, results[i].second);
637 } else if (pendingFibers.size()) {
638 pendingFibers.back().setValue(0);
639 pendingFibers.pop_back();
641 loopController.stop();
645 loopController.loop(std::move(loopFunc));
648 TEST(FiberManager, collectNThrow) {
649 std::vector<Promise<int>> pendingFibers;
650 bool taskAdded = false;
652 FiberManager manager(folly::make_unique<SimpleLoopController>());
653 auto& loopController =
654 dynamic_cast<SimpleLoopController&>(manager.loopController());
656 auto loopFunc = [&]() {
660 std::vector<std::function<int()>> funcs;
661 for (size_t i = 0; i < 3; ++i) {
663 [i, &pendingFibers]() {
664 await([&pendingFibers](Promise<int> promise) {
665 pendingFibers.push_back(std::move(promise));
667 throw std::runtime_error("Runtime");
674 collectN(funcs.begin(), funcs.end(), 2);
676 EXPECT_EQ(1, pendingFibers.size());
681 } else if (pendingFibers.size()) {
682 pendingFibers.back().setValue(0);
683 pendingFibers.pop_back();
685 loopController.stop();
689 loopController.loop(std::move(loopFunc));
692 TEST(FiberManager, collectNVoid) {
693 std::vector<Promise<int>> pendingFibers;
694 bool taskAdded = false;
696 FiberManager manager(folly::make_unique<SimpleLoopController>());
697 auto& loopController =
698 dynamic_cast<SimpleLoopController&>(manager.loopController());
700 auto loopFunc = [&]() {
704 std::vector<std::function<void()>> funcs;
705 for (size_t i = 0; i < 3; ++i) {
707 [i, &pendingFibers]() {
708 await([&pendingFibers](Promise<int> promise) {
709 pendingFibers.push_back(std::move(promise));
715 auto results = collectN(funcs.begin(), funcs.end(), 2);
716 EXPECT_EQ(2, results.size());
717 EXPECT_EQ(1, pendingFibers.size());
721 } else if (pendingFibers.size()) {
722 pendingFibers.back().setValue(0);
723 pendingFibers.pop_back();
725 loopController.stop();
729 loopController.loop(std::move(loopFunc));
732 TEST(FiberManager, collectNVoidThrow) {
733 std::vector<Promise<int>> pendingFibers;
734 bool taskAdded = false;
736 FiberManager manager(folly::make_unique<SimpleLoopController>());
737 auto& loopController =
738 dynamic_cast<SimpleLoopController&>(manager.loopController());
740 auto loopFunc = [&]() {
744 std::vector<std::function<void()>> funcs;
745 for (size_t i = 0; i < 3; ++i) {
747 [i, &pendingFibers]() {
748 await([&pendingFibers](Promise<int> promise) {
749 pendingFibers.push_back(std::move(promise));
751 throw std::runtime_error("Runtime");
757 collectN(funcs.begin(), funcs.end(), 2);
759 EXPECT_EQ(1, pendingFibers.size());
764 } else if (pendingFibers.size()) {
765 pendingFibers.back().setValue(0);
766 pendingFibers.pop_back();
768 loopController.stop();
772 loopController.loop(std::move(loopFunc));
775 TEST(FiberManager, collectAll) {
776 std::vector<Promise<int>> pendingFibers;
777 bool taskAdded = false;
779 FiberManager manager(folly::make_unique<SimpleLoopController>());
780 auto& loopController =
781 dynamic_cast<SimpleLoopController&>(manager.loopController());
783 auto loopFunc = [&]() {
787 std::vector<std::function<int()>> funcs;
788 for (size_t i = 0; i < 3; ++i) {
790 [i, &pendingFibers]() {
791 await([&pendingFibers](Promise<int> promise) {
792 pendingFibers.push_back(std::move(promise));
799 auto results = collectAll(funcs.begin(), funcs.end());
800 EXPECT_TRUE(pendingFibers.empty());
801 for (size_t i = 0; i < 3; ++i) {
802 EXPECT_EQ(i*2+1, results[i]);
807 } else if (pendingFibers.size()) {
808 pendingFibers.back().setValue(0);
809 pendingFibers.pop_back();
811 loopController.stop();
815 loopController.loop(std::move(loopFunc));
818 TEST(FiberManager, collectAllVoid) {
819 std::vector<Promise<int>> pendingFibers;
820 bool taskAdded = false;
822 FiberManager manager(folly::make_unique<SimpleLoopController>());
823 auto& loopController =
824 dynamic_cast<SimpleLoopController&>(manager.loopController());
826 auto loopFunc = [&]() {
830 std::vector<std::function<void()>> funcs;
831 for (size_t i = 0; i < 3; ++ i) {
833 [i, &pendingFibers]() {
834 await([&pendingFibers](Promise<int> promise) {
835 pendingFibers.push_back(std::move(promise));
841 collectAll(funcs.begin(), funcs.end());
842 EXPECT_TRUE(pendingFibers.empty());
846 } else if (pendingFibers.size()) {
847 pendingFibers.back().setValue(0);
848 pendingFibers.pop_back();
850 loopController.stop();
854 loopController.loop(std::move(loopFunc));
857 TEST(FiberManager, collectAny) {
858 std::vector<Promise<int>> pendingFibers;
859 bool taskAdded = false;
861 FiberManager manager(folly::make_unique<SimpleLoopController>());
862 auto& loopController =
863 dynamic_cast<SimpleLoopController&>(manager.loopController());
865 auto loopFunc = [&]() {
869 std::vector<std::function<int()> > funcs;
870 for (size_t i = 0; i < 3; ++ i) {
872 [i, &pendingFibers]() {
873 await([&pendingFibers](Promise<int> promise) {
874 pendingFibers.push_back(std::move(promise));
877 throw std::runtime_error("This exception will be ignored");
884 auto result = collectAny(funcs.begin(), funcs.end());
885 EXPECT_EQ(2, pendingFibers.size());
886 EXPECT_EQ(2, result.first);
887 EXPECT_EQ(2*2+1, result.second);
891 } else if (pendingFibers.size()) {
892 pendingFibers.back().setValue(0);
893 pendingFibers.pop_back();
895 loopController.stop();
899 loopController.loop(std::move(loopFunc));
903 /* Checks that this function was run from a main context,
904 by comparing an address on a stack to a known main stack address
905 and a known related fiber stack address. The assumption
906 is that fiber stack and main stack will be far enough apart,
907 while any two values on the same stack will be close. */
908 void expectMainContext(bool& ran, int* mainLocation, int* fiberLocation) {
910 /* 2 pages is a good guess */
911 constexpr ssize_t DISTANCE = 0x2000 / sizeof(int);
913 EXPECT_TRUE(std::abs(&here - fiberLocation) > DISTANCE);
916 EXPECT_TRUE(std::abs(&here - mainLocation) < DISTANCE);
924 TEST(FiberManager, runInMainContext) {
925 FiberManager manager(folly::make_unique<SimpleLoopController>());
926 auto& loopController =
927 dynamic_cast<SimpleLoopController&>(manager.loopController());
929 bool checkRan = false;
932 manager.runInMainContext(
934 expectMainContext(checkRan, &mainLocation, nullptr);
936 EXPECT_TRUE(checkRan);
945 expectMainContext(checkRan, &mainLocation, &stackLocation);
947 EXPECT_TRUE(checkRan);
953 loopController.stop();
957 EXPECT_TRUE(checkRan);
960 TEST(FiberManager, addTaskFinally) {
961 FiberManager manager(folly::make_unique<SimpleLoopController>());
962 auto& loopController =
963 dynamic_cast<SimpleLoopController&>(manager.loopController());
965 bool checkRan = false;
969 manager.addTaskFinally(
973 [&](Try<int>&& result) {
974 EXPECT_EQ(result.value(), 1234);
976 expectMainContext(checkRan, &mainLocation, nullptr);
980 EXPECT_FALSE(checkRan);
984 loopController.stop();
988 EXPECT_TRUE(checkRan);
991 TEST(FiberManager, fibersPoolWithinLimit) {
992 FiberManager::Options opts;
993 opts.maxFibersPoolSize = 5;
995 FiberManager manager(folly::make_unique<SimpleLoopController>(), opts);
996 auto& loopController =
997 dynamic_cast<SimpleLoopController&>(manager.loopController());
999 size_t fibersRun = 0;
1001 for (size_t i = 0; i < 5; ++i) {
1008 loopController.loop(
1010 loopController.stop();
1014 EXPECT_EQ(5, fibersRun);
1015 EXPECT_EQ(5, manager.fibersAllocated());
1016 EXPECT_EQ(5, manager.fibersPoolSize());
1018 for (size_t i = 0; i < 5; ++i) {
1025 loopController.loop(
1027 loopController.stop();
1031 EXPECT_EQ(10, fibersRun);
1032 EXPECT_EQ(5, manager.fibersAllocated());
1033 EXPECT_EQ(5, manager.fibersPoolSize());
1036 TEST(FiberManager, fibersPoolOverLimit) {
1037 FiberManager::Options opts;
1038 opts.maxFibersPoolSize = 5;
1040 FiberManager manager(folly::make_unique<SimpleLoopController>(), opts);
1041 auto& loopController =
1042 dynamic_cast<SimpleLoopController&>(manager.loopController());
1044 size_t fibersRun = 0;
1046 for (size_t i = 0; i < 10; ++i) {
1054 EXPECT_EQ(0, fibersRun);
1055 EXPECT_EQ(10, manager.fibersAllocated());
1056 EXPECT_EQ(0, manager.fibersPoolSize());
1058 loopController.loop(
1060 loopController.stop();
1064 EXPECT_EQ(10, fibersRun);
1065 EXPECT_EQ(5, manager.fibersAllocated());
1066 EXPECT_EQ(5, manager.fibersPoolSize());
1069 TEST(FiberManager, remoteFiberBasic) {
1070 FiberManager manager(folly::make_unique<SimpleLoopController>());
1071 auto& loopController =
1072 dynamic_cast<SimpleLoopController&>(manager.loopController());
1075 result[0] = result[1] = 0;
1076 folly::Optional<Promise<int>> savedPromise[2];
1079 result[0] = await([&] (Promise<int> promise) {
1080 savedPromise[0] = std::move(promise);
1085 result[1] = await([&] (Promise<int> promise) {
1086 savedPromise[1] = std::move(promise);
1090 manager.loopUntilNoReady();
1092 EXPECT_TRUE(savedPromise[0].hasValue());
1093 EXPECT_TRUE(savedPromise[1].hasValue());
1094 EXPECT_EQ(0, result[0]);
1095 EXPECT_EQ(0, result[1]);
1097 std::thread remoteThread0{
1099 savedPromise[0]->setValue(42);
1102 std::thread remoteThread1{
1104 savedPromise[1]->setValue(43);
1107 remoteThread0.join();
1108 remoteThread1.join();
1109 EXPECT_EQ(0, result[0]);
1110 EXPECT_EQ(0, result[1]);
1111 /* Should only have scheduled once */
1112 EXPECT_EQ(1, loopController.remoteScheduleCalled());
1114 manager.loopUntilNoReady();
1115 EXPECT_EQ(42, result[0]);
1116 EXPECT_EQ(43, result[1]);
1119 TEST(FiberManager, addTaskRemoteBasic) {
1120 FiberManager manager(folly::make_unique<SimpleLoopController>());
1123 result[0] = result[1] = 0;
1124 folly::Optional<Promise<int>> savedPromise[2];
1126 std::thread remoteThread0{
1128 manager.addTaskRemote(
1130 result[0] = await([&] (Promise<int> promise) {
1131 savedPromise[0] = std::move(promise);
1136 std::thread remoteThread1{
1138 manager.addTaskRemote(
1140 result[1] = await([&] (Promise<int> promise) {
1141 savedPromise[1] = std::move(promise);
1146 remoteThread0.join();
1147 remoteThread1.join();
1149 manager.loopUntilNoReady();
1151 EXPECT_TRUE(savedPromise[0].hasValue());
1152 EXPECT_TRUE(savedPromise[1].hasValue());
1153 EXPECT_EQ(0, result[0]);
1154 EXPECT_EQ(0, result[1]);
1156 savedPromise[0]->setValue(42);
1157 savedPromise[1]->setValue(43);
1159 EXPECT_EQ(0, result[0]);
1160 EXPECT_EQ(0, result[1]);
1162 manager.loopUntilNoReady();
1163 EXPECT_EQ(42, result[0]);
1164 EXPECT_EQ(43, result[1]);
1167 TEST(FiberManager, remoteHasTasks) {
1169 FiberManager fm(folly::make_unique<SimpleLoopController>());
1170 std::thread remote([&]() {
1171 fm.addTaskRemote([&]() {
1178 while (fm.hasTasks()) {
1179 fm.loopUntilNoReady();
1182 EXPECT_FALSE(fm.hasTasks());
1183 EXPECT_EQ(counter, 1);
1186 TEST(FiberManager, remoteHasReadyTasks) {
1188 folly::Optional<Promise<int>> savedPromise;
1189 FiberManager fm(folly::make_unique<SimpleLoopController>());
1190 std::thread remote([&]() {
1191 fm.addTaskRemote([&]() {
1192 result = await([&](Promise<int> promise) {
1193 savedPromise = std::move(promise);
1195 EXPECT_TRUE(fm.hasTasks());
1200 EXPECT_TRUE(fm.hasTasks());
1202 fm.loopUntilNoReady();
1203 EXPECT_TRUE(fm.hasTasks());
1205 std::thread remote2([&](){
1206 savedPromise->setValue(47);
1209 EXPECT_TRUE(fm.hasTasks());
1211 fm.loopUntilNoReady();
1212 EXPECT_FALSE(fm.hasTasks());
1214 EXPECT_EQ(result, 47);
1217 template <typename Data>
1218 void testFiberLocal() {
1219 FiberManager fm(LocalType<Data>(),
1220 folly::make_unique<SimpleLoopController>());
1223 EXPECT_EQ(42, local<Data>().value);
1225 local<Data>().value = 43;
1228 EXPECT_EQ(43, local<Data>().value);
1230 local<Data>().value = 44;
1233 EXPECT_EQ(44, local<Data>().value);
1239 EXPECT_EQ(42, local<Data>().value);
1241 local<Data>().value = 43;
1243 fm.addTaskRemote([]() {
1244 EXPECT_EQ(43, local<Data>().value);
1249 EXPECT_EQ(42, local<Data>().value);
1250 local<Data>().value = 43;
1253 EXPECT_EQ(43, local<Data>().value);
1254 local<Data>().value = 44;
1256 std::vector<std::function<void()>> tasks{task};
1257 collectAny(tasks.begin(), tasks.end());
1259 EXPECT_EQ(43, local<Data>().value);
1262 fm.loopUntilNoReady();
1263 EXPECT_FALSE(fm.hasTasks());
1266 TEST(FiberManager, fiberLocal) {
1271 testFiberLocal<SimpleData>();
1274 TEST(FiberManager, fiberLocalHeap) {
1280 testFiberLocal<LargeData>();
1283 TEST(FiberManager, fiberLocalDestructor) {
1290 EXPECT_EQ(42, local<CrazyData>().data);
1291 // Make sure we don't have infinite loop
1292 local<CrazyData>().data = 0;
1298 FiberManager fm(LocalType<CrazyData>(),
1299 folly::make_unique<SimpleLoopController>());
1302 local<CrazyData>().data = 41;
1305 fm.loopUntilNoReady();
1306 EXPECT_FALSE(fm.hasTasks());
1309 TEST(FiberManager, yieldTest) {
1310 FiberManager manager(folly::make_unique<SimpleLoopController>());
1311 auto& loopController =
1312 dynamic_cast<SimpleLoopController&>(manager.loopController());
1314 bool checkRan = false;
1323 loopController.loop(
1326 loopController.stop();
1331 EXPECT_TRUE(checkRan);
1334 TEST(FiberManager, RequestContext) {
1335 FiberManager fm(folly::make_unique<SimpleLoopController>());
1337 bool checkRun1 = false;
1338 bool checkRun2 = false;
1339 bool checkRun3 = false;
1341 folly::fibers::Baton baton1;
1342 folly::fibers::Baton baton2;
1343 folly::fibers::Baton baton3;
1345 folly::RequestContext::create();
1346 auto rcontext1 = folly::RequestContext::get();
1348 EXPECT_EQ(rcontext1, folly::RequestContext::get());
1350 EXPECT_EQ(rcontext1, folly::RequestContext::get());
1352 EXPECT_EQ(rcontext1, folly::RequestContext::get());
1353 runInMainContext([&]() {
1354 EXPECT_EQ(rcontext1, folly::RequestContext::get());
1359 folly::RequestContext::create();
1360 auto rcontext2 = folly::RequestContext::get();
1361 fm.addTaskRemote([&]() {
1362 EXPECT_EQ(rcontext2, folly::RequestContext::get());
1364 EXPECT_EQ(rcontext2, folly::RequestContext::get());
1368 folly::RequestContext::create();
1369 auto rcontext3 = folly::RequestContext::get();
1372 EXPECT_EQ(rcontext3, folly::RequestContext::get());
1374 EXPECT_EQ(rcontext3, folly::RequestContext::get());
1376 return folly::Unit();
1378 [&](Try<folly::Unit>&& /* t */) {
1379 EXPECT_EQ(rcontext3, folly::RequestContext::get());
1383 folly::RequestContext::create();
1384 auto rcontext = folly::RequestContext::get();
1386 fm.loopUntilNoReady();
1387 EXPECT_EQ(rcontext, folly::RequestContext::get());
1390 EXPECT_EQ(rcontext, folly::RequestContext::get());
1391 fm.loopUntilNoReady();
1392 EXPECT_TRUE(checkRun1);
1393 EXPECT_EQ(rcontext, folly::RequestContext::get());
1396 EXPECT_EQ(rcontext, folly::RequestContext::get());
1397 fm.loopUntilNoReady();
1398 EXPECT_TRUE(checkRun2);
1399 EXPECT_EQ(rcontext, folly::RequestContext::get());
1402 EXPECT_EQ(rcontext, folly::RequestContext::get());
1403 fm.loopUntilNoReady();
1404 EXPECT_TRUE(checkRun3);
1405 EXPECT_EQ(rcontext, folly::RequestContext::get());
1408 TEST(FiberManager, resizePeriodically) {
1409 FiberManager::Options opts;
1410 opts.fibersPoolResizePeriodMs = 300;
1411 opts.maxFibersPoolSize = 5;
1413 FiberManager manager(folly::make_unique<EventBaseLoopController>(), opts);
1415 folly::EventBase evb;
1416 dynamic_cast<EventBaseLoopController&>(manager.loopController())
1417 .attachEventBase(evb);
1419 std::vector<Baton> batons(10);
1421 size_t tasksRun = 0;
1422 for (size_t i = 0; i < 30; ++i) {
1423 manager.addTask([i, &batons, &tasksRun]() {
1425 // Keep some fibers active indefinitely
1426 if (i < batons.size()) {
1432 EXPECT_EQ(0, tasksRun);
1433 EXPECT_EQ(30, manager.fibersAllocated());
1434 EXPECT_EQ(0, manager.fibersPoolSize());
1437 EXPECT_EQ(30, tasksRun);
1438 EXPECT_EQ(30, manager.fibersAllocated());
1439 // Can go over maxFibersPoolSize, 10 of 30 fibers still active
1440 EXPECT_EQ(20, manager.fibersPoolSize());
1442 std::this_thread::sleep_for(std::chrono::milliseconds(400));
1443 evb.loopOnce(); // no fibers active in this period
1444 EXPECT_EQ(30, manager.fibersAllocated());
1445 EXPECT_EQ(20, manager.fibersPoolSize());
1447 std::this_thread::sleep_for(std::chrono::milliseconds(400));
1448 evb.loopOnce(); // should shrink fibers pool to maxFibersPoolSize
1449 EXPECT_EQ(15, manager.fibersAllocated());
1450 EXPECT_EQ(5, manager.fibersPoolSize());
1452 for (size_t i = 0; i < batons.size(); ++i) {
1456 EXPECT_EQ(15, manager.fibersAllocated());
1457 EXPECT_EQ(15, manager.fibersPoolSize());
1459 std::this_thread::sleep_for(std::chrono::milliseconds(400));
1460 evb.loopOnce(); // 10 fibers active in last period
1461 EXPECT_EQ(10, manager.fibersAllocated());
1462 EXPECT_EQ(10, manager.fibersPoolSize());
1464 std::this_thread::sleep_for(std::chrono::milliseconds(400));
1466 EXPECT_EQ(5, manager.fibersAllocated());
1467 EXPECT_EQ(5, manager.fibersPoolSize());
1470 TEST(FiberManager, batonWaitTimeoutHandler) {
1471 FiberManager manager(folly::make_unique<EventBaseLoopController>());
1473 folly::EventBase evb;
1474 dynamic_cast<EventBaseLoopController&>(manager.loopController())
1475 .attachEventBase(evb);
1477 size_t fibersRun = 0;
1479 Baton::TimeoutHandler timeoutHandler;
1481 manager.addTask([&]() {
1482 baton.wait(timeoutHandler);
1485 manager.loopUntilNoReady();
1487 EXPECT_FALSE(baton.try_wait());
1488 EXPECT_EQ(0, fibersRun);
1490 timeoutHandler.scheduleTimeout(std::chrono::milliseconds(250));
1491 std::this_thread::sleep_for(std::chrono::milliseconds(500));
1493 EXPECT_FALSE(baton.try_wait());
1494 EXPECT_EQ(0, fibersRun);
1497 manager.loopUntilNoReady();
1499 EXPECT_EQ(1, fibersRun);
1502 TEST(FiberManager, batonWaitTimeoutMany) {
1503 FiberManager manager(folly::make_unique<EventBaseLoopController>());
1505 folly::EventBase evb;
1506 dynamic_cast<EventBaseLoopController&>(manager.loopController())
1507 .attachEventBase(evb);
1509 constexpr size_t kNumTimeoutTasks = 10000;
1510 size_t tasksCount = kNumTimeoutTasks;
1512 // We add many tasks to hit timeout queue deallocation logic.
1513 for (size_t i = 0; i < kNumTimeoutTasks; ++i) {
1514 manager.addTask([&]() {
1516 Baton::TimeoutHandler timeoutHandler;
1518 folly::fibers::addTask([&] {
1519 timeoutHandler.scheduleTimeout(std::chrono::milliseconds(1000));
1522 baton.wait(timeoutHandler);
1523 if (--tasksCount == 0) {
1524 evb.terminateLoopSoon();
1532 TEST(FiberManager, remoteFutureTest) {
1533 FiberManager fiberManager(folly::make_unique<SimpleLoopController>());
1534 auto& loopController =
1535 dynamic_cast<SimpleLoopController&>(fiberManager.loopController());
1539 auto f1 = fiberManager.addTaskFuture([&]() { return testValue1; });
1540 auto f2 = fiberManager.addTaskRemoteFuture([&]() { return testValue2; });
1541 loopController.loop([&]() { loopController.stop(); });
1545 EXPECT_EQ(v1, testValue1);
1546 EXPECT_EQ(v2, testValue2);
1549 static size_t sNumAwaits;
1551 void runBenchmark(size_t numAwaits, size_t toSend) {
1552 sNumAwaits = numAwaits;
1554 FiberManager fiberManager(folly::make_unique<SimpleLoopController>());
1555 auto& loopController =
1556 dynamic_cast<SimpleLoopController&>(fiberManager.loopController());
1558 std::queue<Promise<int>> pendingRequests;
1559 static const size_t maxOutstanding = 5;
1561 auto loop = [&fiberManager, &loopController, &pendingRequests, &toSend]() {
1562 if (pendingRequests.size() == maxOutstanding || toSend == 0) {
1563 if (pendingRequests.empty()) {
1566 pendingRequests.front().setValue(0);
1567 pendingRequests.pop();
1569 fiberManager.addTask([&pendingRequests]() {
1570 for (size_t i = 0; i < sNumAwaits; ++i) {
1571 auto result = await(
1572 [&pendingRequests](Promise<int> promise) {
1573 pendingRequests.push(std::move(promise));
1575 DCHECK_EQ(result, 0);
1579 if (--toSend == 0) {
1580 loopController.stop();
1585 loopController.loop(std::move(loop));
1588 BENCHMARK(FiberManagerBasicOneAwait, iters) {
1589 runBenchmark(1, iters);
1592 BENCHMARK(FiberManagerBasicFiveAwaits, iters) {
1593 runBenchmark(5, iters);
1596 BENCHMARK(FiberManagerAllocateDeallocatePattern, iters) {
1597 static const size_t kNumAllocations = 10000;
1599 FiberManager::Options opts;
1600 opts.maxFibersPoolSize = 0;
1602 FiberManager fiberManager(folly::make_unique<SimpleLoopController>(), opts);
1604 for (size_t iter = 0; iter < iters; ++iter) {
1605 EXPECT_EQ(0, fiberManager.fibersPoolSize());
1607 size_t fibersRun = 0;
1609 for (size_t i = 0; i < kNumAllocations; ++i) {
1610 fiberManager.addTask(
1615 fiberManager.loopUntilNoReady();
1618 EXPECT_EQ(10000, fibersRun);
1619 EXPECT_EQ(0, fiberManager.fibersPoolSize());
1623 BENCHMARK(FiberManagerAllocateLargeChunk, iters) {
1624 static const size_t kNumAllocations = 10000;
1626 FiberManager::Options opts;
1627 opts.maxFibersPoolSize = 0;
1629 FiberManager fiberManager(folly::make_unique<SimpleLoopController>(), opts);
1631 for (size_t iter = 0; iter < iters; ++iter) {
1632 EXPECT_EQ(0, fiberManager.fibersPoolSize());
1634 size_t fibersRun = 0;
1636 for (size_t i = 0; i < kNumAllocations; ++i) {
1637 fiberManager.addTask(
1644 fiberManager.loopUntilNoReady();
1646 EXPECT_EQ(10000, fibersRun);
1647 EXPECT_EQ(0, fiberManager.fibersPoolSize());