/* * 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 #include #include #include #include namespace unifex { class thread_unsafe_event_loop; namespace _thread_unsafe_event_loop { using clock_t = std::chrono::steady_clock; using time_point_t = clock_t::time_point; class cancel_callback; class operation_base { friend cancel_callback; protected: using execute_fn = void(operation_base*) noexcept; operation_base(thread_unsafe_event_loop& loop, execute_fn* execute) noexcept : loop_(loop), execute_(execute) {} operation_base(const operation_base&) = delete; operation_base(operation_base&&) = delete; public: void start() noexcept; private: friend thread_unsafe_event_loop; void execute() noexcept { this->execute_(this); } thread_unsafe_event_loop& loop_; operation_base* next_; operation_base** prevPtr_; execute_fn* execute_; protected: time_point_t dueTime_; }; class cancel_callback { public: explicit cancel_callback(operation_base& op) noexcept : op_(&op) {} void operator()() noexcept; private: operation_base* const op_; }; class scheduler; template struct _schedule_after_sender { class type; }; template using schedule_after_sender = typename _schedule_after_sender::type; template struct _after_op { class type; }; template using after_operation = typename _after_op>::type; template class _after_op::type final : public operation_base { friend schedule_after_sender; public: void start() noexcept { this->dueTime_ = clock_t::now() + duration_; callback_.construct( get_stop_token(receiver_), cancel_callback{*this}); operation_base::start(); } private: template explicit type( Receiver2&& r, Duration d, thread_unsafe_event_loop& loop) : operation_base(loop, &type::execute_impl) , receiver_((Receiver2 &&) r) , duration_(d) {} static void execute_impl(operation_base* p) noexcept { auto& self = *static_cast(p); self.callback_.destruct(); if constexpr (is_stop_never_possible_v< stop_token_type_t>) { unifex::set_value(std::move(self.receiver_)); } else { if (get_stop_token(self.receiver_).stop_requested()) { unifex::set_done(std::move(self.receiver_)); } else { unifex::set_value(std::move(self.receiver_)); } } } UNIFEX_NO_UNIQUE_ADDRESS Receiver receiver_; UNIFEX_NO_UNIQUE_ADDRESS Duration duration_; UNIFEX_NO_UNIQUE_ADDRESS manual_lifetime::template callback_type> callback_; }; template class _schedule_after_sender::type { using schedule_after_sender = type; public: template < template class Variant, template class Tuple> using value_types = Variant>; template