Tweak explicit std::max instantiation
[folly.git] / folly / experimental / fibers / EventBaseLoopController-inl.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 #include <folly/Memory.h>
17 #include <folly/experimental/fibers/EventBaseLoopController.h>
18 #include <folly/experimental/fibers/FiberManager.h>
19 #include <folly/io/async/EventBase.h>
20
21 namespace folly { namespace fibers {
22
23 class EventBaseLoopController::ControllerCallback :
24       public folly::EventBase::LoopCallback {
25  public:
26   explicit ControllerCallback(EventBaseLoopController& controller)
27      : controller_(controller) {}
28
29   void runLoopCallback() noexcept override {
30     controller_.runLoop();
31   }
32  private:
33   EventBaseLoopController& controller_;
34 };
35
36 inline EventBaseLoopController::EventBaseLoopController()
37   : callback_(folly::make_unique<ControllerCallback>(*this)) {
38 }
39
40 inline EventBaseLoopController::~EventBaseLoopController() {
41   callback_->cancelLoopCallback();
42 }
43
44 inline void EventBaseLoopController::attachEventBase(
45   folly::EventBase& eventBase) {
46
47   if (eventBase_ != nullptr) {
48     LOG(ERROR) << "Attempt to reattach EventBase to LoopController";
49   }
50
51   eventBase_ = &eventBase;
52
53   eventBaseAttached_ = true;
54
55   if (awaitingScheduling_) {
56     schedule();
57   }
58 }
59
60 inline void EventBaseLoopController::setFiberManager(FiberManager* fm) {
61   fm_ = fm;
62 }
63
64 inline void EventBaseLoopController::schedule() {
65   if (eventBase_ == nullptr) {
66     // In this case we need to postpone scheduling.
67     awaitingScheduling_ = true;
68   } else {
69     // Schedule it to run in current iteration.
70     eventBase_->runInLoop(callback_.get(), true);
71     awaitingScheduling_ = false;
72   }
73 }
74
75 inline void EventBaseLoopController::cancel() {
76   callback_->cancelLoopCallback();
77 }
78
79 inline void EventBaseLoopController::runLoop() {
80   fm_->loopUntilNoReady();
81 }
82
83 inline void EventBaseLoopController::scheduleThreadSafe() {
84   /* The only way we could end up here is if
85      1) Fiber thread creates a fiber that awaits (which means we must
86         have already attached, fiber thread wouldn't be running).
87      2) We move the promise to another thread (this move is a memory fence)
88      3) We fulfill the promise from the other thread. */
89   assert(eventBaseAttached_);
90   eventBase_->runInEventBaseThread([this] () { runLoop(); });
91 }
92
93 inline void EventBaseLoopController::timedSchedule(std::function<void()> func,
94                                                    TimePoint time) {
95   assert(eventBaseAttached_);
96
97   // We want upper bound for the cast, thus we just add 1
98   auto delay_ms = std::chrono::duration_cast<
99     std::chrono::milliseconds>(time - Clock::now()).count() + 1;
100   // If clock is not monotonic
101   delay_ms = std::max<decltype(delay_ms)>(delay_ms, 0L);
102   eventBase_->tryRunAfterDelay(func, delay_ms);
103 }
104
105 }}  // folly::fibers