2 * Copyright 2015 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/experimental/fibers/EventBaseLoopController.h>
18 #include <folly/experimental/fibers/FiberManager.h>
19 #include <folly/io/async/EventBase.h>
21 namespace folly { namespace fibers {
23 class EventBaseLoopController::ControllerCallback :
24 public folly::EventBase::LoopCallback {
26 explicit ControllerCallback(EventBaseLoopController& controller)
27 : controller_(controller) {}
29 void runLoopCallback() noexcept override {
30 controller_.runLoop();
33 EventBaseLoopController& controller_;
36 inline EventBaseLoopController::EventBaseLoopController()
37 : callback_(folly::make_unique<ControllerCallback>(*this)) {
40 inline EventBaseLoopController::~EventBaseLoopController() {
41 callback_->cancelLoopCallback();
44 inline void EventBaseLoopController::attachEventBase(
45 folly::EventBase& eventBase) {
47 if (eventBase_ != nullptr) {
48 LOG(ERROR) << "Attempt to reattach EventBase to LoopController";
51 eventBase_ = &eventBase;
53 eventBaseAttached_ = true;
55 if (awaitingScheduling_) {
60 inline void EventBaseLoopController::setFiberManager(FiberManager* fm) {
64 inline void EventBaseLoopController::schedule() {
65 if (eventBase_ == nullptr) {
66 // In this case we need to postpone scheduling.
67 awaitingScheduling_ = true;
69 // Schedule it to run in current iteration.
70 eventBase_->runInLoop(callback_.get(), true);
71 awaitingScheduling_ = false;
75 inline void EventBaseLoopController::cancel() {
76 callback_->cancelLoopCallback();
79 inline void EventBaseLoopController::runLoop() {
80 fm_->loopUntilNoReady();
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(); });
93 inline void EventBaseLoopController::timedSchedule(std::function<void()> func,
95 assert(eventBaseAttached_);
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<long long int>(delay_ms, 0L);
102 eventBase_->tryRunAfterDelay(func, delay_ms);