diff --git a/compiler/code-gen/files/init-scripts.cpp b/compiler/code-gen/files/init-scripts.cpp index 3ec4d17c72..67c3b7d103 100644 --- a/compiler/code-gen/files/init-scripts.cpp +++ b/compiler/code-gen/files/init-scripts.cpp @@ -40,12 +40,12 @@ void StaticInit::compile(CodeGenerator &W) const { W << "extern array gen$tl_storers_ht;" << NL; FunctionSignatureGenerator(W) << "void fill_tl_storers_ht()" << SemicolonAndNL() << NL; } - if (!G->is_output_mode_k2_component()) { + if (!G->is_output_mode_k2()) { FunctionSignatureGenerator(W) << ("const char *get_php_scripts_version()") << BEGIN << "return " << RawString(G->settings().php_code_version.get()) << ";" << NL << END << NL << NL; } - if (!G->is_output_mode_k2_component()) { + if (!G->is_output_mode_k2()) { FunctionSignatureGenerator(W) << ("char **get_runtime_options([[maybe_unused]] int *count)") << BEGIN; const auto &runtime_opts = G->get_kphp_runtime_opts(); @@ -113,19 +113,16 @@ struct RunInterruptedFunction { void compile(CodeGenerator &W) const { std::string await_prefix = function->is_interruptible ? "co_await " : ""; - /** - * Oneshot components work the same way as php scripts: - * 1) Start when the request came in - * 2) Collecting output buffer after script finished - **/ - std::string script_start = G->settings().k2_component_is_oneshot.get() ? "co_await accept_initial_stream();" : ""; - std::string script_finish = G->settings().k2_component_is_oneshot.get() ? "co_await shutdown_script();" : ""; - FunctionSignatureGenerator(W) << "task_t " << FunctionName(function) << "$run() " << BEGIN - << script_start << NL - << await_prefix << FunctionName(function) << "();" << NL - << script_finish << NL - << "co_return;" - << END; + std::string component_kind = G->is_output_mode_k2_cli() ? "ComponentKind::CLI" + : G->is_output_mode_k2_server() ? "ComponentKind::Server" + : G->is_output_mode_k2_oneshot() ? "ComponentKind::Oneshot" + : G->is_output_mode_k2_multishot() ? "ComponentKind::Multishot" + : "ComponentKind::Invalid"; + + std::string script_start = "co_await get_component_context()->run_component_prologue<" + component_kind + ">();"; + std::string script_finish = "co_await get_component_context()->run_component_epilogue();"; + FunctionSignatureGenerator(W) << "task_t " << FunctionName(function) << "$run() " << BEGIN << script_start << NL << await_prefix + << FunctionName(function) << "();" << NL << script_finish << NL << "co_return;" << END; W << NL; } }; @@ -207,7 +204,7 @@ void InitScriptsCpp::compile(CodeGenerator &W) const { W << OpenFile("init_php_scripts.cpp", "", false); W << ExternInclude(G->settings().runtime_headers.get()); - if (!G->is_output_mode_k2_component()) { + if (!G->is_output_mode_k2()) { W << ExternInclude("server/php-init-scripts.h"); } @@ -227,14 +224,14 @@ void InitScriptsCpp::compile(CodeGenerator &W) const { return; } - if (G->is_output_mode_k2_component()) { + if (G->is_output_mode_k2()) { W << RunInterruptedFunction(main_file_id->main_function) << NL; } else { W << RunFunction(main_file_id->main_function) << NL; } W << GlobalsResetFunction(main_file_id->main_function) << NL; - if (G->is_output_mode_k2_component()) { + if (G->is_output_mode_k2()) { FunctionSignatureGenerator(W) << "void init_php_scripts_in_each_worker(" << PhpMutableGlobalsRefArgument() << ", task_t &run" ")" << BEGIN; } else { FunctionSignatureGenerator(W) << "void init_php_scripts_in_each_worker(" << PhpMutableGlobalsRefArgument() << ")" << BEGIN; @@ -249,7 +246,7 @@ void InitScriptsCpp::compile(CodeGenerator &W) const { W << FunctionName(main_file_id->main_function) << "$globals_reset(php_globals);" << NL; - if (G->is_output_mode_k2_component()) { + if (G->is_output_mode_k2()) { W << "run = " << FunctionName(main_file_id->main_function) << "$run();" << NL; } else { W << "set_script (" @@ -283,20 +280,16 @@ void CppMainFile::compile(CodeGenerator &W) const { } void ComponentInfoFile::compile(CodeGenerator &W) const { - kphp_assert(G->is_output_mode_k2_component()); + kphp_assert(G->is_output_mode_k2()); G->settings().get_version(); auto now = std::chrono::system_clock::now(); W << OpenFile("image_info.cpp"); W << ExternInclude(G->settings().runtime_headers.get()); - W << "const ImageInfo *vk_k2_describe() " << BEGIN - << "static ImageInfo imageInfo {\"" << G->settings().k2_component_name.get() << "\"" << "," - << std::chrono::duration_cast(now.time_since_epoch()).count() << "," - << "K2_PLATFORM_HEADER_H_VERSION, " - << "{}," //todo:k2 add commit hash - << "{}," //todo:k2 add compiler hash? - << (G->settings().k2_component_is_oneshot.get() ? "1" : "0") - << "};" << NL - << "return &imageInfo;" << NL - << END; + W << "const ImageInfo *vk_k2_describe() " << BEGIN << "static ImageInfo imageInfo {\"" << G->settings().k2_component_name.get() << "\"" << "," + << std::chrono::duration_cast(now.time_since_epoch()).count() << "," + << "K2_PLATFORM_HEADER_H_VERSION, " + << "{}," // todo:k2 add commit hash + << "{}," // todo:k2 add compiler hash? + << (G->is_output_mode_k2_multishot() ? "0" : "1") << "};" << NL << "return &imageInfo;" << NL << END; W << CloseFile(); } diff --git a/compiler/code-gen/files/tl2cpp/tl-combinator.cpp b/compiler/code-gen/files/tl2cpp/tl-combinator.cpp index e003a91dbb..53bc3861cc 100644 --- a/compiler/code-gen/files/tl2cpp/tl-combinator.cpp +++ b/compiler/code-gen/files/tl2cpp/tl-combinator.cpp @@ -100,7 +100,7 @@ void CombinatorStore::gen_arg_processing(CodeGenerator &W, const std::unique_ptr auto *as_type_var = arg->type_expr->as(); kphp_assert(as_type_var); if (!typed_mode) { - const auto *k2_tl_storers_prefix = G->is_output_mode_k2_component() ? "RpcImageState::get()." : ""; + const auto *k2_tl_storers_prefix = G->is_output_mode_k2() ? "RpcImageState::get()." : ""; W << "auto _cur_arg = " << fmt_format("tl_arr_get(tl_object, {}, {}, {}L)", tl2cpp::register_tl_const_str(arg->name), arg->idx, tl2cpp::hash_tl_const_str(arg->name)) << ";" << NL; diff --git a/compiler/compiler-core.cpp b/compiler/compiler-core.cpp index 521ea99d41..bebcc37411 100644 --- a/compiler/compiler-core.cpp +++ b/compiler/compiler-core.cpp @@ -120,15 +120,22 @@ void CompilerCore::finish() { } void CompilerCore::register_settings(CompilerSettings *settings) { - kphp_assert (settings_ == nullptr); + kphp_assert(settings_ == nullptr); settings_ = settings; + const auto mode = settings->mode.get(); - if (settings->mode.get() == "cli") { + if (mode == "cli") { output_mode = OutputMode::cli; - } else if (settings->mode.get() == "lib") { + } else if (mode == "lib") { output_mode = OutputMode::lib; - } else if (settings->mode.get() == "k2-component") { - output_mode = OutputMode::k2_component; + } else if (mode == "k2-cli") { + output_mode = OutputMode::k2_cli; + } else if (mode == "k2-server") { + output_mode = OutputMode::k2_server; + } else if (mode == "k2-oneshot") { + output_mode = OutputMode::k2_oneshot; + } else if (mode == "k2-multishot") { + output_mode = OutputMode::k2_multishot; } else { output_mode = OutputMode::server; } diff --git a/compiler/compiler-core.h b/compiler/compiler-core.h index 4dbf3e7d4a..7d02d4e180 100644 --- a/compiler/compiler-core.h +++ b/compiler/compiler-core.h @@ -25,10 +25,13 @@ #include "compiler/tl-classes.h" enum class OutputMode { - server, // -M server - cli, // -M cli - lib, // -M lib - k2_component // -M k2-component + server, // -M server + cli, // -M cli + lib, // -M lib + k2_cli, // -M k2-cli + k2_server, // -M k2-server + k2_oneshot, // -M k2-oneshot + k2_multishot, // -M k2-multishot }; class CompilerCore { @@ -189,8 +192,24 @@ class CompilerCore { return output_mode == OutputMode::lib; } - bool is_output_mode_k2_component() const { - return output_mode == OutputMode::k2_component; + bool is_output_mode_k2_cli() const { + return output_mode == OutputMode::k2_cli; + } + + bool is_output_mode_k2_server() const { + return output_mode == OutputMode::k2_server; + } + + bool is_output_mode_k2_oneshot() const { + return output_mode == OutputMode::k2_oneshot; + } + + bool is_output_mode_k2_multishot() const { + return output_mode == OutputMode::k2_multishot; + } + + bool is_output_mode_k2() const { + return is_output_mode_k2_cli() || is_output_mode_k2_server() || is_output_mode_k2_oneshot() || is_output_mode_k2_multishot(); } Stats stats; diff --git a/compiler/compiler-settings.cpp b/compiler/compiler-settings.cpp index 6d17d6d0b0..cca200a018 100644 --- a/compiler/compiler-settings.cpp +++ b/compiler/compiler-settings.cpp @@ -216,8 +216,10 @@ void CompilerSettings::init() { option_as_dir(kphp_src_path); functions_file.value_ = get_full_path(functions_file.get()); runtime_sha256_file.value_ = get_full_path(runtime_sha256_file.get()); + + bool is_k2_mode = mode.get().substr(0, 3) == "k2-"; if (link_file.value_.empty()) { - if (mode.get() == "k2-component") { + if (is_k2_mode) { link_file.value_ = kphp_src_path.get() + "/objs/libkphp-light-runtime.a"; } else { link_file.value_ = kphp_src_path.get() + "/objs/libkphp-full-runtime.a"; @@ -225,7 +227,7 @@ void CompilerSettings::init() { } link_file.value_ = get_full_path(link_file.get()); if (functions_file.value_.empty()) { - if (mode.get() == "k2-component") { + if (is_k2_mode) { functions_file.value_ = kphp_src_path.get() + "/builtin-functions/kphp-light/functions.txt"; } else { functions_file.value_ = kphp_src_path.get() + "/builtin-functions/kphp-full/_functions.txt"; @@ -233,8 +235,8 @@ void CompilerSettings::init() { } functions_file.value_ = get_full_path(functions_file.get()); - if (k2_component_name.get() != "KPHP" || k2_component_is_oneshot.get()) { - kphp_error(mode.get() == "k2-component", "Options \"k2-component-name\" and \"oneshot\" available only fore k2-component mode"); + if (k2_component_name.get() != "KPHP") { + kphp_error(is_k2_mode, "Option \"k2-component-name\" is only available for k2 component modes"); } if (mode.get() == "lib") { @@ -302,7 +304,7 @@ void CompilerSettings::init() { if (!no_pch.get()) { ss << " -Winvalid-pch -fpch-preprocess"; } - if (mode.get() == "k2-component" || dynamic_incremental_linkage.get()) { + if (is_k2_mode || dynamic_incremental_linkage.get()) { ss << " -fPIC"; } if (vk::contains(cxx.get(), "clang")) { @@ -316,7 +318,7 @@ void CompilerSettings::init() { #error unsupported __cplusplus value #endif - if (mode.get() == "k2-component") { + if (is_k2_mode) { // for now k2-component must be compiled with clang and statically linked libc++ ss << " -stdlib=libc++"; } else { @@ -413,7 +415,7 @@ void CompilerSettings::init() { option_as_dir(dest_dir); dest_cpp_dir.value_ = dest_dir.get() + "kphp/"; dest_objs_dir.value_ = dest_dir.get() + "objs/"; - if (mode.get() == "k2-component") { + if (is_k2_mode) { binary_path.value_ = dest_dir.get() + k2_component_name.get() + ".so"; } else { binary_path.value_ = dest_dir.get() + mode.get(); diff --git a/compiler/compiler-settings.h b/compiler/compiler-settings.h index bd0222d278..cb20ce99ef 100644 --- a/compiler/compiler-settings.h +++ b/compiler/compiler-settings.h @@ -149,9 +149,8 @@ class CompilerSettings : vk::not_copyable { KphpOption compilation_metrics_file; KphpOption override_kphp_version; KphpOption php_code_version; - KphpOption k2_component_name; - KphpOption k2_component_is_oneshot; + KphpOption k2_component_name; KphpOption cxx; KphpOption cxx_toolchain_dir; diff --git a/compiler/kphp2cpp.cpp b/compiler/kphp2cpp.cpp index 42b42272ae..0ac07c0def 100644 --- a/compiler/kphp2cpp.cpp +++ b/compiler/kphp2cpp.cpp @@ -215,8 +215,8 @@ int main(int argc, char *argv[]) { 'f', "functions-file", "KPHP_FUNCTIONS"); parser.add("File with kphp runtime sha256 hash", settings->runtime_sha256_file, "runtime-sha256", "KPHP_RUNTIME_SHA256", "${KPHP_PATH}/objs/php_lib_version.sha256"); - parser.add("The output binary type: server, k2-component, cli or lib", settings->mode, - 'M', "mode", "KPHP_MODE", "server", {"server", "k2-component", "cli", "lib"}); + parser.add("The output binary type: server, cli, lib, k2-cli, k2-server, k2-oneshot, k2-multishot", settings->mode, 'M', "mode", "KPHP_MODE", "server", + {"server", "cli", "lib", "k2-cli", "k2-server", "k2-oneshot", "k2-multishot"}); parser.add("A runtime library for building the output binary", settings->link_file, 'l', "link-with", "KPHP_LINK_FILE"); parser.add("Build runtime from sources", settings->force_link_runtime, @@ -298,8 +298,6 @@ int main(int argc, char *argv[]) { "require-class-typing", "KPHP_REQUIRE_CLASS_TYPING"); parser.add("Define k2 component name. Default is \"KPHP\"", settings->k2_component_name, "k2-component-name", "KPHP_K2_COMPONENT_NAME", "KPHP"); - parser.add("Enable oneshot mode to k2 component", settings->k2_component_is_oneshot, - "oneshot", "KPHP_K2_COMPONENT_IS_ONESHOT"); parser.add_implicit_option("Linker flags", settings->ld_flags); parser.add_implicit_option("Incremental linker flags", settings->incremental_linker_flags); diff --git a/compiler/make/make.cpp b/compiler/make/make.cpp index 87da4cde6a..52a334070a 100644 --- a/compiler/make/make.cpp +++ b/compiler/make/make.cpp @@ -548,10 +548,10 @@ void run_make() { auto objs = run_pre_make(output_mode, settings, make_stats_file, make, obj_index, bin_file, obj_rt_index); stage::die_if_global_errors(); - if (output_mode == OutputMode::lib) { + if (G->is_output_mode_lib()) { // todo:k2 think about kphp libraries make.create_objs2static_lib_target(objs, &bin_file); - } else if (output_mode == OutputMode::k2_component) { + } else if (G->is_output_mode_k2()) { make.create_objs2k2_component_target(objs, &bin_file); } else { const std::string build_stage{"Compiling"}; diff --git a/compiler/pipes/calc-bad-vars.cpp b/compiler/pipes/calc-bad-vars.cpp index cac43595d2..f3f6a0cc57 100644 --- a/compiler/pipes/calc-bad-vars.cpp +++ b/compiler/pipes/calc-bad-vars.cpp @@ -696,7 +696,7 @@ class CalcBadVars { { FuncCallGraph call_graph(std::move(functions), dep_datas); - if (G->is_output_mode_k2_component()) { + if (G->is_output_mode_k2()) { calc_k2_fork(call_graph, dep_datas); calc_interruptible(call_graph); } else { diff --git a/compiler/pipes/code-gen.cpp b/compiler/pipes/code-gen.cpp index e4db43bf9f..32674d4462 100644 --- a/compiler/pipes/code-gen.cpp +++ b/compiler/pipes/code-gen.cpp @@ -117,7 +117,7 @@ void CodeGenF::on_finish(DataStream> &os) { // TODO: should be done in lib mode also, but in some other way if (!G->is_output_mode_lib()) { - if (!G->is_output_mode_k2_component()) { + if (!G->is_output_mode_k2()) { code_gen_start_root_task(os, std::make_unique(vk::singleton::get().flush_forkable_types(), vk::singleton::get().flush_waitable_types())); } @@ -132,10 +132,10 @@ void CodeGenF::on_finish(DataStream> &os) { code_gen_start_root_task(os, std::make_unique()); code_gen_start_root_task(os, std::make_unique()); - if (!G->is_output_mode_lib() && !G->is_output_mode_k2_component()) { + if (!G->is_output_mode_lib() && !G->is_output_mode_k2()) { code_gen_start_root_task(os, std::make_unique()); } - if (G->is_output_mode_k2_component()) { + if (G->is_output_mode_k2()) { code_gen_start_root_task(os, std::make_unique()); } } diff --git a/runtime-light/component/component.cpp b/runtime-light/component/component.cpp index 4d7f4b678c..161c8146ec 100644 --- a/runtime-light/component/component.cpp +++ b/runtime-light/component/component.cpp @@ -6,18 +6,104 @@ #include #include +#include #include #include "runtime-core/utils/kphp-assert-core.h" #include "runtime-light/core/globals/php-init-scripts.h" +#include "runtime-light/coroutine/awaitable.h" +#include "runtime-light/coroutine/task.h" #include "runtime-light/header.h" #include "runtime-light/scheduler/scheduler.h" +#include "runtime-light/streams/streams.h" #include "runtime-light/utils/context.h" +#include "runtime-light/utils/json-functions.h" + +namespace { + +constexpr uint32_t K2_INVOKE_HTTP_MAGIC = 0xd909efe8; +constexpr uint32_t K2_INVOKE_JOB_WORKER_MAGIC = 0x437d7312; + +void init_http_superglobals(const string &http_query) noexcept { + auto &component_ctx{*get_component_context()}; + component_ctx.php_script_mutable_globals_singleton.get_superglobals().v$_SERVER.set_value(string{"QUERY_TYPE"}, string{"http"}); + component_ctx.php_script_mutable_globals_singleton.get_superglobals().v$_POST = f$json_decode(http_query, true); +} + +task_t init_kphp_cli_component() noexcept { + co_return co_await wait_for_incoming_stream_t{}; +} + +task_t init_kphp_server_component() noexcept { + uint32_t magic{}; + const auto stream_d{co_await wait_for_incoming_stream_t{}}; + const auto read{co_await read_exact_from_stream(stream_d, reinterpret_cast(std::addressof(magic)), sizeof(uint32_t))}; + php_assert(read == sizeof(uint32_t)); + if (magic == K2_INVOKE_HTTP_MAGIC) { + const auto [buffer, size]{co_await read_all_from_stream(stream_d)}; + init_http_superglobals(string{buffer, static_cast(size)}); + get_platform_context()->allocator.free(buffer); + } else if (magic == K2_INVOKE_JOB_WORKER_MAGIC) { + php_error("not implemented"); + } else { + php_error("server got unexpected type of request: 0x%x", magic); + } + + co_return stream_d; +} + +int32_t merge_output_buffers(ComponentState &component_ctx) noexcept { + Response &response{component_ctx.response}; + php_assert(response.current_buffer >= 0); + + int32_t ob_first_not_empty{}; + while (ob_first_not_empty < response.current_buffer && response.output_buffers[ob_first_not_empty].size() == 0) { + ++ob_first_not_empty; // TODO: optimize by precomputing final buffer's size to reserve enough space + } + for (auto i = ob_first_not_empty + 1; i <= response.current_buffer; i++) { + response.output_buffers[ob_first_not_empty].append(response.output_buffers[i].c_str(), response.output_buffers[i].size()); + } + return ob_first_not_empty; +} + +} // namespace void ComponentState::init_script_execution() noexcept { kphp_core_context.init(); - init_php_scripts_in_each_worker(php_script_mutable_globals_singleton, main_task); - scheduler.suspend(std::make_pair(main_task.get_handle(), WaitEvent::Rechedule{})); + init_php_scripts_in_each_worker(php_script_mutable_globals_singleton, main_task_); + scheduler.suspend(std::make_pair(main_task_.get_handle(), WaitEvent::Rechedule{})); +} + +template +task_t ComponentState::run_component_prologue() noexcept { + static_assert(kind != ComponentKind::Invalid); + + component_kind_ = kind; + if constexpr (kind == ComponentKind::CLI) { + standard_stream_ = co_await init_kphp_cli_component(); + } else if constexpr (kind == ComponentKind::Server) { + standard_stream_ = co_await init_kphp_server_component(); + } +} + +template task_t ComponentState::run_component_prologue(); +template task_t ComponentState::run_component_prologue(); +template task_t ComponentState::run_component_prologue(); +template task_t ComponentState::run_component_prologue(); + +task_t ComponentState::run_component_epilogue() noexcept { + if (component_kind_ == ComponentKind::Oneshot || component_kind_ == ComponentKind::Multishot) { + co_return; + } + if (standard_stream() == INVALID_PLATFORM_DESCRIPTOR) { + poll_status = PollStatus::PollFinishedError; + co_return; + } + + const auto &buffer{response.output_buffers[merge_output_buffers(*this)]}; + if ((co_await write_all_to_stream(standard_stream(), buffer.buffer(), buffer.size())) != buffer.size()) { + php_warning("can't write component result to stream %" PRIu64, standard_stream()); + } } void ComponentState::process_platform_updates() noexcept { @@ -51,12 +137,6 @@ void ComponentState::process_platform_updates() noexcept { } } else { // update on incoming stream php_debug("got new incoming stream %" PRIu64, stream_d); - if (standard_stream_ != INVALID_PLATFORM_DESCRIPTOR) { - php_warning("skip new incoming stream since previous one is not closed"); - release_stream(stream_d); - continue; - } // TODO: multiple incoming streams (except for http queries) - standard_stream_ = stream_d; incoming_streams_.push_back(stream_d); opened_streams_.insert(stream_d); if (const auto schedule_status{scheduler.schedule(ScheduleEvent::IncomingStream{.stream_d = stream_d})}; schedule_status == ScheduleStatus::Error) { diff --git a/runtime-light/component/component.h b/runtime-light/component/component.h index 4560999d76..81531b2788 100644 --- a/runtime-light/component/component.h +++ b/runtime-light/component/component.h @@ -27,6 +27,15 @@ constexpr uint64_t INVALID_PLATFORM_DESCRIPTOR = 0; using CoroutineScheduler = SimpleCoroutineScheduler; static_assert(CoroutineSchedulerConcept); +/** + * Supported kinds of KPHP components: + * 1. CLI — works the same way as regular PHP script does + * 2. Server — automatically accepts a stream and expects it to contain either http or job worker request + * 3. Oneshot — can only accept one incoming stream + * 4. Multishot — can accept any number of incoming streams + */ +enum class ComponentKind : uint8_t { Invalid, CLI, Server, Oneshot, Multishot }; + struct ComponentState { template using unordered_set = memory_resource::stl::unordered_set; @@ -47,6 +56,12 @@ struct ComponentState { ~ComponentState() = default; void init_script_execution() noexcept; + + template + task_t run_component_prologue() noexcept; + + task_t run_component_epilogue() noexcept; + void process_platform_updates() noexcept; bool stream_updated(uint64_t stream_d) const noexcept { @@ -71,7 +86,7 @@ struct ComponentState { CoroutineScheduler scheduler; ForkComponentContext fork_component_context; - PollStatus poll_status = PollStatus::PollReschedule; + PollStatus poll_status{PollStatus::PollReschedule}; Response response; PhpScriptMutableGlobals php_script_mutable_globals_singleton; @@ -82,8 +97,9 @@ struct ComponentState { RegexComponentState regex_component_context; private: - task_t main_task; + task_t main_task_; + ComponentKind component_kind_{ComponentKind::Invalid}; uint64_t standard_stream_{INVALID_PLATFORM_DESCRIPTOR}; deque incoming_streams_; unordered_set opened_streams_; diff --git a/runtime-light/core/globals/php-script-globals.h b/runtime-light/core/globals/php-script-globals.h index 5b843dae17..a1a45b08d4 100644 --- a/runtime-light/core/globals/php-script-globals.h +++ b/runtime-light/core/globals/php-script-globals.h @@ -33,7 +33,7 @@ class PhpScriptMutableGlobals { PhpScriptBuiltInSuperGlobals superglobals; public: - PhpScriptMutableGlobals(memory_resource::unsynchronized_pool_resource &resource) + explicit PhpScriptMutableGlobals(memory_resource::unsynchronized_pool_resource &resource) : libs_linear_mem(unordered_map::allocator_type{resource}) {} static PhpScriptMutableGlobals ¤t() noexcept; diff --git a/runtime-light/stdlib/exit/exit-functions.cpp b/runtime-light/stdlib/exit/exit-functions.cpp index c097812977..8db7a4ad3b 100644 --- a/runtime-light/stdlib/exit/exit-functions.cpp +++ b/runtime-light/stdlib/exit/exit-functions.cpp @@ -6,44 +6,10 @@ #include -#include "runtime-core/utils/kphp-assert-core.h" #include "runtime-light/component/component.h" #include "runtime-light/header.h" -#include "runtime-light/streams/streams.h" #include "runtime-light/utils/context.h" -namespace { - -int32_t ob_merge_buffers() noexcept { - Response &response{get_component_context()->response}; - php_assert(response.current_buffer >= 0); - - int32_t ob_first_not_empty{}; - while (ob_first_not_empty < response.current_buffer && response.output_buffers[ob_first_not_empty].size() == 0) { - ++ob_first_not_empty; - } - for (auto i = ob_first_not_empty + 1; i <= response.current_buffer; i++) { - response.output_buffers[ob_first_not_empty].append(response.output_buffers[i].c_str(), response.output_buffers[i].size()); - } - return ob_first_not_empty; -} - -} // namespace - -task_t shutdown_script() noexcept { - auto &component_ctx{*get_component_context()}; - const auto standard_stream{component_ctx.standard_stream()}; - if (standard_stream == INVALID_PLATFORM_DESCRIPTOR) { - component_ctx.poll_status = PollStatus::PollFinishedError; - co_return; - } - - const auto &buffer{component_ctx.response.output_buffers[ob_merge_buffers()]}; - if ((co_await write_all_to_stream(standard_stream, buffer.buffer(), buffer.size())) != buffer.size()) { - php_warning("can't write component result to stream %" PRIu64, standard_stream); - } -} - task_t f$exit(const mixed &v) noexcept { // TODO: make it synchronous int64_t exit_code{}; if (v.is_string()) { @@ -56,10 +22,10 @@ task_t f$exit(const mixed &v) noexcept { // TODO: make it synchronous } else { exit_code = 1; } - co_await shutdown_script(); auto &component_ctx{*get_component_context()}; + co_await component_ctx.run_component_epilogue(); component_ctx.poll_status = component_ctx.poll_status != PollStatus::PollFinishedError && exit_code == 0 ? PollStatus::PollFinishedOk : PollStatus::PollFinishedError; component_ctx.release_all_streams(); - get_platform_context()->abort(); + get_platform_context()->exit(static_cast(exit_code)); } diff --git a/runtime-light/streams/streams.cpp b/runtime-light/streams/streams.cpp index 2d19628090..41147037ce 100644 --- a/runtime-light/streams/streams.cpp +++ b/runtime-light/streams/streams.cpp @@ -9,31 +9,11 @@ #include #include -#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" #include "runtime-light/header.h" #include "runtime-light/utils/context.h" -#include "runtime-light/utils/json-functions.h" - -namespace { - -void init_http_superglobals(const string &http_query) { - auto &component_ctx{*get_component_context()}; - component_ctx.php_script_mutable_globals_singleton.get_superglobals().v$_SERVER.set_value(string{"QUERY_TYPE"}, string{"http"}); - component_ctx.php_script_mutable_globals_singleton.get_superglobals().v$_POST = f$json_decode(http_query, true); -} - -} // namespace - -task_t accept_initial_stream() noexcept { - const auto incoming_stream_d{co_await wait_for_incoming_stream_t{}}; - const auto [buffer, size]{co_await read_all_from_stream(incoming_stream_d)}; - init_http_superglobals(string{buffer, static_cast(size)}); - get_platform_context()->allocator.free(buffer); - co_return incoming_stream_d; -} task_t> read_all_from_stream(uint64_t stream_d) noexcept { const auto &platform_ctx = *get_platform_context(); diff --git a/tests/kphp_tester.py b/tests/kphp_tester.py index ce2cb96f2c..77a79f6fe0 100755 --- a/tests/kphp_tester.py +++ b/tests/kphp_tester.py @@ -64,11 +64,10 @@ def make_kphp_once_runner(self, use_nocc, cxx_name, k2_bin): ) def set_up_env_for_k2(self, cxx_name="clang++"): - self.env_vars["KPHP_MODE"] = "k2-component" + self.env_vars["KPHP_MODE"] = "k2-cli" 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_K2_COMPONENT_IS_ONESHOT"] = "1" self.env_vars["KPHP_FORCE_LINK_RUNTIME"] = "1"