/* * Copyright (c) Facebook, Inc. and its affiliates. * * Licensed under the Apache License Version 2.0 with LLVM Exceptions * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://llvm.org/LICENSE.txt * * 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 #include #include #include namespace unifex { namespace _trampoline { class scheduler { std::size_t maxRecursionDepth_; public: scheduler() noexcept : maxRecursionDepth_(16) {} explicit scheduler(std::size_t depth) noexcept : maxRecursionDepth_(depth) {} private: struct operation_base { using execute_fn = void(operation_base*) noexcept; explicit operation_base(execute_fn* execute, std::size_t maxDepth) noexcept : execute_(execute) , maxRecursionDepth_(maxDepth) {} void execute() noexcept { execute_(this); } void start() noexcept { auto* currentState = trampoline_state::current_; if (currentState == nullptr) { trampoline_state state; execute(); state.drain(); } else if (currentState->recursionDepth_ < maxRecursionDepth_) { ++currentState->recursionDepth_; execute(); } else { // Exceeded recursion limit. next_ = std::exchange( currentState->head_, static_cast(this)); } } operation_base* next_ = nullptr; execute_fn* execute_; std::size_t maxRecursionDepth_; }; struct trampoline_state { static thread_local trampoline_state* current_; trampoline_state() noexcept { current_ = this; } ~trampoline_state() { current_ = nullptr; } void drain() noexcept; std::size_t recursionDepth_ = 1; operation_base* head_ = nullptr; }; class schedule_sender; template struct _op { class type final : operation_base { UNIFEX_NO_UNIQUE_ADDRESS Receiver receiver_; friend schedule_sender; template explicit type(Receiver2&& receiver, std::size_t maxDepth) : operation_base(&type::execute_impl, maxDepth) , receiver_((Receiver2 &&) receiver) {} static void execute_impl(operation_base* p) noexcept { auto& self = *static_cast(p); if (is_stop_never_possible_v>) { unifex::set_value(static_cast(self.receiver_)); } else { if (get_stop_token(self.receiver_).stop_requested()) { unifex::set_done(static_cast(self.receiver_)); } else { unifex::set_value(static_cast(self.receiver_)); } } } public: using operation_base::start; }; }; template using operation = typename _op>::type; class schedule_sender { public: explicit schedule_sender(std::size_t maxDepth) noexcept : maxRecursionDepth_(maxDepth) {} template < template class Variant, template class Tuple> using value_types = Variant>; template