c5b14f18e5218d229440597b08c237590eb8d795
[folly.git] / folly / experimental / fibers / test / FibersTest.cpp
1 /*
2  * Copyright 2016 Facebook, Inc.
3  *
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
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 #include <atomic>
17 #include <thread>
18 #include <vector>
19
20 #include <gtest/gtest.h>
21
22 #include <folly/Benchmark.h>
23 #include <folly/Memory.h>
24 #include <folly/futures/Future.h>
25
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>
33
34 using namespace folly::fibers;
35
36 using folly::Try;
37
38 TEST(FiberManager, batonTimedWaitTimeout) {
39   bool taskAdded = false;
40   size_t iterations = 0;
41
42   FiberManager manager(folly::make_unique<SimpleLoopController>());
43   auto& loopController =
44       dynamic_cast<SimpleLoopController&>(manager.loopController());
45
46   auto loopFunc = [&]() {
47     if (!taskAdded) {
48       manager.addTask([&]() {
49         Baton baton;
50
51         auto res = baton.timed_wait(std::chrono::milliseconds(230));
52
53         EXPECT_FALSE(res);
54         EXPECT_EQ(5, iterations);
55
56         loopController.stop();
57       });
58       manager.addTask([&]() {
59         Baton baton;
60
61         auto res = baton.timed_wait(std::chrono::milliseconds(130));
62
63         EXPECT_FALSE(res);
64         EXPECT_EQ(3, iterations);
65
66         loopController.stop();
67       });
68       taskAdded = true;
69     } else {
70       std::this_thread::sleep_for(std::chrono::milliseconds(50));
71       iterations++;
72     }
73   };
74
75   loopController.loop(std::move(loopFunc));
76 }
77
78 TEST(FiberManager, batonTimedWaitPost) {
79   bool taskAdded = false;
80   size_t iterations = 0;
81   Baton* baton_ptr;
82
83   FiberManager manager(folly::make_unique<SimpleLoopController>());
84   auto& loopController =
85       dynamic_cast<SimpleLoopController&>(manager.loopController());
86
87   auto loopFunc = [&]() {
88     if (!taskAdded) {
89       manager.addTask([&]() {
90         Baton baton;
91         baton_ptr = &baton;
92
93         auto res = baton.timed_wait(std::chrono::milliseconds(130));
94
95         EXPECT_TRUE(res);
96         EXPECT_EQ(2, iterations);
97
98         loopController.stop();
99       });
100       taskAdded = true;
101     } else {
102       std::this_thread::sleep_for(std::chrono::milliseconds(50));
103       iterations++;
104       if (iterations == 2) {
105         baton_ptr->post();
106       }
107     }
108   };
109
110   loopController.loop(std::move(loopFunc));
111 }
112
113 TEST(FiberManager, batonTimedWaitTimeoutEvb) {
114   size_t tasksComplete = 0;
115
116   folly::EventBase evb;
117
118   FiberManager manager(folly::make_unique<EventBaseLoopController>());
119   dynamic_cast<EventBaseLoopController&>(manager.loopController())
120       .attachEventBase(evb);
121
122   auto task = [&](size_t timeout_ms) {
123     Baton baton;
124
125     auto start = EventBaseLoopController::Clock::now();
126     auto res = baton.timed_wait(std::chrono::milliseconds(timeout_ms));
127     auto finish = EventBaseLoopController::Clock::now();
128
129     EXPECT_FALSE(res);
130
131     auto duration_ms =
132         std::chrono::duration_cast<std::chrono::milliseconds>(finish - start);
133
134     EXPECT_GT(duration_ms.count(), timeout_ms - 50);
135     EXPECT_LT(duration_ms.count(), timeout_ms + 50);
136
137     if (++tasksComplete == 2) {
138       evb.terminateLoopSoon();
139     }
140   };
141
142   evb.runInEventBaseThread([&]() {
143     manager.addTask([&]() { task(500); });
144     manager.addTask([&]() { task(250); });
145   });
146
147   evb.loopForever();
148
149   EXPECT_EQ(2, tasksComplete);
150 }
151
152 TEST(FiberManager, batonTimedWaitPostEvb) {
153   size_t tasksComplete = 0;
154
155   folly::EventBase evb;
156
157   FiberManager manager(folly::make_unique<EventBaseLoopController>());
158   dynamic_cast<EventBaseLoopController&>(manager.loopController())
159       .attachEventBase(evb);
160
161   evb.runInEventBaseThread([&]() {
162     manager.addTask([&]() {
163       Baton baton;
164
165       evb.tryRunAfterDelay([&]() { baton.post(); }, 100);
166
167       auto start = EventBaseLoopController::Clock::now();
168       auto res = baton.timed_wait(std::chrono::milliseconds(130));
169       auto finish = EventBaseLoopController::Clock::now();
170
171       EXPECT_TRUE(res);
172
173       auto duration_ms =
174           std::chrono::duration_cast<std::chrono::milliseconds>(finish - start);
175
176       EXPECT_TRUE(duration_ms.count() > 95 && duration_ms.count() < 110);
177
178       if (++tasksComplete == 1) {
179         evb.terminateLoopSoon();
180       }
181     });
182   });
183
184   evb.loopForever();
185
186   EXPECT_EQ(1, tasksComplete);
187 }
188
189 TEST(FiberManager, batonTryWait) {
190   FiberManager manager(folly::make_unique<SimpleLoopController>());
191
192   // Check if try_wait and post work as expected
193   Baton b;
194
195   manager.addTask([&]() {
196     while (!b.try_wait()) {
197     }
198   });
199   auto thr = std::thread([&]() {
200     std::this_thread::sleep_for(std::chrono::milliseconds(300));
201     b.post();
202   });
203
204   manager.loopUntilNoReady();
205   thr.join();
206
207   Baton c;
208
209   // Check try_wait without post
210   manager.addTask([&]() {
211     int cnt = 100;
212     while (cnt && !c.try_wait()) {
213       cnt--;
214     }
215     EXPECT_TRUE(!c.try_wait()); // must still hold
216     EXPECT_EQ(cnt, 0);
217   });
218
219   manager.loopUntilNoReady();
220 }
221
222 TEST(FiberManager, genericBatonFiberWait) {
223   FiberManager manager(folly::make_unique<SimpleLoopController>());
224
225   GenericBaton b;
226   bool fiberRunning = false;
227
228   manager.addTask([&]() {
229     EXPECT_EQ(manager.hasActiveFiber(), true);
230     fiberRunning = true;
231     b.wait();
232     fiberRunning = false;
233   });
234
235   EXPECT_FALSE(fiberRunning);
236   manager.loopUntilNoReady();
237   EXPECT_TRUE(fiberRunning); // ensure fiber still active
238
239   auto thr = std::thread([&]() {
240     std::this_thread::sleep_for(std::chrono::milliseconds(300));
241     b.post();
242   });
243
244   while (fiberRunning) {
245     manager.loopUntilNoReady();
246   }
247
248   thr.join();
249 }
250
251 TEST(FiberManager, genericBatonThreadWait) {
252   FiberManager manager(folly::make_unique<SimpleLoopController>());
253   GenericBaton b;
254   std::atomic<bool> threadWaiting(false);
255
256   auto thr = std::thread([&]() {
257     threadWaiting = true;
258     b.wait();
259     threadWaiting = false;
260   });
261
262   while (!threadWaiting) {
263   }
264   std::this_thread::sleep_for(std::chrono::milliseconds(300));
265
266   manager.addTask([&]() {
267     EXPECT_EQ(manager.hasActiveFiber(), true);
268     EXPECT_TRUE(threadWaiting);
269     b.post();
270     while (threadWaiting) {
271     }
272   });
273
274   manager.loopUntilNoReady();
275   thr.join();
276 }
277
278 TEST(FiberManager, addTasksNoncopyable) {
279   std::vector<Promise<int>> pendingFibers;
280   bool taskAdded = false;
281
282   FiberManager manager(folly::make_unique<SimpleLoopController>());
283   auto& loopController =
284       dynamic_cast<SimpleLoopController&>(manager.loopController());
285
286   auto loopFunc = [&]() {
287     if (!taskAdded) {
288       manager.addTask([&]() {
289         std::vector<std::function<std::unique_ptr<int>()>> funcs;
290         for (size_t i = 0; i < 3; ++i) {
291           funcs.push_back([i, &pendingFibers]() {
292             await([&pendingFibers](Promise<int> promise) {
293               pendingFibers.push_back(std::move(promise));
294             });
295             return folly::make_unique<int>(i * 2 + 1);
296           });
297         }
298
299         auto iter = addTasks(funcs.begin(), funcs.end());
300
301         size_t n = 0;
302         while (iter.hasNext()) {
303           auto result = iter.awaitNext();
304           EXPECT_EQ(2 * iter.getTaskID() + 1, *result);
305           EXPECT_GE(2 - n, pendingFibers.size());
306           ++n;
307         }
308         EXPECT_EQ(3, n);
309       });
310       taskAdded = true;
311     } else if (pendingFibers.size()) {
312       pendingFibers.back().setValue(0);
313       pendingFibers.pop_back();
314     } else {
315       loopController.stop();
316     }
317   };
318
319   loopController.loop(std::move(loopFunc));
320 }
321
322 TEST(FiberManager, addTasksThrow) {
323   std::vector<Promise<int>> pendingFibers;
324   bool taskAdded = false;
325
326   FiberManager manager(folly::make_unique<SimpleLoopController>());
327   auto& loopController =
328       dynamic_cast<SimpleLoopController&>(manager.loopController());
329
330   auto loopFunc = [&]() {
331     if (!taskAdded) {
332       manager.addTask([&]() {
333         std::vector<std::function<int()>> funcs;
334         for (size_t i = 0; i < 3; ++i) {
335           funcs.push_back([i, &pendingFibers]() {
336             await([&pendingFibers](Promise<int> promise) {
337               pendingFibers.push_back(std::move(promise));
338             });
339             if (i % 2 == 0) {
340               throw std::runtime_error("Runtime");
341             }
342             return i * 2 + 1;
343           });
344         }
345
346         auto iter = addTasks(funcs.begin(), funcs.end());
347
348         size_t n = 0;
349         while (iter.hasNext()) {
350           try {
351             int result = iter.awaitNext();
352             EXPECT_EQ(1, iter.getTaskID() % 2);
353             EXPECT_EQ(2 * iter.getTaskID() + 1, result);
354           } catch (...) {
355             EXPECT_EQ(0, iter.getTaskID() % 2);
356           }
357           EXPECT_GE(2 - n, pendingFibers.size());
358           ++n;
359         }
360         EXPECT_EQ(3, n);
361       });
362       taskAdded = true;
363     } else if (pendingFibers.size()) {
364       pendingFibers.back().setValue(0);
365       pendingFibers.pop_back();
366     } else {
367       loopController.stop();
368     }
369   };
370
371   loopController.loop(std::move(loopFunc));
372 }
373
374 TEST(FiberManager, addTasksVoid) {
375   std::vector<Promise<int>> pendingFibers;
376   bool taskAdded = false;
377
378   FiberManager manager(folly::make_unique<SimpleLoopController>());
379   auto& loopController =
380       dynamic_cast<SimpleLoopController&>(manager.loopController());
381
382   auto loopFunc = [&]() {
383     if (!taskAdded) {
384       manager.addTask([&]() {
385         std::vector<std::function<void()>> funcs;
386         for (size_t i = 0; i < 3; ++i) {
387           funcs.push_back([i, &pendingFibers]() {
388             await([&pendingFibers](Promise<int> promise) {
389               pendingFibers.push_back(std::move(promise));
390             });
391           });
392         }
393
394         auto iter = addTasks(funcs.begin(), funcs.end());
395
396         size_t n = 0;
397         while (iter.hasNext()) {
398           iter.awaitNext();
399           EXPECT_GE(2 - n, pendingFibers.size());
400           ++n;
401         }
402         EXPECT_EQ(3, n);
403       });
404       taskAdded = true;
405     } else if (pendingFibers.size()) {
406       pendingFibers.back().setValue(0);
407       pendingFibers.pop_back();
408     } else {
409       loopController.stop();
410     }
411   };
412
413   loopController.loop(std::move(loopFunc));
414 }
415
416 TEST(FiberManager, addTasksVoidThrow) {
417   std::vector<Promise<int>> pendingFibers;
418   bool taskAdded = false;
419
420   FiberManager manager(folly::make_unique<SimpleLoopController>());
421   auto& loopController =
422       dynamic_cast<SimpleLoopController&>(manager.loopController());
423
424   auto loopFunc = [&]() {
425     if (!taskAdded) {
426       manager.addTask([&]() {
427         std::vector<std::function<void()>> funcs;
428         for (size_t i = 0; i < 3; ++i) {
429           funcs.push_back([i, &pendingFibers]() {
430             await([&pendingFibers](Promise<int> promise) {
431               pendingFibers.push_back(std::move(promise));
432             });
433             if (i % 2 == 0) {
434               throw std::runtime_error("");
435             }
436           });
437         }
438
439         auto iter = addTasks(funcs.begin(), funcs.end());
440
441         size_t n = 0;
442         while (iter.hasNext()) {
443           try {
444             iter.awaitNext();
445             EXPECT_EQ(1, iter.getTaskID() % 2);
446           } catch (...) {
447             EXPECT_EQ(0, iter.getTaskID() % 2);
448           }
449           EXPECT_GE(2 - n, pendingFibers.size());
450           ++n;
451         }
452         EXPECT_EQ(3, n);
453       });
454       taskAdded = true;
455     } else if (pendingFibers.size()) {
456       pendingFibers.back().setValue(0);
457       pendingFibers.pop_back();
458     } else {
459       loopController.stop();
460     }
461   };
462
463   loopController.loop(std::move(loopFunc));
464 }
465
466 TEST(FiberManager, addTasksReserve) {
467   std::vector<Promise<int>> pendingFibers;
468   bool taskAdded = false;
469
470   FiberManager manager(folly::make_unique<SimpleLoopController>());
471   auto& loopController =
472       dynamic_cast<SimpleLoopController&>(manager.loopController());
473
474   auto loopFunc = [&]() {
475     if (!taskAdded) {
476       manager.addTask([&]() {
477         std::vector<std::function<void()>> funcs;
478         for (size_t i = 0; i < 3; ++i) {
479           funcs.push_back([&pendingFibers]() {
480             await([&pendingFibers](Promise<int> promise) {
481               pendingFibers.push_back(std::move(promise));
482             });
483           });
484         }
485
486         auto iter = addTasks(funcs.begin(), funcs.end());
487
488         iter.reserve(2);
489         EXPECT_TRUE(iter.hasCompleted());
490         EXPECT_TRUE(iter.hasPending());
491         EXPECT_TRUE(iter.hasNext());
492
493         iter.awaitNext();
494         EXPECT_TRUE(iter.hasCompleted());
495         EXPECT_TRUE(iter.hasPending());
496         EXPECT_TRUE(iter.hasNext());
497
498         iter.awaitNext();
499         EXPECT_FALSE(iter.hasCompleted());
500         EXPECT_TRUE(iter.hasPending());
501         EXPECT_TRUE(iter.hasNext());
502
503         iter.awaitNext();
504         EXPECT_FALSE(iter.hasCompleted());
505         EXPECT_FALSE(iter.hasPending());
506         EXPECT_FALSE(iter.hasNext());
507       });
508       taskAdded = true;
509     } else if (pendingFibers.size()) {
510       pendingFibers.back().setValue(0);
511       pendingFibers.pop_back();
512     } else {
513       loopController.stop();
514     }
515   };
516
517   loopController.loop(std::move(loopFunc));
518 }
519
520 TEST(FiberManager, addTaskDynamic) {
521   folly::EventBase evb;
522
523   Baton batons[3];
524
525   auto makeTask = [&](size_t taskId) {
526     return [&, taskId]() -> size_t {
527       batons[taskId].wait();
528       return taskId;
529     };
530   };
531
532   getFiberManager(evb)
533       .addTaskFuture([&]() {
534         TaskIterator<size_t> iterator;
535
536         iterator.addTask(makeTask(0));
537         iterator.addTask(makeTask(1));
538
539         batons[1].post();
540
541         EXPECT_EQ(1, iterator.awaitNext());
542
543         iterator.addTask(makeTask(2));
544
545         batons[2].post();
546
547         EXPECT_EQ(2, iterator.awaitNext());
548
549         batons[0].post();
550
551         EXPECT_EQ(0, iterator.awaitNext());
552       })
553       .waitVia(&evb);
554 }
555
556 TEST(FiberManager, forEach) {
557   std::vector<Promise<int>> pendingFibers;
558   bool taskAdded = false;
559
560   FiberManager manager(folly::make_unique<SimpleLoopController>());
561   auto& loopController =
562       dynamic_cast<SimpleLoopController&>(manager.loopController());
563
564   auto loopFunc = [&]() {
565     if (!taskAdded) {
566       manager.addTask([&]() {
567         std::vector<std::function<int()>> funcs;
568         for (size_t i = 0; i < 3; ++i) {
569           funcs.push_back([i, &pendingFibers]() {
570             await([&pendingFibers](Promise<int> promise) {
571               pendingFibers.push_back(std::move(promise));
572             });
573             return i * 2 + 1;
574           });
575         }
576
577         std::vector<std::pair<size_t, int>> results;
578         forEach(funcs.begin(), funcs.end(), [&results](size_t id, int result) {
579           results.emplace_back(id, result);
580         });
581         EXPECT_EQ(3, results.size());
582         EXPECT_TRUE(pendingFibers.empty());
583         for (size_t i = 0; i < 3; ++i) {
584           EXPECT_EQ(results[i].first * 2 + 1, results[i].second);
585         }
586       });
587       taskAdded = true;
588     } else if (pendingFibers.size()) {
589       pendingFibers.back().setValue(0);
590       pendingFibers.pop_back();
591     } else {
592       loopController.stop();
593     }
594   };
595
596   loopController.loop(std::move(loopFunc));
597 }
598
599 TEST(FiberManager, collectN) {
600   std::vector<Promise<int>> pendingFibers;
601   bool taskAdded = false;
602
603   FiberManager manager(folly::make_unique<SimpleLoopController>());
604   auto& loopController =
605       dynamic_cast<SimpleLoopController&>(manager.loopController());
606
607   auto loopFunc = [&]() {
608     if (!taskAdded) {
609       manager.addTask([&]() {
610         std::vector<std::function<int()>> funcs;
611         for (size_t i = 0; i < 3; ++i) {
612           funcs.push_back([i, &pendingFibers]() {
613             await([&pendingFibers](Promise<int> promise) {
614               pendingFibers.push_back(std::move(promise));
615             });
616             return i * 2 + 1;
617           });
618         }
619
620         auto results = collectN(funcs.begin(), funcs.end(), 2);
621         EXPECT_EQ(2, results.size());
622         EXPECT_EQ(1, pendingFibers.size());
623         for (size_t i = 0; i < 2; ++i) {
624           EXPECT_EQ(results[i].first * 2 + 1, results[i].second);
625         }
626       });
627       taskAdded = true;
628     } else if (pendingFibers.size()) {
629       pendingFibers.back().setValue(0);
630       pendingFibers.pop_back();
631     } else {
632       loopController.stop();
633     }
634   };
635
636   loopController.loop(std::move(loopFunc));
637 }
638
639 TEST(FiberManager, collectNThrow) {
640   std::vector<Promise<int>> pendingFibers;
641   bool taskAdded = false;
642
643   FiberManager manager(folly::make_unique<SimpleLoopController>());
644   auto& loopController =
645       dynamic_cast<SimpleLoopController&>(manager.loopController());
646
647   auto loopFunc = [&]() {
648     if (!taskAdded) {
649       manager.addTask([&]() {
650         std::vector<std::function<int()>> funcs;
651         for (size_t i = 0; i < 3; ++i) {
652           funcs.push_back([i, &pendingFibers]() {
653             await([&pendingFibers](Promise<int> promise) {
654               pendingFibers.push_back(std::move(promise));
655             });
656             throw std::runtime_error("Runtime");
657             return i * 2 + 1;
658           });
659         }
660
661         try {
662           collectN(funcs.begin(), funcs.end(), 2);
663         } catch (...) {
664           EXPECT_EQ(1, pendingFibers.size());
665         }
666       });
667       taskAdded = true;
668     } else if (pendingFibers.size()) {
669       pendingFibers.back().setValue(0);
670       pendingFibers.pop_back();
671     } else {
672       loopController.stop();
673     }
674   };
675
676   loopController.loop(std::move(loopFunc));
677 }
678
679 TEST(FiberManager, collectNVoid) {
680   std::vector<Promise<int>> pendingFibers;
681   bool taskAdded = false;
682
683   FiberManager manager(folly::make_unique<SimpleLoopController>());
684   auto& loopController =
685       dynamic_cast<SimpleLoopController&>(manager.loopController());
686
687   auto loopFunc = [&]() {
688     if (!taskAdded) {
689       manager.addTask([&]() {
690         std::vector<std::function<void()>> funcs;
691         for (size_t i = 0; i < 3; ++i) {
692           funcs.push_back([i, &pendingFibers]() {
693             await([&pendingFibers](Promise<int> promise) {
694               pendingFibers.push_back(std::move(promise));
695             });
696           });
697         }
698
699         auto results = collectN(funcs.begin(), funcs.end(), 2);
700         EXPECT_EQ(2, results.size());
701         EXPECT_EQ(1, pendingFibers.size());
702       });
703       taskAdded = true;
704     } else if (pendingFibers.size()) {
705       pendingFibers.back().setValue(0);
706       pendingFibers.pop_back();
707     } else {
708       loopController.stop();
709     }
710   };
711
712   loopController.loop(std::move(loopFunc));
713 }
714
715 TEST(FiberManager, collectNVoidThrow) {
716   std::vector<Promise<int>> pendingFibers;
717   bool taskAdded = false;
718
719   FiberManager manager(folly::make_unique<SimpleLoopController>());
720   auto& loopController =
721       dynamic_cast<SimpleLoopController&>(manager.loopController());
722
723   auto loopFunc = [&]() {
724     if (!taskAdded) {
725       manager.addTask([&]() {
726         std::vector<std::function<void()>> funcs;
727         for (size_t i = 0; i < 3; ++i) {
728           funcs.push_back([i, &pendingFibers]() {
729             await([&pendingFibers](Promise<int> promise) {
730               pendingFibers.push_back(std::move(promise));
731             });
732             throw std::runtime_error("Runtime");
733           });
734         }
735
736         try {
737           collectN(funcs.begin(), funcs.end(), 2);
738         } catch (...) {
739           EXPECT_EQ(1, pendingFibers.size());
740         }
741       });
742       taskAdded = true;
743     } else if (pendingFibers.size()) {
744       pendingFibers.back().setValue(0);
745       pendingFibers.pop_back();
746     } else {
747       loopController.stop();
748     }
749   };
750
751   loopController.loop(std::move(loopFunc));
752 }
753
754 TEST(FiberManager, collectAll) {
755   std::vector<Promise<int>> pendingFibers;
756   bool taskAdded = false;
757
758   FiberManager manager(folly::make_unique<SimpleLoopController>());
759   auto& loopController =
760       dynamic_cast<SimpleLoopController&>(manager.loopController());
761
762   auto loopFunc = [&]() {
763     if (!taskAdded) {
764       manager.addTask([&]() {
765         std::vector<std::function<int()>> funcs;
766         for (size_t i = 0; i < 3; ++i) {
767           funcs.push_back([i, &pendingFibers]() {
768             await([&pendingFibers](Promise<int> promise) {
769               pendingFibers.push_back(std::move(promise));
770             });
771             return i * 2 + 1;
772           });
773         }
774
775         auto results = collectAll(funcs.begin(), funcs.end());
776         EXPECT_TRUE(pendingFibers.empty());
777         for (size_t i = 0; i < 3; ++i) {
778           EXPECT_EQ(i * 2 + 1, results[i]);
779         }
780       });
781       taskAdded = true;
782     } else if (pendingFibers.size()) {
783       pendingFibers.back().setValue(0);
784       pendingFibers.pop_back();
785     } else {
786       loopController.stop();
787     }
788   };
789
790   loopController.loop(std::move(loopFunc));
791 }
792
793 TEST(FiberManager, collectAllVoid) {
794   std::vector<Promise<int>> pendingFibers;
795   bool taskAdded = false;
796
797   FiberManager manager(folly::make_unique<SimpleLoopController>());
798   auto& loopController =
799       dynamic_cast<SimpleLoopController&>(manager.loopController());
800
801   auto loopFunc = [&]() {
802     if (!taskAdded) {
803       manager.addTask([&]() {
804         std::vector<std::function<void()>> funcs;
805         for (size_t i = 0; i < 3; ++i) {
806           funcs.push_back([i, &pendingFibers]() {
807             await([&pendingFibers](Promise<int> promise) {
808               pendingFibers.push_back(std::move(promise));
809             });
810           });
811         }
812
813         collectAll(funcs.begin(), funcs.end());
814         EXPECT_TRUE(pendingFibers.empty());
815       });
816       taskAdded = true;
817     } else if (pendingFibers.size()) {
818       pendingFibers.back().setValue(0);
819       pendingFibers.pop_back();
820     } else {
821       loopController.stop();
822     }
823   };
824
825   loopController.loop(std::move(loopFunc));
826 }
827
828 TEST(FiberManager, collectAny) {
829   std::vector<Promise<int>> pendingFibers;
830   bool taskAdded = false;
831
832   FiberManager manager(folly::make_unique<SimpleLoopController>());
833   auto& loopController =
834       dynamic_cast<SimpleLoopController&>(manager.loopController());
835
836   auto loopFunc = [&]() {
837     if (!taskAdded) {
838       manager.addTask([&]() {
839         std::vector<std::function<int()>> funcs;
840         for (size_t i = 0; i < 3; ++i) {
841           funcs.push_back([i, &pendingFibers]() {
842             await([&pendingFibers](Promise<int> promise) {
843               pendingFibers.push_back(std::move(promise));
844             });
845             if (i == 1) {
846               throw std::runtime_error("This exception will be ignored");
847             }
848             return i * 2 + 1;
849           });
850         }
851
852         auto result = collectAny(funcs.begin(), funcs.end());
853         EXPECT_EQ(2, pendingFibers.size());
854         EXPECT_EQ(2, result.first);
855         EXPECT_EQ(2 * 2 + 1, result.second);
856       });
857       taskAdded = true;
858     } else if (pendingFibers.size()) {
859       pendingFibers.back().setValue(0);
860       pendingFibers.pop_back();
861     } else {
862       loopController.stop();
863     }
864   };
865
866   loopController.loop(std::move(loopFunc));
867 }
868
869 namespace {
870 /* Checks that this function was run from a main context,
871    by comparing an address on a stack to a known main stack address
872    and a known related fiber stack address.  The assumption
873    is that fiber stack and main stack will be far enough apart,
874    while any two values on the same stack will be close. */
875 void expectMainContext(bool& ran, int* mainLocation, int* fiberLocation) {
876   int here;
877   /* 2 pages is a good guess */
878   constexpr ssize_t DISTANCE = 0x2000 / sizeof(int);
879   if (fiberLocation) {
880     EXPECT_TRUE(std::abs(&here - fiberLocation) > DISTANCE);
881   }
882   if (mainLocation) {
883     EXPECT_TRUE(std::abs(&here - mainLocation) < DISTANCE);
884   }
885
886   EXPECT_FALSE(ran);
887   ran = true;
888 }
889 }
890
891 TEST(FiberManager, runInMainContext) {
892   FiberManager manager(folly::make_unique<SimpleLoopController>());
893   auto& loopController =
894       dynamic_cast<SimpleLoopController&>(manager.loopController());
895
896   bool checkRan = false;
897
898   int mainLocation;
899   manager.runInMainContext(
900       [&]() { expectMainContext(checkRan, &mainLocation, nullptr); });
901   EXPECT_TRUE(checkRan);
902
903   checkRan = false;
904
905   manager.addTask([&]() {
906     struct A {
907       explicit A(int value_) : value(value_) {}
908       A(const A&) = delete;
909       A(A&&) = default;
910
911       int value;
912     };
913     int stackLocation;
914     auto ret = runInMainContext([&]() {
915       expectMainContext(checkRan, &mainLocation, &stackLocation);
916       return A(42);
917     });
918     EXPECT_TRUE(checkRan);
919     EXPECT_EQ(42, ret.value);
920   });
921
922   loopController.loop([&]() { loopController.stop(); });
923
924   EXPECT_TRUE(checkRan);
925 }
926
927 TEST(FiberManager, addTaskFinally) {
928   FiberManager manager(folly::make_unique<SimpleLoopController>());
929   auto& loopController =
930       dynamic_cast<SimpleLoopController&>(manager.loopController());
931
932   bool checkRan = false;
933
934   int mainLocation;
935
936   manager.addTaskFinally(
937       [&]() { return 1234; },
938       [&](Try<int>&& result) {
939         EXPECT_EQ(result.value(), 1234);
940
941         expectMainContext(checkRan, &mainLocation, nullptr);
942       });
943
944   EXPECT_FALSE(checkRan);
945
946   loopController.loop([&]() { loopController.stop(); });
947
948   EXPECT_TRUE(checkRan);
949 }
950
951 TEST(FiberManager, fibersPoolWithinLimit) {
952   FiberManager::Options opts;
953   opts.maxFibersPoolSize = 5;
954
955   FiberManager manager(folly::make_unique<SimpleLoopController>(), opts);
956   auto& loopController =
957       dynamic_cast<SimpleLoopController&>(manager.loopController());
958
959   size_t fibersRun = 0;
960
961   for (size_t i = 0; i < 5; ++i) {
962     manager.addTask([&]() { ++fibersRun; });
963   }
964   loopController.loop([&]() { loopController.stop(); });
965
966   EXPECT_EQ(5, fibersRun);
967   EXPECT_EQ(5, manager.fibersAllocated());
968   EXPECT_EQ(5, manager.fibersPoolSize());
969
970   for (size_t i = 0; i < 5; ++i) {
971     manager.addTask([&]() { ++fibersRun; });
972   }
973   loopController.loop([&]() { loopController.stop(); });
974
975   EXPECT_EQ(10, fibersRun);
976   EXPECT_EQ(5, manager.fibersAllocated());
977   EXPECT_EQ(5, manager.fibersPoolSize());
978 }
979
980 TEST(FiberManager, fibersPoolOverLimit) {
981   FiberManager::Options opts;
982   opts.maxFibersPoolSize = 5;
983
984   FiberManager manager(folly::make_unique<SimpleLoopController>(), opts);
985   auto& loopController =
986       dynamic_cast<SimpleLoopController&>(manager.loopController());
987
988   size_t fibersRun = 0;
989
990   for (size_t i = 0; i < 10; ++i) {
991     manager.addTask([&]() { ++fibersRun; });
992   }
993
994   EXPECT_EQ(0, fibersRun);
995   EXPECT_EQ(10, manager.fibersAllocated());
996   EXPECT_EQ(0, manager.fibersPoolSize());
997
998   loopController.loop([&]() { loopController.stop(); });
999
1000   EXPECT_EQ(10, fibersRun);
1001   EXPECT_EQ(5, manager.fibersAllocated());
1002   EXPECT_EQ(5, manager.fibersPoolSize());
1003 }
1004
1005 TEST(FiberManager, remoteFiberBasic) {
1006   FiberManager manager(folly::make_unique<SimpleLoopController>());
1007   auto& loopController =
1008       dynamic_cast<SimpleLoopController&>(manager.loopController());
1009
1010   int result[2];
1011   result[0] = result[1] = 0;
1012   folly::Optional<Promise<int>> savedPromise[2];
1013   manager.addTask([&]() {
1014     result[0] = await(
1015         [&](Promise<int> promise) { savedPromise[0] = std::move(promise); });
1016   });
1017   manager.addTask([&]() {
1018     result[1] = await(
1019         [&](Promise<int> promise) { savedPromise[1] = std::move(promise); });
1020   });
1021
1022   manager.loopUntilNoReady();
1023
1024   EXPECT_TRUE(savedPromise[0].hasValue());
1025   EXPECT_TRUE(savedPromise[1].hasValue());
1026   EXPECT_EQ(0, result[0]);
1027   EXPECT_EQ(0, result[1]);
1028
1029   std::thread remoteThread0{[&]() { savedPromise[0]->setValue(42); }};
1030   std::thread remoteThread1{[&]() { savedPromise[1]->setValue(43); }};
1031   remoteThread0.join();
1032   remoteThread1.join();
1033   EXPECT_EQ(0, result[0]);
1034   EXPECT_EQ(0, result[1]);
1035   /* Should only have scheduled once */
1036   EXPECT_EQ(1, loopController.remoteScheduleCalled());
1037
1038   manager.loopUntilNoReady();
1039   EXPECT_EQ(42, result[0]);
1040   EXPECT_EQ(43, result[1]);
1041 }
1042
1043 TEST(FiberManager, addTaskRemoteBasic) {
1044   FiberManager manager(folly::make_unique<SimpleLoopController>());
1045
1046   int result[2];
1047   result[0] = result[1] = 0;
1048   folly::Optional<Promise<int>> savedPromise[2];
1049
1050   std::thread remoteThread0{[&]() {
1051     manager.addTaskRemote([&]() {
1052       result[0] = await(
1053           [&](Promise<int> promise) { savedPromise[0] = std::move(promise); });
1054     });
1055   }};
1056   std::thread remoteThread1{[&]() {
1057     manager.addTaskRemote([&]() {
1058       result[1] = await(
1059           [&](Promise<int> promise) { savedPromise[1] = std::move(promise); });
1060     });
1061   }};
1062   remoteThread0.join();
1063   remoteThread1.join();
1064
1065   manager.loopUntilNoReady();
1066
1067   EXPECT_TRUE(savedPromise[0].hasValue());
1068   EXPECT_TRUE(savedPromise[1].hasValue());
1069   EXPECT_EQ(0, result[0]);
1070   EXPECT_EQ(0, result[1]);
1071
1072   savedPromise[0]->setValue(42);
1073   savedPromise[1]->setValue(43);
1074
1075   EXPECT_EQ(0, result[0]);
1076   EXPECT_EQ(0, result[1]);
1077
1078   manager.loopUntilNoReady();
1079   EXPECT_EQ(42, result[0]);
1080   EXPECT_EQ(43, result[1]);
1081 }
1082
1083 TEST(FiberManager, remoteHasTasks) {
1084   size_t counter = 0;
1085   FiberManager fm(folly::make_unique<SimpleLoopController>());
1086   std::thread remote([&]() { fm.addTaskRemote([&]() { ++counter; }); });
1087
1088   remote.join();
1089
1090   while (fm.hasTasks()) {
1091     fm.loopUntilNoReady();
1092   }
1093
1094   EXPECT_FALSE(fm.hasTasks());
1095   EXPECT_EQ(counter, 1);
1096 }
1097
1098 TEST(FiberManager, remoteHasReadyTasks) {
1099   int result = 0;
1100   folly::Optional<Promise<int>> savedPromise;
1101   FiberManager fm(folly::make_unique<SimpleLoopController>());
1102   std::thread remote([&]() {
1103     fm.addTaskRemote([&]() {
1104       result = await(
1105           [&](Promise<int> promise) { savedPromise = std::move(promise); });
1106       EXPECT_TRUE(fm.hasTasks());
1107     });
1108   });
1109
1110   remote.join();
1111   EXPECT_TRUE(fm.hasTasks());
1112
1113   fm.loopUntilNoReady();
1114   EXPECT_TRUE(fm.hasTasks());
1115
1116   std::thread remote2([&]() { savedPromise->setValue(47); });
1117   remote2.join();
1118   EXPECT_TRUE(fm.hasTasks());
1119
1120   fm.loopUntilNoReady();
1121   EXPECT_FALSE(fm.hasTasks());
1122
1123   EXPECT_EQ(result, 47);
1124 }
1125
1126 template <typename Data>
1127 void testFiberLocal() {
1128   FiberManager fm(
1129       LocalType<Data>(), folly::make_unique<SimpleLoopController>());
1130
1131   fm.addTask([]() {
1132     EXPECT_EQ(42, local<Data>().value);
1133
1134     local<Data>().value = 43;
1135
1136     addTask([]() {
1137       EXPECT_EQ(43, local<Data>().value);
1138
1139       local<Data>().value = 44;
1140
1141       addTask([]() { EXPECT_EQ(44, local<Data>().value); });
1142     });
1143   });
1144
1145   fm.addTask([&]() {
1146     EXPECT_EQ(42, local<Data>().value);
1147
1148     local<Data>().value = 43;
1149
1150     fm.addTaskRemote([]() { EXPECT_EQ(43, local<Data>().value); });
1151   });
1152
1153   fm.addTask([]() {
1154     EXPECT_EQ(42, local<Data>().value);
1155     local<Data>().value = 43;
1156
1157     auto task = []() {
1158       EXPECT_EQ(43, local<Data>().value);
1159       local<Data>().value = 44;
1160     };
1161     std::vector<std::function<void()>> tasks{task};
1162     collectAny(tasks.begin(), tasks.end());
1163
1164     EXPECT_EQ(43, local<Data>().value);
1165   });
1166
1167   fm.loopUntilNoReady();
1168   EXPECT_FALSE(fm.hasTasks());
1169 }
1170
1171 TEST(FiberManager, fiberLocal) {
1172   struct SimpleData {
1173     int value{42};
1174   };
1175
1176   testFiberLocal<SimpleData>();
1177 }
1178
1179 TEST(FiberManager, fiberLocalHeap) {
1180   struct LargeData {
1181     char _[1024 * 1024];
1182     int value{42};
1183   };
1184
1185   testFiberLocal<LargeData>();
1186 }
1187
1188 TEST(FiberManager, fiberLocalDestructor) {
1189   struct CrazyData {
1190     size_t data{42};
1191
1192     ~CrazyData() {
1193       if (data == 41) {
1194         addTask([]() {
1195           EXPECT_EQ(42, local<CrazyData>().data);
1196           // Make sure we don't have infinite loop
1197           local<CrazyData>().data = 0;
1198         });
1199       }
1200     }
1201   };
1202
1203   FiberManager fm(
1204       LocalType<CrazyData>(), folly::make_unique<SimpleLoopController>());
1205
1206   fm.addTask([]() { local<CrazyData>().data = 41; });
1207
1208   fm.loopUntilNoReady();
1209   EXPECT_FALSE(fm.hasTasks());
1210 }
1211
1212 TEST(FiberManager, yieldTest) {
1213   FiberManager manager(folly::make_unique<SimpleLoopController>());
1214   auto& loopController =
1215       dynamic_cast<SimpleLoopController&>(manager.loopController());
1216
1217   bool checkRan = false;
1218
1219   manager.addTask([&]() {
1220     manager.yield();
1221     checkRan = true;
1222   });
1223
1224   loopController.loop([&]() {
1225     if (checkRan) {
1226       loopController.stop();
1227     }
1228   });
1229
1230   EXPECT_TRUE(checkRan);
1231 }
1232
1233 TEST(FiberManager, RequestContext) {
1234   FiberManager fm(folly::make_unique<SimpleLoopController>());
1235
1236   bool checkRun1 = false;
1237   bool checkRun2 = false;
1238   bool checkRun3 = false;
1239   bool checkRun4 = false;
1240   folly::fibers::Baton baton1;
1241   folly::fibers::Baton baton2;
1242   folly::fibers::Baton baton3;
1243   folly::fibers::Baton baton4;
1244
1245   folly::RequestContext::create();
1246   auto rcontext1 = folly::RequestContext::get();
1247   fm.addTask([&]() {
1248     EXPECT_EQ(rcontext1, folly::RequestContext::get());
1249     baton1.wait([&]() { EXPECT_EQ(rcontext1, folly::RequestContext::get()); });
1250     EXPECT_EQ(rcontext1, folly::RequestContext::get());
1251     runInMainContext(
1252         [&]() { EXPECT_EQ(rcontext1, folly::RequestContext::get()); });
1253     checkRun1 = true;
1254   });
1255
1256   folly::RequestContext::create();
1257   auto rcontext2 = folly::RequestContext::get();
1258   fm.addTaskRemote([&]() {
1259     EXPECT_EQ(rcontext2, folly::RequestContext::get());
1260     baton2.wait();
1261     EXPECT_EQ(rcontext2, folly::RequestContext::get());
1262     checkRun2 = true;
1263   });
1264
1265   folly::RequestContext::create();
1266   auto rcontext3 = folly::RequestContext::get();
1267   fm.addTaskFinally(
1268       [&]() {
1269         EXPECT_EQ(rcontext3, folly::RequestContext::get());
1270         baton3.wait();
1271         EXPECT_EQ(rcontext3, folly::RequestContext::get());
1272
1273         return folly::Unit();
1274       },
1275       [&](Try<folly::Unit>&& /* t */) {
1276         EXPECT_EQ(rcontext3, folly::RequestContext::get());
1277         checkRun3 = true;
1278       });
1279
1280   folly::RequestContext::setContext(nullptr);
1281   fm.addTask([&]() {
1282     folly::RequestContext::create();
1283     auto rcontext4 = folly::RequestContext::get();
1284     baton4.wait();
1285     EXPECT_EQ(rcontext4, folly::RequestContext::get());
1286     checkRun4 = true;
1287   });
1288
1289   folly::RequestContext::create();
1290   auto rcontext = folly::RequestContext::get();
1291
1292   fm.loopUntilNoReady();
1293   EXPECT_EQ(rcontext, folly::RequestContext::get());
1294
1295   baton1.post();
1296   EXPECT_EQ(rcontext, folly::RequestContext::get());
1297   fm.loopUntilNoReady();
1298   EXPECT_TRUE(checkRun1);
1299   EXPECT_EQ(rcontext, folly::RequestContext::get());
1300
1301   baton2.post();
1302   EXPECT_EQ(rcontext, folly::RequestContext::get());
1303   fm.loopUntilNoReady();
1304   EXPECT_TRUE(checkRun2);
1305   EXPECT_EQ(rcontext, folly::RequestContext::get());
1306
1307   baton3.post();
1308   EXPECT_EQ(rcontext, folly::RequestContext::get());
1309   fm.loopUntilNoReady();
1310   EXPECT_TRUE(checkRun3);
1311   EXPECT_EQ(rcontext, folly::RequestContext::get());
1312
1313   baton4.post();
1314   EXPECT_EQ(rcontext, folly::RequestContext::get());
1315   fm.loopUntilNoReady();
1316   EXPECT_TRUE(checkRun4);
1317   EXPECT_EQ(rcontext, folly::RequestContext::get());
1318 }
1319
1320 TEST(FiberManager, resizePeriodically) {
1321   FiberManager::Options opts;
1322   opts.fibersPoolResizePeriodMs = 300;
1323   opts.maxFibersPoolSize = 5;
1324
1325   FiberManager manager(folly::make_unique<EventBaseLoopController>(), opts);
1326
1327   folly::EventBase evb;
1328   dynamic_cast<EventBaseLoopController&>(manager.loopController())
1329       .attachEventBase(evb);
1330
1331   std::vector<Baton> batons(10);
1332
1333   size_t tasksRun = 0;
1334   for (size_t i = 0; i < 30; ++i) {
1335     manager.addTask([i, &batons, &tasksRun]() {
1336       ++tasksRun;
1337       // Keep some fibers active indefinitely
1338       if (i < batons.size()) {
1339         batons[i].wait();
1340       }
1341     });
1342   }
1343
1344   EXPECT_EQ(0, tasksRun);
1345   EXPECT_EQ(30, manager.fibersAllocated());
1346   EXPECT_EQ(0, manager.fibersPoolSize());
1347
1348   evb.loopOnce();
1349   EXPECT_EQ(30, tasksRun);
1350   EXPECT_EQ(30, manager.fibersAllocated());
1351   // Can go over maxFibersPoolSize, 10 of 30 fibers still active
1352   EXPECT_EQ(20, manager.fibersPoolSize());
1353
1354   std::this_thread::sleep_for(std::chrono::milliseconds(400));
1355   evb.loopOnce(); // no fibers active in this period
1356   EXPECT_EQ(30, manager.fibersAllocated());
1357   EXPECT_EQ(20, manager.fibersPoolSize());
1358
1359   std::this_thread::sleep_for(std::chrono::milliseconds(400));
1360   evb.loopOnce(); // should shrink fibers pool to maxFibersPoolSize
1361   EXPECT_EQ(15, manager.fibersAllocated());
1362   EXPECT_EQ(5, manager.fibersPoolSize());
1363
1364   for (size_t i = 0; i < batons.size(); ++i) {
1365     batons[i].post();
1366   }
1367   evb.loopOnce();
1368   EXPECT_EQ(15, manager.fibersAllocated());
1369   EXPECT_EQ(15, manager.fibersPoolSize());
1370
1371   std::this_thread::sleep_for(std::chrono::milliseconds(400));
1372   evb.loopOnce(); // 10 fibers active in last period
1373   EXPECT_EQ(10, manager.fibersAllocated());
1374   EXPECT_EQ(10, manager.fibersPoolSize());
1375
1376   std::this_thread::sleep_for(std::chrono::milliseconds(400));
1377   evb.loopOnce();
1378   EXPECT_EQ(5, manager.fibersAllocated());
1379   EXPECT_EQ(5, manager.fibersPoolSize());
1380 }
1381
1382 TEST(FiberManager, batonWaitTimeoutHandler) {
1383   FiberManager manager(folly::make_unique<EventBaseLoopController>());
1384
1385   folly::EventBase evb;
1386   dynamic_cast<EventBaseLoopController&>(manager.loopController())
1387       .attachEventBase(evb);
1388
1389   size_t fibersRun = 0;
1390   Baton baton;
1391   Baton::TimeoutHandler timeoutHandler;
1392
1393   manager.addTask([&]() {
1394     baton.wait(timeoutHandler);
1395     ++fibersRun;
1396   });
1397   manager.loopUntilNoReady();
1398
1399   EXPECT_FALSE(baton.try_wait());
1400   EXPECT_EQ(0, fibersRun);
1401
1402   timeoutHandler.scheduleTimeout(std::chrono::milliseconds(250));
1403   std::this_thread::sleep_for(std::chrono::milliseconds(500));
1404
1405   EXPECT_FALSE(baton.try_wait());
1406   EXPECT_EQ(0, fibersRun);
1407
1408   evb.loopOnce();
1409   manager.loopUntilNoReady();
1410
1411   EXPECT_EQ(1, fibersRun);
1412 }
1413
1414 TEST(FiberManager, batonWaitTimeoutMany) {
1415   FiberManager manager(folly::make_unique<EventBaseLoopController>());
1416
1417   folly::EventBase evb;
1418   dynamic_cast<EventBaseLoopController&>(manager.loopController())
1419       .attachEventBase(evb);
1420
1421   constexpr size_t kNumTimeoutTasks = 10000;
1422   size_t tasksCount = kNumTimeoutTasks;
1423
1424   // We add many tasks to hit timeout queue deallocation logic.
1425   for (size_t i = 0; i < kNumTimeoutTasks; ++i) {
1426     manager.addTask([&]() {
1427       Baton baton;
1428       Baton::TimeoutHandler timeoutHandler;
1429
1430       folly::fibers::addTask([&] {
1431         timeoutHandler.scheduleTimeout(std::chrono::milliseconds(1000));
1432       });
1433
1434       baton.wait(timeoutHandler);
1435       if (--tasksCount == 0) {
1436         evb.terminateLoopSoon();
1437       }
1438     });
1439   }
1440
1441   evb.loopForever();
1442 }
1443
1444 TEST(FiberManager, remoteFutureTest) {
1445   FiberManager fiberManager(folly::make_unique<SimpleLoopController>());
1446   auto& loopController =
1447       dynamic_cast<SimpleLoopController&>(fiberManager.loopController());
1448
1449   int testValue1 = 5;
1450   int testValue2 = 7;
1451   auto f1 = fiberManager.addTaskFuture([&]() { return testValue1; });
1452   auto f2 = fiberManager.addTaskRemoteFuture([&]() { return testValue2; });
1453   loopController.loop([&]() { loopController.stop(); });
1454   auto v1 = f1.get();
1455   auto v2 = f2.get();
1456
1457   EXPECT_EQ(v1, testValue1);
1458   EXPECT_EQ(v2, testValue2);
1459 }
1460
1461 // Test that a void function produes a Future<Unit>.
1462 TEST(FiberManager, remoteFutureVoidUnitTest) {
1463   FiberManager fiberManager(folly::make_unique<SimpleLoopController>());
1464   auto& loopController =
1465       dynamic_cast<SimpleLoopController&>(fiberManager.loopController());
1466
1467   bool ranLocal = false;
1468   folly::Future<folly::Unit> futureLocal =
1469       fiberManager.addTaskFuture([&]() { ranLocal = true; });
1470
1471   bool ranRemote = false;
1472   folly::Future<folly::Unit> futureRemote =
1473       fiberManager.addTaskRemoteFuture([&]() { ranRemote = true; });
1474
1475   loopController.loop([&]() { loopController.stop(); });
1476
1477   futureLocal.wait();
1478   ASSERT_TRUE(ranLocal);
1479
1480   futureRemote.wait();
1481   ASSERT_TRUE(ranRemote);
1482 }
1483
1484 TEST(FiberManager, nestedFiberManagers) {
1485   folly::EventBase outerEvb;
1486   folly::EventBase innerEvb;
1487
1488   getFiberManager(outerEvb).addTask([&]() {
1489     EXPECT_EQ(
1490         &getFiberManager(outerEvb), FiberManager::getFiberManagerUnsafe());
1491
1492     runInMainContext([&]() {
1493       getFiberManager(innerEvb).addTask([&]() {
1494         EXPECT_EQ(
1495             &getFiberManager(innerEvb), FiberManager::getFiberManagerUnsafe());
1496
1497         innerEvb.terminateLoopSoon();
1498       });
1499
1500       innerEvb.loopForever();
1501     });
1502
1503     EXPECT_EQ(
1504         &getFiberManager(outerEvb), FiberManager::getFiberManagerUnsafe());
1505
1506     outerEvb.terminateLoopSoon();
1507   });
1508
1509   outerEvb.loopForever();
1510 }
1511
1512 static size_t sNumAwaits;
1513
1514 void runBenchmark(size_t numAwaits, size_t toSend) {
1515   sNumAwaits = numAwaits;
1516
1517   FiberManager fiberManager(folly::make_unique<SimpleLoopController>());
1518   auto& loopController =
1519       dynamic_cast<SimpleLoopController&>(fiberManager.loopController());
1520
1521   std::queue<Promise<int>> pendingRequests;
1522   static const size_t maxOutstanding = 5;
1523
1524   auto loop = [&fiberManager, &loopController, &pendingRequests, &toSend]() {
1525     if (pendingRequests.size() == maxOutstanding || toSend == 0) {
1526       if (pendingRequests.empty()) {
1527         return;
1528       }
1529       pendingRequests.front().setValue(0);
1530       pendingRequests.pop();
1531     } else {
1532       fiberManager.addTask([&pendingRequests]() {
1533         for (size_t i = 0; i < sNumAwaits; ++i) {
1534           auto result = await([&pendingRequests](Promise<int> promise) {
1535             pendingRequests.push(std::move(promise));
1536           });
1537           DCHECK_EQ(result, 0);
1538         }
1539       });
1540
1541       if (--toSend == 0) {
1542         loopController.stop();
1543       }
1544     }
1545   };
1546
1547   loopController.loop(std::move(loop));
1548 }
1549
1550 BENCHMARK(FiberManagerBasicOneAwait, iters) {
1551   runBenchmark(1, iters);
1552 }
1553
1554 BENCHMARK(FiberManagerBasicFiveAwaits, iters) {
1555   runBenchmark(5, iters);
1556 }
1557
1558 BENCHMARK(FiberManagerCreateDestroy, iters) {
1559   for (size_t i = 0; i < iters; ++i) {
1560     folly::EventBase evb;
1561     auto& fm = folly::fibers::getFiberManager(evb);
1562     fm.addTask([]() {});
1563     evb.loop();
1564   }
1565 }
1566
1567 BENCHMARK(FiberManagerAllocateDeallocatePattern, iters) {
1568   static const size_t kNumAllocations = 10000;
1569
1570   FiberManager::Options opts;
1571   opts.maxFibersPoolSize = 0;
1572
1573   FiberManager fiberManager(folly::make_unique<SimpleLoopController>(), opts);
1574
1575   for (size_t iter = 0; iter < iters; ++iter) {
1576     EXPECT_EQ(0, fiberManager.fibersPoolSize());
1577
1578     size_t fibersRun = 0;
1579
1580     for (size_t i = 0; i < kNumAllocations; ++i) {
1581       fiberManager.addTask([&fibersRun] { ++fibersRun; });
1582       fiberManager.loopUntilNoReady();
1583     }
1584
1585     EXPECT_EQ(10000, fibersRun);
1586     EXPECT_EQ(0, fiberManager.fibersPoolSize());
1587   }
1588 }
1589
1590 BENCHMARK(FiberManagerAllocateLargeChunk, iters) {
1591   static const size_t kNumAllocations = 10000;
1592
1593   FiberManager::Options opts;
1594   opts.maxFibersPoolSize = 0;
1595
1596   FiberManager fiberManager(folly::make_unique<SimpleLoopController>(), opts);
1597
1598   for (size_t iter = 0; iter < iters; ++iter) {
1599     EXPECT_EQ(0, fiberManager.fibersPoolSize());
1600
1601     size_t fibersRun = 0;
1602
1603     for (size_t i = 0; i < kNumAllocations; ++i) {
1604       fiberManager.addTask([&fibersRun] { ++fibersRun; });
1605     }
1606
1607     fiberManager.loopUntilNoReady();
1608
1609     EXPECT_EQ(10000, fibersRun);
1610     EXPECT_EQ(0, fiberManager.fibersPoolSize());
1611   }
1612 }