diff --git a/builtin-functions/kphp-light/functions.txt b/builtin-functions/kphp-light/functions.txt index 40fa259d2e..0ab5a3dfee 100644 --- a/builtin-functions/kphp-light/functions.txt +++ b/builtin-functions/kphp-light/functions.txt @@ -85,7 +85,7 @@ function wait(future | false $id, float $timeout = -1.0) ::: ^1[*] | null; function sched_yield() ::: void; /** @kphp-extern-func-info interruptible */ -function sched_yield_sleep($timeout_ns ::: int) ::: void; +function sched_yield_sleep($duration ::: float) ::: void; // === Rpc ======================================================================================== diff --git a/compiler/code-gen/declarations.cpp b/compiler/code-gen/declarations.cpp index 79c441ee2a..c3b0359b83 100644 --- a/compiler/code-gen/declarations.cpp +++ b/compiler/code-gen/declarations.cpp @@ -72,9 +72,7 @@ void FunctionDeclaration::compile(CodeGenerator &W) const { switch (style) { case gen_out_style::tagger: case gen_out_style::cpp: { - if (function->is_k2_fork) { - FunctionSignatureGenerator(W) << "task_t " << FunctionName(function) << "(" << params_gen << ")"; - } else if (function->is_interruptible) { + if (function->is_interruptible) { FunctionSignatureGenerator(W) << "task_t<" << ret_type_gen << ">" << " " << FunctionName(function) << "(" << params_gen << ")"; } else { FunctionSignatureGenerator(W) << ret_type_gen << " " << FunctionName(function) << "(" << params_gen << ")"; diff --git a/compiler/code-gen/vertex-compiler.cpp b/compiler/code-gen/vertex-compiler.cpp index b13f5b062f..177251ae87 100644 --- a/compiler/code-gen/vertex-compiler.cpp +++ b/compiler/code-gen/vertex-compiler.cpp @@ -849,7 +849,7 @@ void compile_func_call(VertexAdaptor root, CodeGenerator &W, func_ if (mode == func_call_mode::fork_call) { if (func->is_interruptible) { - W << "(co_await start_fork_t{" << FunctionName(func); + W << "(co_await start_fork_t{static_cast>(" << FunctionName(func); } else { W << FunctionForkName(func); } @@ -883,9 +883,7 @@ void compile_func_call(VertexAdaptor root, CodeGenerator &W, func_ W << ")"; if (func->is_interruptible) { if (mode == func_call_mode::fork_call) { - W << ", start_fork_t::execution::fork})"; - } else if (func->is_k2_fork) { // k2 fork's return type is 'task_t' so we need to unpack actual result from fork_result - W << ").get_result<" << TypeName(tinf::get_type(root)) << ">()"; + W << "), start_fork_t::execution::fork})"; } else { W << ")"; } diff --git a/runtime-core/utils/small-object-storage.h b/runtime-core/utils/small-object-storage.h index 2ea08dbfe7..efa7f9ecf6 100644 --- a/runtime-core/utils/small-object-storage.h +++ b/runtime-core/utils/small-object-storage.h @@ -9,7 +9,7 @@ #include #include -#include "runtime-core/runtime-core.h" +#include "runtime-core/allocator/runtime-allocator.h" template union small_object_storage { diff --git a/runtime-light/allocator/runtime-light-allocator.cpp b/runtime-light/allocator/runtime-light-allocator.cpp index 50ac7625c0..6895e1a1e2 100644 --- a/runtime-light/allocator/runtime-light-allocator.cpp +++ b/runtime-light/allocator/runtime-light-allocator.cpp @@ -5,9 +5,8 @@ #include #include -#include "runtime-core/runtime-core.h" +#include "runtime-core/utils/kphp-assert-core.h" #include "runtime-light/component/component.h" -#include "runtime-light/utils/panic.h" namespace { // TODO: make it depend on max chunk size, e.g. MIN_EXTRA_MEM_SIZE = f(MAX_CHUNK_SIZE); @@ -136,4 +135,4 @@ void *RuntimeAllocator::realloc_global_memory(void *mem, size_t new_size, size_t void RuntimeAllocator::free_global_memory(void *mem, size_t) noexcept { get_platform_context()->allocator.free(mem); -} \ No newline at end of file +} diff --git a/runtime-light/coroutine/awaitable.h b/runtime-light/coroutine/awaitable.h index c27ab80eb3..f55d2f1228 100644 --- a/runtime-light/coroutine/awaitable.h +++ b/runtime-light/coroutine/awaitable.h @@ -19,7 +19,6 @@ #include "runtime-light/header.h" #include "runtime-light/scheduler/scheduler.h" #include "runtime-light/stdlib/fork/fork-context.h" -#include "runtime-light/stdlib/fork/fork.h" #include "runtime-light/utils/context.h" template @@ -277,7 +276,7 @@ class start_fork_t { SuspendToken suspend_token{std::noop_coroutine(), WaitEvent::Rechedule{}}; public: - explicit start_fork_t(task_t &&task_, execution exec_policy_) noexcept + explicit start_fork_t(task_t task_, execution exec_policy_) noexcept : exec_policy(exec_policy_) , fork_coro(task_.get_handle()) , fork_id(ForkComponentContext::get().push_fork(std::move(task_))) {} @@ -328,13 +327,16 @@ class start_fork_t { template class wait_fork_t { int64_t fork_id; - task_t fork_task; - task_t::awaiter_t fork_awaiter; + task_t fork_task; + task_t::awaiter_t fork_awaiter; + + using fork_resume_t = decltype(fork_awaiter.await_resume()); + using await_resume_t = fork_resume_t; public: explicit wait_fork_t(int64_t fork_id_) noexcept : fork_id(fork_id_) - , fork_task(ForkComponentContext::get().pop_fork(fork_id)) + , fork_task(static_cast>(ForkComponentContext::get().pop_fork(fork_id))) , fork_awaiter(std::addressof(fork_task)) {} wait_fork_t(wait_fork_t &&other) noexcept @@ -355,8 +357,12 @@ class wait_fork_t { fork_awaiter.await_suspend(coro); } - T await_resume() noexcept { - return fork_awaiter.await_resume().get_result(); + await_resume_t await_resume() noexcept { + if constexpr (std::is_void_v) { + fork_awaiter.await_resume(); + } else { + return fork_awaiter.await_resume(); + } } constexpr bool resumable() const noexcept { diff --git a/runtime-light/coroutine/task.h b/runtime-light/coroutine/task.h index ae368e9b63..db8dff5c08 100644 --- a/runtime-light/coroutine/task.h +++ b/runtime-light/coroutine/task.h @@ -5,6 +5,7 @@ #pragma once #include +#include #include #include #include @@ -62,7 +63,6 @@ struct task_t : public task_base_t { struct promise_void_t; using promise_type = std::conditional_t{}, promise_non_void_t, promise_void_t>; - using task_base_t::task_base_t; struct promise_base_t { @@ -225,4 +225,16 @@ struct task_t : public task_base_t { std::coroutine_handle get_handle() { return std::coroutine_handle::from_address(handle_address); } + + // conversion functions + // + // erase type + explicit operator task_t() && noexcept { + return task_t{std::coroutine_handle<>::from_address(std::exchange(handle_address, nullptr))}; + } + // restore erased type + template + requires(std::same_as) explicit operator task_t() && noexcept { + return task_t{std::coroutine_handle<>::from_address(std::exchange(handle_address, nullptr))}; + } }; diff --git a/runtime-light/stdlib/fork/fork-api.cpp b/runtime-light/stdlib/fork/fork-api.cpp index b8e68746ce..fca25d4357 100644 --- a/runtime-light/stdlib/fork/fork-api.cpp +++ b/runtime-light/stdlib/fork/fork-api.cpp @@ -5,7 +5,6 @@ #include "runtime-light/stdlib/fork/fork-api.h" #include -#include #include "runtime-core/utils/kphp-assert-core.h" #include "runtime-light/coroutine/awaitable.h" @@ -15,10 +14,10 @@ task_t f$sched_yield() noexcept { co_await wait_for_reschedule_t{}; } -task_t f$sched_yield_sleep(int64_t duration_ns) noexcept { - if (duration_ns < 0) { - php_warning("can't sleep for negative duration %" PRId64, duration_ns); +task_t f$sched_yield_sleep(double duration) noexcept { + if (duration <= 0) { + php_warning("can't sleep for negative or zero duration %.9f", duration); co_return; } - co_await wait_for_timer_t{std::chrono::nanoseconds{static_cast(duration_ns)}}; + co_await wait_for_timer_t{std::chrono::duration_cast(std::chrono::duration{duration})}; } diff --git a/runtime-light/stdlib/fork/fork-api.h b/runtime-light/stdlib/fork/fork-api.h index 99b3fa2167..55e05d0fe4 100644 --- a/runtime-light/stdlib/fork/fork-api.h +++ b/runtime-light/stdlib/fork/fork-api.h @@ -5,9 +5,11 @@ #pragma once #include +#include #include #include "runtime-core/core-types/decl/optional.h" +#include "runtime-core/runtime-core.h" #include "runtime-core/utils/kphp-assert-core.h" #include "runtime-light/coroutine/awaitable.h" #include "runtime-light/coroutine/task.h" @@ -23,7 +25,7 @@ constexpr auto DEFAULT_TIMEOUT_NS = std::chrono::duration_cast -requires(is_optional::value) task_t f$wait(int64_t fork_id, double timeout = -1.0) noexcept { +requires(is_optional::value || std::same_as) task_t f$wait(int64_t fork_id, double timeout = -1.0) noexcept { auto &fork_ctx{ForkComponentContext::get()}; if (!fork_ctx.contains(fork_id)) { php_warning("can't find fork %" PRId64, fork_id); @@ -38,10 +40,10 @@ requires(is_optional::value) task_t f$wait(int64_t fork_id, double timeout } template -requires(is_optional::value) task_t f$wait(Optional fork_id_opt, double timeout = -1.0) noexcept { +requires(is_optional::value || std::same_as) task_t f$wait(Optional fork_id_opt, double timeout = -1.0) noexcept { co_return co_await f$wait(fork_id_opt.has_value() ? fork_id_opt.val() : INVALID_FORK_ID, timeout); } task_t f$sched_yield() noexcept; -task_t f$sched_yield_sleep(int64_t duration_ns) noexcept; +task_t f$sched_yield_sleep(double duration) noexcept; diff --git a/runtime-light/stdlib/fork/fork-context.h b/runtime-light/stdlib/fork/fork-context.h index 57c67ec1af..0788204439 100644 --- a/runtime-light/stdlib/fork/fork-context.h +++ b/runtime-light/stdlib/fork/fork-context.h @@ -10,7 +10,6 @@ #include "runtime-core/memory-resource/unsynchronized_pool_resource.h" #include "runtime-core/utils/kphp-assert-core.h" #include "runtime-light/coroutine/task.h" -#include "runtime-light/stdlib/fork/fork.h" #include "runtime-light/utils/concepts.h" constexpr int64_t INVALID_FORK_ID = -1; @@ -20,15 +19,15 @@ class ForkComponentContext { using unordered_map = memory_resource::stl::unordered_map; static constexpr auto FORK_ID_INIT = 0; - - unordered_map> forks; + // type erased tasks that represent forks + unordered_map> forks; int64_t next_fork_id{FORK_ID_INIT + 1}; - int64_t push_fork(task_t &&task) noexcept { + int64_t push_fork(task_t task) noexcept { return forks.emplace(next_fork_id, std::move(task)), next_fork_id++; } - task_t pop_fork(int64_t fork_id) noexcept { + task_t pop_fork(int64_t fork_id) noexcept { const auto it_fork{forks.find(fork_id)}; if (it_fork == forks.end()) { php_critical_error("can't find fork %" PRId64, fork_id); @@ -44,7 +43,7 @@ class ForkComponentContext { public: explicit ForkComponentContext(memory_resource::unsynchronized_pool_resource &memory_resource) noexcept - : forks(unordered_map>::allocator_type{memory_resource}) {} + : forks(unordered_map>::allocator_type{memory_resource}) {} static ForkComponentContext &get() noexcept; diff --git a/runtime-light/stdlib/fork/fork.h b/runtime-light/stdlib/fork/fork.h deleted file mode 100644 index 0837de8d38..0000000000 --- a/runtime-light/stdlib/fork/fork.h +++ /dev/null @@ -1,27 +0,0 @@ -// Compiler for PHP (aka KPHP) -// Copyright (c) 2024 LLC «V Kontakte» -// Distributed under the GPL v3 License, see LICENSE.notice.txt - -#pragma once - -#include -#include -#include - -#include "runtime-core/runtime-core.h" -#include "runtime-core/utils/small-object-storage.h" - -class fork_result { - small_object_storage storage{}; - -public: - template - requires(!std::same_as) explicit fork_result(T &&t) noexcept { - storage.emplace>(std::forward(t)); - } - - template - T get_result() noexcept { - return *storage.get(); - } -}; diff --git a/runtime-light/stdlib/misc.cpp b/runtime-light/stdlib/misc.cpp index daca639574..a0f342f522 100644 --- a/runtime-light/stdlib/misc.cpp +++ b/runtime-light/stdlib/misc.cpp @@ -6,13 +6,13 @@ #include +#include "runtime-core/utils/kphp-assert-core.h" #include "runtime-light/component/component.h" #include "runtime-light/coroutine/awaitable.h" #include "runtime-light/header.h" #include "runtime-light/stdlib/superglobals.h" #include "runtime-light/streams/streams.h" #include "runtime-light/utils/context.h" -#include "runtime-light/utils/panic.h" namespace { @@ -60,7 +60,7 @@ task_t finish(int64_t exit_code, bool from_exit) { // TODO: use exit code const auto ob_total_buffer = ob_merge_buffers(); Response &response = component_ctx.response; auto &buffer = response.output_buffers[ob_total_buffer]; - if (co_await write_all_to_stream(standard_stream, buffer.c_str(), buffer.size())) { + if ((co_await write_all_to_stream(standard_stream, buffer.c_str(), buffer.size())) != buffer.size()) { php_warning("can't write component result to stream %" PRIu64, standard_stream); } component_ctx.release_all_streams(); diff --git a/runtime-light/stdlib/rpc/rpc-api.cpp b/runtime-light/stdlib/rpc/rpc-api.cpp index 3fd36bbeae..ea727da862 100644 --- a/runtime-light/stdlib/rpc/rpc-api.cpp +++ b/runtime-light/stdlib/rpc/rpc-api.cpp @@ -132,7 +132,7 @@ task_t rpc_send_impl(string actor, double timeout, bool ignore_ans : DEFAULT_TIMEOUT_NS}; // create fork to wait for RPC response. we need to do it even if 'ignore_answer' is 'true' to make sure // that the stream will not be closed too early. otherwise, platform may even not send RPC request - auto waiter_task{[](int64_t query_id, auto comp_query, std::chrono::nanoseconds timeout, bool collect_responses_extra_info) noexcept -> task_t { + auto waiter_task{[](int64_t query_id, auto comp_query, std::chrono::nanoseconds timeout, bool collect_responses_extra_info) noexcept -> task_t { auto fetch_task{f$component_client_get_result(std::move(comp_query))}; const auto response{(co_await wait_with_timeout_t{task_t::awaiter_t{std::addressof(fetch_task)}, timeout}).value_or(string{})}; // update response extra info if needed @@ -149,7 +149,7 @@ task_t rpc_send_impl(string actor, double timeout, bool ignore_ans co_return response; }(query_id, std::move(comp_query), timeout_ns, collect_responses_extra_info)}; // start waiter fork - const auto waiter_fork_id{co_await start_fork_t{std::move(waiter_task), start_fork_t::execution::self}}; + const auto waiter_fork_id{co_await start_fork_t{static_cast>(std::move(waiter_task)), start_fork_t::execution::self}}; if (ignore_answer) { co_return RpcQueryInfo{.id = RPC_IGNORED_ANSWER_QUERY_ID, .request_size = request_size, .timestamp = timestamp}; diff --git a/runtime-light/stdlib/string-functions.cpp b/runtime-light/stdlib/string-functions.cpp index 3a839a66d1..5039cef93e 100644 --- a/runtime-light/stdlib/string-functions.cpp +++ b/runtime-light/stdlib/string-functions.cpp @@ -35,14 +35,14 @@ void f$debug_print_string(const string &s) { Optional f$byte_to_int(const string &s) { if (s.size() != 1) { php_warning("Cannot convert non-byte string to int"); - return Optional(); + return {}; } return *s.c_str(); } Optional f$int_to_byte(int64_t v) { if (v > 127 || v < -128) { - php_warning("Cannot convert too big int to byte %ld", v); + php_warning("Cannot convert too big int to byte %" PRId64, v); return false; } char c = v; diff --git a/runtime-light/stdlib/string-functions.h b/runtime-light/stdlib/string-functions.h index c2ba29b38f..a2264a2fc4 100644 --- a/runtime-light/stdlib/string-functions.h +++ b/runtime-light/stdlib/string-functions.h @@ -1,7 +1,6 @@ #pragma once #include "runtime-core/runtime-core.h" -#include void print(const char *s, size_t s_len); diff --git a/runtime-light/stdlib/timer/timer.h b/runtime-light/stdlib/timer/timer.h index b771d05fcf..e3c96883c7 100644 --- a/runtime-light/stdlib/timer/timer.h +++ b/runtime-light/stdlib/timer/timer.h @@ -19,10 +19,9 @@ task_t f$set_timer(int64_t timeout_ms, T &&on_timer_callback) noexcept { php_warning("can't set timer for negative duration %" PRId64 "ms", timeout_ms); co_return; } - const auto fork_f{[](std::chrono::nanoseconds duration, T &&on_timer_callback) -> task_t { + const auto fork_f{[](std::chrono::nanoseconds duration, T &&on_timer_callback) -> task_t { co_await wait_for_timer_t{duration}; on_timer_callback(); - co_return 0; }}; // TODO: someone should pop that fork from ForkComponentContext since it will stay there unless we perform f$wait on fork const auto duration_ms{std::chrono::milliseconds{static_cast(timeout_ms)}}; co_await start_fork_t{fork_f(std::chrono::duration_cast(duration_ms), std::forward(on_timer_callback)), diff --git a/runtime-light/utils/panic.h b/runtime-light/utils/panic.cpp similarity index 85% rename from runtime-light/utils/panic.h rename to runtime-light/utils/panic.cpp index 88fc2e6b1b..059db31fd8 100644 --- a/runtime-light/utils/panic.h +++ b/runtime-light/utils/panic.cpp @@ -2,16 +2,15 @@ // Copyright (c) 2024 LLC «V Kontakte» // Distributed under the GPL v3 License, see LICENSE.notice.txt -#pragma once - #include -#include "context.h" +#include "runtime-core/utils/kphp-assert-core.h" #include "runtime-light/component/component.h" #include "runtime-light/header.h" +#include "runtime-light/utils/context.h" #include "runtime-light/utils/logs.h" -inline void critical_error_handler() { +void critical_error_handler() { constexpr const char *message = "script panic"; const auto &platform_ctx = *get_platform_context(); auto &component_ctx = *get_component_context(); diff --git a/runtime-light/utils/php_assert.cpp b/runtime-light/utils/php_assert.cpp index 0d869406bd..190caca8d3 100644 --- a/runtime-light/utils/php_assert.cpp +++ b/runtime-light/utils/php_assert.cpp @@ -2,9 +2,6 @@ // Copyright (c) 2020 LLC «V Kontakte» // Distributed under the GPL v3 License, see LICENSE.notice.txt -#include "runtime-light/utils/php_assert.h" - -#include #include #include #include @@ -16,7 +13,10 @@ #include #include -#include "runtime-light/utils/panic.h" +#include "runtime-core/utils/kphp-assert-core.h" +#include "runtime-light/header.h" +#include "runtime-light/utils/context.h" +#include "runtime-light/utils/logs.h" static void php_warning_impl(bool out_of_memory, int error_type, char const *message, va_list args) { (void)out_of_memory; diff --git a/runtime-light/utils/php_assert.h b/runtime-light/utils/php_assert.h deleted file mode 100644 index 41d30d4f7b..0000000000 --- a/runtime-light/utils/php_assert.h +++ /dev/null @@ -1,13 +0,0 @@ -// Compiler for PHP (aka KPHP) -// Copyright (c) 2020 LLC «V Kontakte» -// Distributed under the GPL v3 License, see LICENSE.notice.txt - -#pragma once - -#include -#include - -#include "common/wrappers/likely.h" -#include "common/mixin/not_copyable.h" - -#include "runtime-core/utils/kphp-assert-core.h" diff --git a/runtime-light/utils/utils.cmake b/runtime-light/utils/utils.cmake index fee0426cd6..f74079da0d 100644 --- a/runtime-light/utils/utils.cmake +++ b/runtime-light/utils/utils.cmake @@ -1 +1 @@ -prepend(RUNTIME_UTILS_SRC utils/ php_assert.cpp json-functions.cpp context.cpp) +prepend(RUNTIME_UTILS_SRC utils/ panic.cpp php_assert.cpp json-functions.cpp context.cpp) diff --git a/tests/kphp_tester.py b/tests/kphp_tester.py index 82016c0e9d..abb6253249 100755 --- a/tests/kphp_tester.py +++ b/tests/kphp_tester.py @@ -60,7 +60,7 @@ def make_kphp_once_runner(self, use_nocc, cxx_name, k2_bin): vkext_dir=os.path.abspath(os.path.join(tester_dir, os.path.pardir, "objs", "vkext")), use_nocc=use_nocc, cxx_name=cxx_name, - k2_bin=k2_bin + k2_bin=os.path.abspath(k2_bin) ) def set_up_env_for_k2(self, cxx_name="clang++"): @@ -68,7 +68,6 @@ def set_up_env_for_k2(self, cxx_name="clang++"): self.env_vars["KPHP_USER_BINARY_PATH"] = "component.so" self.env_vars["KPHP_ENABLE_GLOBAL_VARS_MEMORY_STATS"] = "0" self.env_vars["KPHP_PROFILER"] = "0" - self.env_vars["KPHP_CXX"] = cxx_name self.env_vars["KPHP_K2_COMPONENT_IS_ONESHOT"] = "1" self.env_vars["KPHP_FORCE_LINK_RUNTIME"] = "1" diff --git a/tests/phpt/dl/474_flex.php b/tests/phpt/dl/474_flex.php index e1e26791df..ce61cef0e9 100644 --- a/tests/phpt/dl/474_flex.php +++ b/tests/phpt/dl/474_flex.php @@ -1,4 +1,4 @@ -@ok benchmark +@ok k2_skip benchmark 1 2 3 -waited 1123456789 -waited 1123456790 -waited 1123456791 +waited 0.03 +waited 0.01 +waited 0.02