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