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