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>
25 #include <folly/experimental/fibers/AddTasks.h>
26 #include <folly/experimental/fibers/EventBaseLoopController.h>
27 #include <folly/experimental/fibers/FiberManager.h>
28 #include <folly/experimental/fibers/GenericBaton.h>
29 #include <folly/experimental/fibers/SimpleLoopController.h>
30 #include <folly/experimental/fibers/WhenN.h>
32 using namespace folly::fibers;
36 TEST(FiberManager, batonTimedWaitTimeout) {
37 bool taskAdded = false;
38 size_t iterations = 0;
40 FiberManager manager(folly::make_unique<SimpleLoopController>());
41 auto& loopController =
42 dynamic_cast<SimpleLoopController&>(manager.loopController());
44 auto loopFunc = [&]() {
50 auto res = baton.timed_wait(std::chrono::milliseconds(230));
53 EXPECT_EQ(5, iterations);
55 loopController.stop();
62 auto res = baton.timed_wait(std::chrono::milliseconds(130));
65 EXPECT_EQ(3, iterations);
67 loopController.stop();
72 std::this_thread::sleep_for(std::chrono::milliseconds(50));
77 loopController.loop(std::move(loopFunc));
80 TEST(FiberManager, batonTimedWaitPost) {
81 bool taskAdded = false;
82 size_t iterations = 0;
85 FiberManager manager(folly::make_unique<SimpleLoopController>());
86 auto& loopController =
87 dynamic_cast<SimpleLoopController&>(manager.loopController());
89 auto loopFunc = [&]() {
96 auto res = baton.timed_wait(std::chrono::milliseconds(130));
99 EXPECT_EQ(2, iterations);
101 loopController.stop();
106 std::this_thread::sleep_for(std::chrono::milliseconds(50));
108 if (iterations == 2) {
114 loopController.loop(std::move(loopFunc));
117 TEST(FiberManager, batonTimedWaitTimeoutEvb) {
118 size_t tasksComplete = 0;
120 folly::EventBase evb;
122 FiberManager manager(folly::make_unique<EventBaseLoopController>());
123 dynamic_cast<EventBaseLoopController&>(
124 manager.loopController()).attachEventBase(evb);
126 auto task = [&](size_t timeout_ms) {
129 auto start = EventBaseLoopController::Clock::now();
130 auto res = baton.timed_wait(std::chrono::milliseconds(timeout_ms));
131 auto finish = EventBaseLoopController::Clock::now();
136 std::chrono::duration_cast<std::chrono::milliseconds>(finish - start);
138 EXPECT_GT(duration_ms.count(), timeout_ms - 50);
139 EXPECT_LT(duration_ms.count(), timeout_ms + 50);
141 if (++tasksComplete == 2) {
142 evb.terminateLoopSoon();
146 evb.runInEventBaseThread([&]() {
161 EXPECT_EQ(2, tasksComplete);
164 TEST(FiberManager, batonTimedWaitPostEvb) {
165 size_t tasksComplete = 0;
167 folly::EventBase evb;
169 FiberManager manager(folly::make_unique<EventBaseLoopController>());
170 dynamic_cast<EventBaseLoopController&>(
171 manager.loopController()).attachEventBase(evb);
173 evb.runInEventBaseThread([&]() {
174 manager.addTask([&]() {
177 evb.tryRunAfterDelay([&]() {
182 auto start = EventBaseLoopController::Clock::now();
183 auto res = baton.timed_wait(std::chrono::milliseconds(130));
184 auto finish = EventBaseLoopController::Clock::now();
188 auto duration_ms = std::chrono::duration_cast<
189 std::chrono::milliseconds>(finish - start);
191 EXPECT_TRUE(duration_ms.count() > 95 &&
192 duration_ms.count() < 110);
194 if (++tasksComplete == 1) {
195 evb.terminateLoopSoon();
202 EXPECT_EQ(1, tasksComplete);
205 TEST(FiberManager, batonTryWait) {
207 FiberManager manager(folly::make_unique<SimpleLoopController>());
209 // Check if try_wait and post work as expected
212 manager.addTask([&](){
213 while (!b.try_wait()) {
216 auto thr = std::thread([&](){
217 std::this_thread::sleep_for(std::chrono::milliseconds(300));
221 manager.loopUntilNoReady();
226 // Check try_wait without post
227 manager.addTask([&](){
229 while (cnt && !c.try_wait()) {
232 EXPECT_TRUE(!c.try_wait()); // must still hold
236 manager.loopUntilNoReady();
239 TEST(FiberManager, genericBatonFiberWait) {
240 FiberManager manager(folly::make_unique<SimpleLoopController>());
243 bool fiberRunning = false;
245 manager.addTask([&](){
246 EXPECT_EQ(manager.hasActiveFiber(), true);
249 fiberRunning = false;
252 EXPECT_FALSE(fiberRunning);
253 manager.loopUntilNoReady();
254 EXPECT_TRUE(fiberRunning); // ensure fiber still active
256 auto thr = std::thread([&](){
257 std::this_thread::sleep_for(std::chrono::milliseconds(300));
261 while (fiberRunning) {
262 manager.loopUntilNoReady();
268 TEST(FiberManager, genericBatonThreadWait) {
269 FiberManager manager(folly::make_unique<SimpleLoopController>());
271 std::atomic<bool> threadWaiting(false);
273 auto thr = std::thread([&](){
274 threadWaiting = true;
276 threadWaiting = false;
279 while (!threadWaiting) {}
280 std::this_thread::sleep_for(std::chrono::milliseconds(300));
282 manager.addTask([&](){
283 EXPECT_EQ(manager.hasActiveFiber(), true);
284 EXPECT_TRUE(threadWaiting);
286 while(threadWaiting) {}
289 manager.loopUntilNoReady();
293 TEST(FiberManager, addTasksNoncopyable) {
294 std::vector<Promise<int>> pendingFibers;
295 bool taskAdded = false;
297 FiberManager manager(folly::make_unique<SimpleLoopController>());
298 auto& loopController =
299 dynamic_cast<SimpleLoopController&>(manager.loopController());
301 auto loopFunc = [&]() {
305 std::vector<std::function<std::unique_ptr<int>()>> funcs;
306 for (size_t i = 0; i < 3; ++i) {
308 [i, &pendingFibers]() {
309 await([&pendingFibers](Promise<int> promise) {
310 pendingFibers.push_back(std::move(promise));
312 return folly::make_unique<int>(i*2 + 1);
317 auto iter = addTasks(funcs.begin(), funcs.end());
320 while (iter.hasNext()) {
321 auto result = iter.awaitNext();
322 EXPECT_EQ(2 * iter.getTaskID() + 1, *result);
323 EXPECT_GE(2 - n, pendingFibers.size());
330 } else if (pendingFibers.size()) {
331 pendingFibers.back().setValue(0);
332 pendingFibers.pop_back();
334 loopController.stop();
338 loopController.loop(std::move(loopFunc));
341 TEST(FiberManager, addTasksThrow) {
342 std::vector<Promise<int>> pendingFibers;
343 bool taskAdded = false;
345 FiberManager manager(folly::make_unique<SimpleLoopController>());
346 auto& loopController =
347 dynamic_cast<SimpleLoopController&>(manager.loopController());
349 auto loopFunc = [&]() {
353 std::vector<std::function<int()>> funcs;
354 for (size_t i = 0; i < 3; ++i) {
356 [i, &pendingFibers]() {
357 await([&pendingFibers](Promise<int> promise) {
358 pendingFibers.push_back(std::move(promise));
361 throw std::runtime_error("Runtime");
368 auto iter = addTasks(funcs.begin(), funcs.end());
371 while (iter.hasNext()) {
373 int result = iter.awaitNext();
374 EXPECT_EQ(1, iter.getTaskID() % 2);
375 EXPECT_EQ(2 * iter.getTaskID() + 1, result);
377 EXPECT_EQ(0, iter.getTaskID() % 2);
379 EXPECT_GE(2 - n, pendingFibers.size());
386 } else if (pendingFibers.size()) {
387 pendingFibers.back().setValue(0);
388 pendingFibers.pop_back();
390 loopController.stop();
394 loopController.loop(std::move(loopFunc));
397 TEST(FiberManager, addTasksVoid) {
398 std::vector<Promise<int>> pendingFibers;
399 bool taskAdded = false;
401 FiberManager manager(folly::make_unique<SimpleLoopController>());
402 auto& loopController =
403 dynamic_cast<SimpleLoopController&>(manager.loopController());
405 auto loopFunc = [&]() {
409 std::vector<std::function<void()>> funcs;
410 for (size_t i = 0; i < 3; ++i) {
412 [i, &pendingFibers]() {
413 await([&pendingFibers](Promise<int> promise) {
414 pendingFibers.push_back(std::move(promise));
420 auto iter = addTasks(funcs.begin(), funcs.end());
423 while (iter.hasNext()) {
425 EXPECT_GE(2 - n, pendingFibers.size());
432 } else if (pendingFibers.size()) {
433 pendingFibers.back().setValue(0);
434 pendingFibers.pop_back();
436 loopController.stop();
440 loopController.loop(std::move(loopFunc));
443 TEST(FiberManager, addTasksVoidThrow) {
444 std::vector<Promise<int>> pendingFibers;
445 bool taskAdded = false;
447 FiberManager manager(folly::make_unique<SimpleLoopController>());
448 auto& loopController =
449 dynamic_cast<SimpleLoopController&>(manager.loopController());
451 auto loopFunc = [&]() {
455 std::vector<std::function<void()>> funcs;
456 for (size_t i = 0; i < 3; ++i) {
458 [i, &pendingFibers]() {
459 await([&pendingFibers](Promise<int> promise) {
460 pendingFibers.push_back(std::move(promise));
463 throw std::runtime_error("");
469 auto iter = addTasks(funcs.begin(), funcs.end());
472 while (iter.hasNext()) {
475 EXPECT_EQ(1, iter.getTaskID() % 2);
477 EXPECT_EQ(0, iter.getTaskID() % 2);
479 EXPECT_GE(2 - n, pendingFibers.size());
486 } else if (pendingFibers.size()) {
487 pendingFibers.back().setValue(0);
488 pendingFibers.pop_back();
490 loopController.stop();
494 loopController.loop(std::move(loopFunc));
497 TEST(FiberManager, reserve) {
498 std::vector<Promise<int>> pendingFibers;
499 bool taskAdded = false;
501 FiberManager manager(folly::make_unique<SimpleLoopController>());
502 auto& loopController =
503 dynamic_cast<SimpleLoopController&>(manager.loopController());
505 auto loopFunc = [&]() {
509 std::vector<std::function<void()>> funcs;
510 for (size_t i = 0; i < 3; ++i) {
513 await([&pendingFibers](Promise<int> promise) {
514 pendingFibers.push_back(std::move(promise));
520 auto iter = addTasks(funcs.begin(), funcs.end());
523 EXPECT_TRUE(iter.hasCompleted());
524 EXPECT_TRUE(iter.hasPending());
525 EXPECT_TRUE(iter.hasNext());
528 EXPECT_TRUE(iter.hasCompleted());
529 EXPECT_TRUE(iter.hasPending());
530 EXPECT_TRUE(iter.hasNext());
533 EXPECT_FALSE(iter.hasCompleted());
534 EXPECT_TRUE(iter.hasPending());
535 EXPECT_TRUE(iter.hasNext());
538 EXPECT_FALSE(iter.hasCompleted());
539 EXPECT_FALSE(iter.hasPending());
540 EXPECT_FALSE(iter.hasNext());
544 } else if (pendingFibers.size()) {
545 pendingFibers.back().setValue(0);
546 pendingFibers.pop_back();
548 loopController.stop();
552 loopController.loop(std::move(loopFunc));
555 TEST(FiberManager, forEach) {
556 std::vector<Promise<int>> pendingFibers;
557 bool taskAdded = false;
559 FiberManager manager(folly::make_unique<SimpleLoopController>());
560 auto& loopController =
561 dynamic_cast<SimpleLoopController&>(manager.loopController());
563 auto loopFunc = [&]() {
567 std::vector<std::function<int()>> funcs;
568 for (size_t i = 0; i < 3; ++i) {
570 [i, &pendingFibers]() {
571 await([&pendingFibers](Promise<int> promise) {
572 pendingFibers.push_back(std::move(promise));
579 std::vector<std::pair<size_t, int>> results;
580 forEach(funcs.begin(), funcs.end(),
581 [&results](size_t id, int result) {
582 results.emplace_back(id, result);
584 EXPECT_EQ(3, results.size());
585 EXPECT_TRUE(pendingFibers.empty());
586 for (size_t i = 0; i < 3; ++i) {
587 EXPECT_EQ(results[i].first * 2 + 1, results[i].second);
592 } else if (pendingFibers.size()) {
593 pendingFibers.back().setValue(0);
594 pendingFibers.pop_back();
596 loopController.stop();
600 loopController.loop(std::move(loopFunc));
603 TEST(FiberManager, collectN) {
604 std::vector<Promise<int>> pendingFibers;
605 bool taskAdded = false;
607 FiberManager manager(folly::make_unique<SimpleLoopController>());
608 auto& loopController =
609 dynamic_cast<SimpleLoopController&>(manager.loopController());
611 auto loopFunc = [&]() {
615 std::vector<std::function<int()>> funcs;
616 for (size_t i = 0; i < 3; ++i) {
618 [i, &pendingFibers]() {
619 await([&pendingFibers](Promise<int> promise) {
620 pendingFibers.push_back(std::move(promise));
627 auto results = collectN(funcs.begin(), funcs.end(), 2);
628 EXPECT_EQ(2, results.size());
629 EXPECT_EQ(1, pendingFibers.size());
630 for (size_t i = 0; i < 2; ++i) {
631 EXPECT_EQ(results[i].first*2 + 1, results[i].second);
636 } else if (pendingFibers.size()) {
637 pendingFibers.back().setValue(0);
638 pendingFibers.pop_back();
640 loopController.stop();
644 loopController.loop(std::move(loopFunc));
647 TEST(FiberManager, collectNThrow) {
648 std::vector<Promise<int>> pendingFibers;
649 bool taskAdded = false;
651 FiberManager manager(folly::make_unique<SimpleLoopController>());
652 auto& loopController =
653 dynamic_cast<SimpleLoopController&>(manager.loopController());
655 auto loopFunc = [&]() {
659 std::vector<std::function<int()>> funcs;
660 for (size_t i = 0; i < 3; ++i) {
662 [i, &pendingFibers]() {
663 await([&pendingFibers](Promise<int> promise) {
664 pendingFibers.push_back(std::move(promise));
666 throw std::runtime_error("Runtime");
673 collectN(funcs.begin(), funcs.end(), 2);
675 EXPECT_EQ(1, pendingFibers.size());
680 } else if (pendingFibers.size()) {
681 pendingFibers.back().setValue(0);
682 pendingFibers.pop_back();
684 loopController.stop();
688 loopController.loop(std::move(loopFunc));
691 TEST(FiberManager, collectNVoid) {
692 std::vector<Promise<int>> pendingFibers;
693 bool taskAdded = false;
695 FiberManager manager(folly::make_unique<SimpleLoopController>());
696 auto& loopController =
697 dynamic_cast<SimpleLoopController&>(manager.loopController());
699 auto loopFunc = [&]() {
703 std::vector<std::function<void()>> funcs;
704 for (size_t i = 0; i < 3; ++i) {
706 [i, &pendingFibers]() {
707 await([&pendingFibers](Promise<int> promise) {
708 pendingFibers.push_back(std::move(promise));
714 auto results = collectN(funcs.begin(), funcs.end(), 2);
715 EXPECT_EQ(2, results.size());
716 EXPECT_EQ(1, pendingFibers.size());
720 } else if (pendingFibers.size()) {
721 pendingFibers.back().setValue(0);
722 pendingFibers.pop_back();
724 loopController.stop();
728 loopController.loop(std::move(loopFunc));
731 TEST(FiberManager, collectNVoidThrow) {
732 std::vector<Promise<int>> pendingFibers;
733 bool taskAdded = false;
735 FiberManager manager(folly::make_unique<SimpleLoopController>());
736 auto& loopController =
737 dynamic_cast<SimpleLoopController&>(manager.loopController());
739 auto loopFunc = [&]() {
743 std::vector<std::function<void()>> funcs;
744 for (size_t i = 0; i < 3; ++i) {
746 [i, &pendingFibers]() {
747 await([&pendingFibers](Promise<int> promise) {
748 pendingFibers.push_back(std::move(promise));
750 throw std::runtime_error("Runtime");
756 collectN(funcs.begin(), funcs.end(), 2);
758 EXPECT_EQ(1, pendingFibers.size());
763 } else if (pendingFibers.size()) {
764 pendingFibers.back().setValue(0);
765 pendingFibers.pop_back();
767 loopController.stop();
771 loopController.loop(std::move(loopFunc));
774 TEST(FiberManager, collectAll) {
775 std::vector<Promise<int>> pendingFibers;
776 bool taskAdded = false;
778 FiberManager manager(folly::make_unique<SimpleLoopController>());
779 auto& loopController =
780 dynamic_cast<SimpleLoopController&>(manager.loopController());
782 auto loopFunc = [&]() {
786 std::vector<std::function<int()>> funcs;
787 for (size_t i = 0; i < 3; ++i) {
789 [i, &pendingFibers]() {
790 await([&pendingFibers](Promise<int> promise) {
791 pendingFibers.push_back(std::move(promise));
798 auto results = collectAll(funcs.begin(), funcs.end());
799 EXPECT_TRUE(pendingFibers.empty());
800 for (size_t i = 0; i < 3; ++i) {
801 EXPECT_EQ(i*2+1, results[i]);
806 } else if (pendingFibers.size()) {
807 pendingFibers.back().setValue(0);
808 pendingFibers.pop_back();
810 loopController.stop();
814 loopController.loop(std::move(loopFunc));
817 TEST(FiberManager, collectAllVoid) {
818 std::vector<Promise<int>> pendingFibers;
819 bool taskAdded = false;
821 FiberManager manager(folly::make_unique<SimpleLoopController>());
822 auto& loopController =
823 dynamic_cast<SimpleLoopController&>(manager.loopController());
825 auto loopFunc = [&]() {
829 std::vector<std::function<void()>> funcs;
830 for (size_t i = 0; i < 3; ++ i) {
832 [i, &pendingFibers]() {
833 await([&pendingFibers](Promise<int> promise) {
834 pendingFibers.push_back(std::move(promise));
840 collectAll(funcs.begin(), funcs.end());
841 EXPECT_TRUE(pendingFibers.empty());
845 } else if (pendingFibers.size()) {
846 pendingFibers.back().setValue(0);
847 pendingFibers.pop_back();
849 loopController.stop();
853 loopController.loop(std::move(loopFunc));
856 TEST(FiberManager, collectAny) {
857 std::vector<Promise<int>> pendingFibers;
858 bool taskAdded = false;
860 FiberManager manager(folly::make_unique<SimpleLoopController>());
861 auto& loopController =
862 dynamic_cast<SimpleLoopController&>(manager.loopController());
864 auto loopFunc = [&]() {
868 std::vector<std::function<int()> > funcs;
869 for (size_t i = 0; i < 3; ++ i) {
871 [i, &pendingFibers]() {
872 await([&pendingFibers](Promise<int> promise) {
873 pendingFibers.push_back(std::move(promise));
876 throw std::runtime_error("This exception will be ignored");
883 auto result = collectAny(funcs.begin(), funcs.end());
884 EXPECT_EQ(2, pendingFibers.size());
885 EXPECT_EQ(2, result.first);
886 EXPECT_EQ(2*2+1, result.second);
890 } else if (pendingFibers.size()) {
891 pendingFibers.back().setValue(0);
892 pendingFibers.pop_back();
894 loopController.stop();
898 loopController.loop(std::move(loopFunc));
902 /* Checks that this function was run from a main context,
903 by comparing an address on a stack to a known main stack address
904 and a known related fiber stack address. The assumption
905 is that fiber stack and main stack will be far enough apart,
906 while any two values on the same stack will be close. */
907 void expectMainContext(bool& ran, int* mainLocation, int* fiberLocation) {
909 /* 2 pages is a good guess */
910 constexpr ssize_t DISTANCE = 0x2000 / sizeof(int);
912 EXPECT_TRUE(std::abs(&here - fiberLocation) > DISTANCE);
915 EXPECT_TRUE(std::abs(&here - mainLocation) < DISTANCE);
923 TEST(FiberManager, runInMainContext) {
924 FiberManager manager(folly::make_unique<SimpleLoopController>());
925 auto& loopController =
926 dynamic_cast<SimpleLoopController&>(manager.loopController());
928 bool checkRan = false;
931 manager.runInMainContext(
933 expectMainContext(checkRan, &mainLocation, nullptr);
935 EXPECT_TRUE(checkRan);
944 expectMainContext(checkRan, &mainLocation, &stackLocation);
946 EXPECT_TRUE(checkRan);
952 loopController.stop();
956 EXPECT_TRUE(checkRan);
959 TEST(FiberManager, addTaskFinally) {
960 FiberManager manager(folly::make_unique<SimpleLoopController>());
961 auto& loopController =
962 dynamic_cast<SimpleLoopController&>(manager.loopController());
964 bool checkRan = false;
968 manager.addTaskFinally(
972 [&](Try<int>&& result) {
973 EXPECT_EQ(result.value(), 1234);
975 expectMainContext(checkRan, &mainLocation, nullptr);
979 EXPECT_FALSE(checkRan);
983 loopController.stop();
987 EXPECT_TRUE(checkRan);
990 TEST(FiberManager, fibersPoolWithinLimit) {
991 FiberManager::Options opts;
992 opts.maxFibersPoolSize = 5;
994 FiberManager manager(folly::make_unique<SimpleLoopController>(), opts);
995 auto& loopController =
996 dynamic_cast<SimpleLoopController&>(manager.loopController());
998 size_t fibersRun = 0;
1000 for (size_t i = 0; i < 5; ++i) {
1007 loopController.loop(
1009 loopController.stop();
1013 EXPECT_EQ(5, fibersRun);
1014 EXPECT_EQ(5, manager.fibersAllocated());
1015 EXPECT_EQ(5, manager.fibersPoolSize());
1017 for (size_t i = 0; i < 5; ++i) {
1024 loopController.loop(
1026 loopController.stop();
1030 EXPECT_EQ(10, fibersRun);
1031 EXPECT_EQ(5, manager.fibersAllocated());
1032 EXPECT_EQ(5, manager.fibersPoolSize());
1035 TEST(FiberManager, fibersPoolOverLimit) {
1036 FiberManager::Options opts;
1037 opts.maxFibersPoolSize = 5;
1039 FiberManager manager(folly::make_unique<SimpleLoopController>(), opts);
1040 auto& loopController =
1041 dynamic_cast<SimpleLoopController&>(manager.loopController());
1043 size_t fibersRun = 0;
1045 for (size_t i = 0; i < 10; ++i) {
1053 EXPECT_EQ(0, fibersRun);
1054 EXPECT_EQ(10, manager.fibersAllocated());
1055 EXPECT_EQ(0, manager.fibersPoolSize());
1057 loopController.loop(
1059 loopController.stop();
1063 EXPECT_EQ(10, fibersRun);
1064 EXPECT_EQ(5, manager.fibersAllocated());
1065 EXPECT_EQ(5, manager.fibersPoolSize());
1068 TEST(FiberManager, remoteFiberBasic) {
1069 FiberManager manager(folly::make_unique<SimpleLoopController>());
1070 auto& loopController =
1071 dynamic_cast<SimpleLoopController&>(manager.loopController());
1074 result[0] = result[1] = 0;
1075 folly::Optional<Promise<int>> savedPromise[2];
1078 result[0] = await([&] (Promise<int> promise) {
1079 savedPromise[0] = std::move(promise);
1084 result[1] = await([&] (Promise<int> promise) {
1085 savedPromise[1] = std::move(promise);
1089 manager.loopUntilNoReady();
1091 EXPECT_TRUE(savedPromise[0].hasValue());
1092 EXPECT_TRUE(savedPromise[1].hasValue());
1093 EXPECT_EQ(0, result[0]);
1094 EXPECT_EQ(0, result[1]);
1096 std::thread remoteThread0{
1098 savedPromise[0]->setValue(42);
1101 std::thread remoteThread1{
1103 savedPromise[1]->setValue(43);
1106 remoteThread0.join();
1107 remoteThread1.join();
1108 EXPECT_EQ(0, result[0]);
1109 EXPECT_EQ(0, result[1]);
1110 /* Should only have scheduled once */
1111 EXPECT_EQ(1, loopController.remoteScheduleCalled());
1113 manager.loopUntilNoReady();
1114 EXPECT_EQ(42, result[0]);
1115 EXPECT_EQ(43, result[1]);
1118 TEST(FiberManager, addTaskRemoteBasic) {
1119 FiberManager manager(folly::make_unique<SimpleLoopController>());
1122 result[0] = result[1] = 0;
1123 folly::Optional<Promise<int>> savedPromise[2];
1125 std::thread remoteThread0{
1127 manager.addTaskRemote(
1129 result[0] = await([&] (Promise<int> promise) {
1130 savedPromise[0] = std::move(promise);
1135 std::thread remoteThread1{
1137 manager.addTaskRemote(
1139 result[1] = await([&] (Promise<int> promise) {
1140 savedPromise[1] = std::move(promise);
1145 remoteThread0.join();
1146 remoteThread1.join();
1148 manager.loopUntilNoReady();
1150 EXPECT_TRUE(savedPromise[0].hasValue());
1151 EXPECT_TRUE(savedPromise[1].hasValue());
1152 EXPECT_EQ(0, result[0]);
1153 EXPECT_EQ(0, result[1]);
1155 savedPromise[0]->setValue(42);
1156 savedPromise[1]->setValue(43);
1158 EXPECT_EQ(0, result[0]);
1159 EXPECT_EQ(0, result[1]);
1161 manager.loopUntilNoReady();
1162 EXPECT_EQ(42, result[0]);
1163 EXPECT_EQ(43, result[1]);
1166 TEST(FiberManager, remoteHasTasks) {
1168 FiberManager fm(folly::make_unique<SimpleLoopController>());
1169 std::thread remote([&]() {
1170 fm.addTaskRemote([&]() {
1177 while (fm.hasTasks()) {
1178 fm.loopUntilNoReady();
1181 EXPECT_FALSE(fm.hasTasks());
1182 EXPECT_EQ(counter, 1);
1185 TEST(FiberManager, remoteHasReadyTasks) {
1187 folly::Optional<Promise<int>> savedPromise;
1188 FiberManager fm(folly::make_unique<SimpleLoopController>());
1189 std::thread remote([&]() {
1190 fm.addTaskRemote([&]() {
1191 result = await([&](Promise<int> promise) {
1192 savedPromise = std::move(promise);
1194 EXPECT_TRUE(fm.hasTasks());
1199 EXPECT_TRUE(fm.hasTasks());
1201 fm.loopUntilNoReady();
1202 EXPECT_TRUE(fm.hasTasks());
1204 std::thread remote2([&](){
1205 savedPromise->setValue(47);
1208 EXPECT_TRUE(fm.hasTasks());
1210 fm.loopUntilNoReady();
1211 EXPECT_FALSE(fm.hasTasks());
1213 EXPECT_EQ(result, 47);
1216 template <typename Data>
1217 void testFiberLocal() {
1218 FiberManager fm(LocalType<Data>(),
1219 folly::make_unique<SimpleLoopController>());
1222 EXPECT_EQ(42, local<Data>().value);
1224 local<Data>().value = 43;
1227 EXPECT_EQ(43, local<Data>().value);
1229 local<Data>().value = 44;
1232 EXPECT_EQ(44, local<Data>().value);
1238 EXPECT_EQ(42, local<Data>().value);
1240 local<Data>().value = 43;
1242 fm.addTaskRemote([]() {
1243 EXPECT_EQ(43, local<Data>().value);
1248 EXPECT_EQ(42, local<Data>().value);
1249 local<Data>().value = 43;
1252 EXPECT_EQ(43, local<Data>().value);
1253 local<Data>().value = 44;
1255 std::vector<std::function<void()>> tasks{task};
1256 collectAny(tasks.begin(), tasks.end());
1258 EXPECT_EQ(43, local<Data>().value);
1261 fm.loopUntilNoReady();
1262 EXPECT_FALSE(fm.hasTasks());
1265 TEST(FiberManager, fiberLocal) {
1270 testFiberLocal<SimpleData>();
1273 TEST(FiberManager, fiberLocalHeap) {
1279 testFiberLocal<LargeData>();
1282 TEST(FiberManager, fiberLocalDestructor) {
1289 EXPECT_EQ(42, local<CrazyData>().data);
1290 // Make sure we don't have infinite loop
1291 local<CrazyData>().data = 0;
1297 FiberManager fm(LocalType<CrazyData>(),
1298 folly::make_unique<SimpleLoopController>());
1301 local<CrazyData>().data = 41;
1304 fm.loopUntilNoReady();
1305 EXPECT_FALSE(fm.hasTasks());
1308 TEST(FiberManager, yieldTest) {
1309 FiberManager manager(folly::make_unique<SimpleLoopController>());
1310 auto& loopController =
1311 dynamic_cast<SimpleLoopController&>(manager.loopController());
1313 bool checkRan = false;
1322 loopController.loop(
1325 loopController.stop();
1330 EXPECT_TRUE(checkRan);
1333 TEST(FiberManager, RequestContext) {
1334 FiberManager fm(folly::make_unique<SimpleLoopController>());
1336 bool checkRun1 = false;
1337 bool checkRun2 = false;
1338 bool checkRun3 = false;
1340 folly::fibers::Baton baton1;
1341 folly::fibers::Baton baton2;
1342 folly::fibers::Baton baton3;
1344 folly::RequestContext::create();
1345 auto rcontext1 = folly::RequestContext::get();
1347 EXPECT_EQ(rcontext1, folly::RequestContext::get());
1349 EXPECT_EQ(rcontext1, folly::RequestContext::get());
1351 EXPECT_EQ(rcontext1, folly::RequestContext::get());
1352 runInMainContext([&]() {
1353 EXPECT_EQ(rcontext1, folly::RequestContext::get());
1358 folly::RequestContext::create();
1359 auto rcontext2 = folly::RequestContext::get();
1360 fm.addTaskRemote([&]() {
1361 EXPECT_EQ(rcontext2, folly::RequestContext::get());
1363 EXPECT_EQ(rcontext2, folly::RequestContext::get());
1367 folly::RequestContext::create();
1368 auto rcontext3 = folly::RequestContext::get();
1369 fm.addTaskFinally([&]() {
1370 EXPECT_EQ(rcontext3, folly::RequestContext::get());
1372 EXPECT_EQ(rcontext3, folly::RequestContext::get());
1374 return folly::Unit();
1376 [&](Try<folly::Unit>&& t) {
1377 EXPECT_EQ(rcontext3, folly::RequestContext::get());
1381 folly::RequestContext::create();
1382 auto rcontext = folly::RequestContext::get();
1384 fm.loopUntilNoReady();
1385 EXPECT_EQ(rcontext, folly::RequestContext::get());
1388 EXPECT_EQ(rcontext, folly::RequestContext::get());
1389 fm.loopUntilNoReady();
1390 EXPECT_TRUE(checkRun1);
1391 EXPECT_EQ(rcontext, folly::RequestContext::get());
1394 EXPECT_EQ(rcontext, folly::RequestContext::get());
1395 fm.loopUntilNoReady();
1396 EXPECT_TRUE(checkRun2);
1397 EXPECT_EQ(rcontext, folly::RequestContext::get());
1400 EXPECT_EQ(rcontext, folly::RequestContext::get());
1401 fm.loopUntilNoReady();
1402 EXPECT_TRUE(checkRun3);
1403 EXPECT_EQ(rcontext, folly::RequestContext::get());
1406 static size_t sNumAwaits;
1408 void runBenchmark(size_t numAwaits, size_t toSend) {
1409 sNumAwaits = numAwaits;
1411 FiberManager fiberManager(folly::make_unique<SimpleLoopController>());
1412 auto& loopController =
1413 dynamic_cast<SimpleLoopController&>(fiberManager.loopController());
1415 std::queue<Promise<int>> pendingRequests;
1416 static const size_t maxOutstanding = 5;
1418 auto loop = [&fiberManager, &loopController, &pendingRequests, &toSend]() {
1419 if (pendingRequests.size() == maxOutstanding || toSend == 0) {
1420 if (pendingRequests.empty()) {
1423 pendingRequests.front().setValue(0);
1424 pendingRequests.pop();
1426 fiberManager.addTask([&pendingRequests]() {
1427 for (size_t i = 0; i < sNumAwaits; ++i) {
1428 auto result = await(
1429 [&pendingRequests](Promise<int> promise) {
1430 pendingRequests.push(std::move(promise));
1432 DCHECK_EQ(result, 0);
1436 if (--toSend == 0) {
1437 loopController.stop();
1442 loopController.loop(std::move(loop));
1445 BENCHMARK(FiberManagerBasicOneAwait, iters) {
1446 runBenchmark(1, iters);
1449 BENCHMARK(FiberManagerBasicFiveAwaits, iters) {
1450 runBenchmark(5, iters);
1453 BENCHMARK(FiberManagerAllocateDeallocatePattern, iters) {
1454 static const size_t kNumAllocations = 10000;
1456 FiberManager::Options opts;
1457 opts.maxFibersPoolSize = 0;
1459 FiberManager fiberManager(folly::make_unique<SimpleLoopController>(), opts);
1461 for (size_t iter = 0; iter < iters; ++iter) {
1462 EXPECT_EQ(0, fiberManager.fibersPoolSize());
1464 size_t fibersRun = 0;
1466 for (size_t i = 0; i < kNumAllocations; ++i) {
1467 fiberManager.addTask(
1472 fiberManager.loopUntilNoReady();
1475 EXPECT_EQ(10000, fibersRun);
1476 EXPECT_EQ(0, fiberManager.fibersPoolSize());
1480 BENCHMARK(FiberManagerAllocateLargeChunk, iters) {
1481 static const size_t kNumAllocations = 10000;
1483 FiberManager::Options opts;
1484 opts.maxFibersPoolSize = 0;
1486 FiberManager fiberManager(folly::make_unique<SimpleLoopController>(), opts);
1488 for (size_t iter = 0; iter < iters; ++iter) {
1489 EXPECT_EQ(0, fiberManager.fibersPoolSize());
1491 size_t fibersRun = 0;
1493 for (size_t i = 0; i < kNumAllocations; ++i) {
1494 fiberManager.addTask(
1501 fiberManager.loopUntilNoReady();
1503 EXPECT_EQ(10000, fibersRun);
1504 EXPECT_EQ(0, fiberManager.fibersPoolSize());