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