/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include #include namespace folly { namespace fibers { class FiberManager; class SimpleLoopController : public LoopController { public: SimpleLoopController(); ~SimpleLoopController(); /** * Run FiberManager loop; if no ready task are present, * run provided function. Stops after both stop() has been called * and no waiting tasks remain. */ template void loop(F&& func) { loopThread_.store(std::this_thread::get_id(), std::memory_order_release); bool waiting = false; stopRequested_ = false; while (LIKELY(waiting || !stopRequested_)) { func(); runTimeouts(); if (scheduled_) { scheduled_ = false; runLoop(); waiting = fm_->hasTasks(); } } loopThread_.store({}, std::memory_order_release); } /** * Requests exit from loop() as soon as all waiting tasks complete. */ void stop() { stopRequested_ = true; } int remoteScheduleCalled() const { return remoteScheduleCalled_; } void runLoop() override { do { if (remoteLoopRun_ < remoteScheduleCalled_) { for (; remoteLoopRun_ < remoteScheduleCalled_; ++remoteLoopRun_) { if (fm_->shouldRunLoopRemote()) { fm_->loopUntilNoReadyImpl(); } } } else { fm_->loopUntilNoReadyImpl(); } } while (remoteLoopRun_ < remoteScheduleCalled_); } void runEagerFiber(Fiber* fiber) override { fm_->runEagerFiberImpl(fiber); } void schedule() override { scheduled_ = true; } HHWheelTimer* timer() override { return timer_.get(); } bool isInLoopThread() const { auto tid = loopThread_.load(std::memory_order_relaxed); return tid == std::thread::id() || tid == std::this_thread::get_id(); } private: FiberManager* fm_; std::atomic scheduled_{false}; bool stopRequested_; std::atomic remoteScheduleCalled_{0}; int remoteLoopRun_{0}; std::atomic loopThread_; class SimpleTimeoutManager; std::unique_ptr timeoutManager_; std::shared_ptr timer_; /* LoopController interface */ void setFiberManager(FiberManager* fm) override { fm_ = fm; } void scheduleThreadSafe() override { ++remoteScheduleCalled_; scheduled_ = true; } void runTimeouts(); friend class FiberManager; }; } // namespace fibers } // namespace folly