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>());
208 auto& loopController =
209 dynamic_cast<SimpleLoopController&>(manager.loopController());
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.push_back(std::make_pair(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, whenN) {
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 = whenN(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, whenNThrow) {
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 whenN(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, whenNVoid) {
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 = whenN(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, whenNVoidThrow) {
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 whenN(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, whenAll) {
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 = whenAll(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, whenAllVoid) {
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 whenAll(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, whenAny) {
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 = whenAny(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);
946 expectMainContext(checkRan, &mainLocation, &stackLocation);
948 EXPECT_TRUE(checkRan);
954 loopController.stop();
958 EXPECT_TRUE(checkRan);
961 TEST(FiberManager, addTaskFinally) {
962 FiberManager manager(folly::make_unique<SimpleLoopController>());
963 auto& loopController =
964 dynamic_cast<SimpleLoopController&>(manager.loopController());
966 bool checkRan = false;
970 manager.addTaskFinally(
974 [&](Try<int>&& result) {
975 EXPECT_EQ(result.value(), 1234);
977 expectMainContext(checkRan, &mainLocation, nullptr);
981 EXPECT_FALSE(checkRan);
985 loopController.stop();
989 EXPECT_TRUE(checkRan);
992 TEST(FiberManager, fibersPoolWithinLimit) {
993 FiberManager::Options opts;
994 opts.maxFibersPoolSize = 5;
996 FiberManager manager(folly::make_unique<SimpleLoopController>(), opts);
997 auto& loopController =
998 dynamic_cast<SimpleLoopController&>(manager.loopController());
1000 size_t fibersRun = 0;
1002 for (size_t i = 0; i < 5; ++i) {
1009 loopController.loop(
1011 loopController.stop();
1015 EXPECT_EQ(5, fibersRun);
1016 EXPECT_EQ(5, manager.fibersAllocated());
1017 EXPECT_EQ(5, manager.fibersPoolSize());
1019 for (size_t i = 0; i < 5; ++i) {
1026 loopController.loop(
1028 loopController.stop();
1032 EXPECT_EQ(10, fibersRun);
1033 EXPECT_EQ(5, manager.fibersAllocated());
1034 EXPECT_EQ(5, manager.fibersPoolSize());
1037 TEST(FiberManager, fibersPoolOverLimit) {
1038 FiberManager::Options opts;
1039 opts.maxFibersPoolSize = 5;
1041 FiberManager manager(folly::make_unique<SimpleLoopController>(), opts);
1042 auto& loopController =
1043 dynamic_cast<SimpleLoopController&>(manager.loopController());
1045 size_t fibersRun = 0;
1047 for (size_t i = 0; i < 10; ++i) {
1055 EXPECT_EQ(0, fibersRun);
1056 EXPECT_EQ(10, manager.fibersAllocated());
1057 EXPECT_EQ(0, manager.fibersPoolSize());
1059 loopController.loop(
1061 loopController.stop();
1065 EXPECT_EQ(10, fibersRun);
1066 EXPECT_EQ(5, manager.fibersAllocated());
1067 EXPECT_EQ(5, manager.fibersPoolSize());
1070 TEST(FiberManager, remoteFiberBasic) {
1071 FiberManager manager(folly::make_unique<SimpleLoopController>());
1072 auto& loopController =
1073 dynamic_cast<SimpleLoopController&>(manager.loopController());
1076 result[0] = result[1] = 0;
1077 folly::Optional<Promise<int>> savedPromise[2];
1080 result[0] = await([&] (Promise<int> promise) {
1081 savedPromise[0] = std::move(promise);
1086 result[1] = await([&] (Promise<int> promise) {
1087 savedPromise[1] = std::move(promise);
1091 manager.loopUntilNoReady();
1093 EXPECT_TRUE(savedPromise[0].hasValue());
1094 EXPECT_TRUE(savedPromise[1].hasValue());
1095 EXPECT_EQ(0, result[0]);
1096 EXPECT_EQ(0, result[1]);
1098 std::thread remoteThread0{
1100 savedPromise[0]->setValue(42);
1103 std::thread remoteThread1{
1105 savedPromise[1]->setValue(43);
1108 remoteThread0.join();
1109 remoteThread1.join();
1110 EXPECT_EQ(0, result[0]);
1111 EXPECT_EQ(0, result[1]);
1112 /* Should only have scheduled once */
1113 EXPECT_EQ(1, loopController.remoteScheduleCalled());
1115 manager.loopUntilNoReady();
1116 EXPECT_EQ(42, result[0]);
1117 EXPECT_EQ(43, result[1]);
1120 TEST(FiberManager, addTaskRemoteBasic) {
1121 FiberManager manager(folly::make_unique<SimpleLoopController>());
1124 result[0] = result[1] = 0;
1125 folly::Optional<Promise<int>> savedPromise[2];
1127 std::thread remoteThread0{
1129 manager.addTaskRemote(
1131 result[0] = await([&] (Promise<int> promise) {
1132 savedPromise[0] = std::move(promise);
1137 std::thread remoteThread1{
1139 manager.addTaskRemote(
1141 result[1] = await([&] (Promise<int> promise) {
1142 savedPromise[1] = std::move(promise);
1147 remoteThread0.join();
1148 remoteThread1.join();
1150 manager.loopUntilNoReady();
1152 EXPECT_TRUE(savedPromise[0].hasValue());
1153 EXPECT_TRUE(savedPromise[1].hasValue());
1154 EXPECT_EQ(0, result[0]);
1155 EXPECT_EQ(0, result[1]);
1157 savedPromise[0]->setValue(42);
1158 savedPromise[1]->setValue(43);
1160 EXPECT_EQ(0, result[0]);
1161 EXPECT_EQ(0, result[1]);
1163 manager.loopUntilNoReady();
1164 EXPECT_EQ(42, result[0]);
1165 EXPECT_EQ(43, result[1]);
1168 TEST(FiberManager, remoteHasTasks) {
1170 FiberManager fm(folly::make_unique<SimpleLoopController>());
1171 std::thread remote([&]() {
1172 fm.addTaskRemote([&]() {
1179 while (fm.hasTasks()) {
1180 fm.loopUntilNoReady();
1183 EXPECT_FALSE(fm.hasTasks());
1184 EXPECT_EQ(counter, 1);
1187 TEST(FiberManager, remoteHasReadyTasks) {
1189 folly::Optional<Promise<int>> savedPromise;
1190 FiberManager fm(folly::make_unique<SimpleLoopController>());
1191 std::thread remote([&]() {
1192 fm.addTaskRemote([&]() {
1193 result = await([&](Promise<int> promise) {
1194 savedPromise = std::move(promise);
1196 EXPECT_TRUE(fm.hasTasks());
1201 EXPECT_TRUE(fm.hasTasks());
1203 fm.loopUntilNoReady();
1204 EXPECT_TRUE(fm.hasTasks());
1206 std::thread remote2([&](){
1207 savedPromise->setValue(47);
1210 EXPECT_TRUE(fm.hasTasks());
1212 fm.loopUntilNoReady();
1213 EXPECT_FALSE(fm.hasTasks());
1215 EXPECT_EQ(result, 47);
1218 template <typename Data>
1219 void testFiberLocal() {
1220 FiberManager fm(LocalType<Data>(),
1221 folly::make_unique<SimpleLoopController>());
1224 EXPECT_EQ(42, local<Data>().value);
1226 local<Data>().value = 43;
1229 EXPECT_EQ(43, local<Data>().value);
1231 local<Data>().value = 44;
1234 EXPECT_EQ(44, local<Data>().value);
1240 EXPECT_EQ(42, local<Data>().value);
1242 local<Data>().value = 43;
1244 fm.addTaskRemote([]() {
1245 EXPECT_EQ(43, local<Data>().value);
1250 EXPECT_EQ(42, local<Data>().value);
1251 local<Data>().value = 43;
1254 EXPECT_EQ(43, local<Data>().value);
1255 local<Data>().value = 44;
1257 std::vector<std::function<void()>> tasks{task};
1258 whenAny(tasks.begin(), tasks.end());
1260 EXPECT_EQ(43, local<Data>().value);
1263 fm.loopUntilNoReady();
1264 EXPECT_FALSE(fm.hasTasks());
1267 TEST(FiberManager, fiberLocal) {
1272 testFiberLocal<SimpleData>();
1275 TEST(FiberManager, fiberLocalHeap) {
1281 testFiberLocal<LargeData>();
1284 TEST(FiberManager, yieldTest) {
1285 FiberManager manager(folly::make_unique<SimpleLoopController>());
1286 auto& loopController =
1287 dynamic_cast<SimpleLoopController&>(manager.loopController());
1289 bool checkRan = false;
1298 loopController.loop(
1301 loopController.stop();
1306 EXPECT_TRUE(checkRan);
1309 static size_t sNumAwaits;
1311 void runBenchmark(size_t numAwaits, size_t toSend) {
1312 sNumAwaits = numAwaits;
1314 FiberManager fiberManager(folly::make_unique<SimpleLoopController>());
1315 auto& loopController =
1316 dynamic_cast<SimpleLoopController&>(fiberManager.loopController());
1318 std::queue<Promise<int>> pendingRequests;
1319 static const size_t maxOutstanding = 5;
1321 auto loop = [&fiberManager, &loopController, &pendingRequests, &toSend]() {
1322 if (pendingRequests.size() == maxOutstanding || toSend == 0) {
1323 if (pendingRequests.empty()) {
1326 pendingRequests.front().setValue(0);
1327 pendingRequests.pop();
1329 fiberManager.addTask([&pendingRequests]() {
1330 for (size_t i = 0; i < sNumAwaits; ++i) {
1331 auto result = await(
1332 [&pendingRequests](Promise<int> promise) {
1333 pendingRequests.push(std::move(promise));
1335 assert(result == 0);
1339 if (--toSend == 0) {
1340 loopController.stop();
1345 loopController.loop(std::move(loop));
1348 BENCHMARK(FiberManagerBasicOneAwait, iters) {
1349 runBenchmark(1, iters);
1352 BENCHMARK(FiberManagerBasicFiveAwaits, iters) {
1353 runBenchmark(5, iters);