2 * Copyright 2017 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 #include <folly/Memory.h>
17 #include <folly/fibers/EventBaseLoopController.h>
22 template <typename EventBaseT>
23 inline EventBaseLoopControllerT<EventBaseT>::EventBaseLoopControllerT()
24 : callback_(*this), aliveWeak_(destructionCallback_.getWeak()) {}
26 template <typename EventBaseT>
27 inline EventBaseLoopControllerT<EventBaseT>::~EventBaseLoopControllerT() {
28 callback_.cancelLoopCallback();
29 eventBaseKeepAlive_.reset();
32 template <typename EventBaseT>
33 inline void EventBaseLoopControllerT<EventBaseT>::attachEventBase(
34 EventBaseT& eventBase) {
35 if (eventBase_ != nullptr) {
36 LOG(ERROR) << "Attempt to reattach EventBase to LoopController";
39 eventBase_ = &eventBase;
40 eventBase_->runOnDestruction(&destructionCallback_);
42 eventBaseAttached_ = true;
44 if (awaitingScheduling_) {
49 template <typename EventBaseT>
50 inline void EventBaseLoopControllerT<EventBaseT>::setFiberManager(
55 template <typename EventBaseT>
56 inline void EventBaseLoopControllerT<EventBaseT>::schedule() {
57 if (eventBase_ == nullptr) {
58 // In this case we need to postpone scheduling.
59 awaitingScheduling_ = true;
61 // Schedule it to run in current iteration.
62 eventBase_->runInLoop(&callback_, true);
63 awaitingScheduling_ = false;
67 template <typename EventBaseT>
68 inline void EventBaseLoopControllerT<EventBaseT>::cancel() {
69 callback_.cancelLoopCallback();
72 template <typename EventBaseT>
73 inline void EventBaseLoopControllerT<EventBaseT>::runLoop() {
74 if (!eventBaseKeepAlive_) {
75 eventBaseKeepAlive_ = eventBase_->loopKeepAlive();
78 loopRunner_->run([&] { fm_->loopUntilNoReadyImpl(); });
80 fm_->loopUntilNoReadyImpl();
82 if (!fm_->hasTasks()) {
83 eventBaseKeepAlive_.reset();
87 template <typename EventBaseT>
88 inline void EventBaseLoopControllerT<EventBaseT>::scheduleThreadSafe(
89 std::function<bool()> func) {
90 /* The only way we could end up here is if
91 1) Fiber thread creates a fiber that awaits (which means we must
92 have already attached, fiber thread wouldn't be running).
93 2) We move the promise to another thread (this move is a memory fence)
94 3) We fulfill the promise from the other thread. */
95 assert(eventBaseAttached_);
97 auto alive = aliveWeak_.lock();
99 if (func() && alive) {
100 auto aliveWeak = aliveWeak_;
101 eventBase_->runInEventBaseThread([this, aliveWeak]() {
102 if (!aliveWeak.expired()) {
109 template <typename EventBaseT>
110 inline void EventBaseLoopControllerT<EventBaseT>::timedSchedule(
111 std::function<void()> func,
113 assert(eventBaseAttached_);
115 // We want upper bound for the cast, thus we just add 1
117 std::chrono::duration_cast<std::chrono::milliseconds>(time - Clock::now())
120 // If clock is not monotonic
121 delay_ms = std::max<decltype(delay_ms)>(delay_ms, 0);
122 eventBase_->tryRunAfterDelay(func, uint32_t(delay_ms));