adding Promise::await
[folly.git] / folly / experimental / fibers / SimpleLoopController.h
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 #pragma once
17
18 #include <folly/Likely.h>
19
20 #include <folly/experimental/fibers/LoopController.h>
21
22 namespace folly {
23 namespace fibers {
24
25 class FiberManager;
26
27 class SimpleLoopController : public LoopController {
28  public:
29   SimpleLoopController() : fm_(nullptr), stopRequested_(false) {}
30
31   /**
32    * Run FiberManager loop; if no ready task are present,
33    * run provided function. Stops after both stop() has been called
34    * and no waiting tasks remain.
35    */
36   template <typename F>
37   void loop(F&& func) {
38     bool waiting = false;
39     stopRequested_ = false;
40
41     while (LIKELY(waiting || !stopRequested_)) {
42       func();
43
44       auto time = Clock::now();
45
46       for (size_t i = 0; i < scheduledFuncs_.size(); ++i) {
47         if (scheduledFuncs_[i].first <= time) {
48           scheduledFuncs_[i].second();
49           swap(scheduledFuncs_[i], scheduledFuncs_.back());
50           scheduledFuncs_.pop_back();
51           --i;
52         }
53       }
54
55       if (scheduled_) {
56         scheduled_ = false;
57         waiting = fm_->loopUntilNoReady();
58       }
59     }
60   }
61
62   /**
63    * Requests exit from loop() as soon as all waiting tasks complete.
64    */
65   void stop() {
66     stopRequested_ = true;
67   }
68
69   int remoteScheduleCalled() const {
70     return remoteScheduleCalled_;
71   }
72
73   void schedule() override {
74     scheduled_ = true;
75   }
76
77   void timedSchedule(std::function<void()> func, TimePoint time) override {
78     scheduledFuncs_.emplace_back(time, std::move(func));
79   }
80
81  private:
82   FiberManager* fm_;
83   std::atomic<bool> scheduled_{false};
84   bool stopRequested_;
85   std::atomic<int> remoteScheduleCalled_{0};
86   std::vector<std::pair<TimePoint, std::function<void()>>> scheduledFuncs_;
87
88   /* LoopController interface */
89
90   void setFiberManager(FiberManager* fm) override {
91     fm_ = fm;
92   }
93
94   void cancel() override {
95     scheduled_ = false;
96   }
97
98   void scheduleThreadSafe(std::function<bool()> func) override {
99     if (func()) {
100       ++remoteScheduleCalled_;
101       scheduled_ = true;
102     }
103   }
104
105   friend class FiberManager;
106 };
107 }
108 } // folly::fibers