Skip to content

Commit

Permalink
[k2] implement register_shutdown_function (#1177)
Browse files Browse the repository at this point in the history
  • Loading branch information
apolyakov authored Dec 9, 2024
1 parent 357bc05 commit 8490a28
Show file tree
Hide file tree
Showing 17 changed files with 88 additions and 32 deletions.
4 changes: 4 additions & 0 deletions builtin-functions/kphp-light/server.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@

function ini_get ($s ::: string): string | false;

// === Handlers ===================================================================================

function register_shutdown_function (callable():void $callback) ::: void;

// === URL ========================================================================================

define('PHP_URL_SCHEME', 0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ function posix_getpwuid($uid ::: int) ::: mixed[] | false;
function kphp_extended_instance_cache_metrics_init(callable(string $key):string $normalization_function) ::: void;


function register_shutdown_function (callable():void $function) ::: void;
function register_kphp_on_warning_callback(callable(string $warning_message, string[] $stacktrace):void $stacktrace) ::: void;
function register_kphp_on_oom_callback(callable():void $callback) ::: bool;

Expand Down
3 changes: 3 additions & 0 deletions compiler/compiler-settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,9 @@ void CompilerSettings::init() {
if (is_k2_mode) {
// for now k2-component must be compiled with clang and statically linked libc++
ss << " -stdlib=libc++";
ss << " -I" << kphp_src_path.get() + "objs/include ";
ss << " -I" << kphp_src_path.get() + "third-party ";
ss << " -I" << kphp_src_path.get() + "third-party/abseil-cpp ";
} else {
// default value is false
// when we build using full runtime, we should force to use runtime as static lib
Expand Down
4 changes: 4 additions & 0 deletions runtime-common/core/memory-resource/resource_allocator.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#pragma once

#include <functional>
#include <list>
#include <map>
#include <queue>
#include <string>
Expand Down Expand Up @@ -84,6 +85,9 @@ using queue = std::queue<T, std::deque<T, resource_allocator<T, Resource>>>;
template<class T, class Resource>
using vector = std::vector<T, resource_allocator<T, Resource>>;

template<class T, class Resource>
using list = std::list<T, resource_allocator<T, Resource>>;

template<class Resource>
using string = std::basic_string<char, std::char_traits<char>, resource_allocator<char, Resource>>;
} // namespace stl
Expand Down
15 changes: 6 additions & 9 deletions runtime-light/runtime-light.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ include(${THIRD_PARTY_DIR}/abseil-cpp-cmake/abseil-cpp.cmake)
include(${THIRD_PARTY_DIR}/pcre2-cmake/pcre2.cmake)
include(${THIRD_PARTY_DIR}/zlib-cmake/zlib.cmake)

set(THIRD_PARTY_INCLUDE -I${OBJS_DIR}/include -I${THIRD_PARTY_DIR}
-I${THIRD_PARTY_DIR}/abseil-cpp)

# =================================================================================================
include(${RUNTIME_LIGHT_DIR}/allocator/allocator.cmake)
include(${RUNTIME_LIGHT_DIR}/core/core.cmake)
Expand Down Expand Up @@ -41,14 +44,8 @@ set_property(TARGET runtime-light PROPERTY POSITION_INDEPENDENT_CODE ON)
set_target_properties(runtime-light PROPERTIES LIBRARY_OUTPUT_DIRECTORY
${BASE_DIR}/objs)
target_compile_options(
runtime-light
PUBLIC -stdlib=libc++
-iquote
${GENERATED_DIR}
-I${THIRD_PARTY_DIR}
-I${THIRD_PARTY_DIR}/abseil-cpp
-fPIC
-O3)
runtime-light PUBLIC -stdlib=libc++ -iquote ${GENERATED_DIR}
${THIRD_PARTY_INCLUDE} -fPIC -O3)
target_link_options(runtime-light PUBLIC -stdlib=libc++ -static-libstdc++)
# add statically linking libraries
string(JOIN " " ABSEIL_LIBS ${ABSEIL_LIBS})
Expand Down Expand Up @@ -101,7 +98,7 @@ file(

add_library(php_lib_version_j OBJECT
${CMAKE_CURRENT_BINARY_DIR}/php_lib_version.cpp)
target_compile_options(php_lib_version_j PRIVATE -I. -E)
target_compile_options(php_lib_version_j PRIVATE -I. ${THIRD_PARTY_INCLUDE} -E)
target_compile_options(php_lib_version_j PUBLIC -stdlib=libc++)
target_link_options(php_lib_version_j PUBLIC -stdlib=libc++ -static-libstdc++)
add_dependencies(php_lib_version_j kphp-light-runtime)
Expand Down
4 changes: 2 additions & 2 deletions runtime-light/runtime-light.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ ComponentState *k2_create_component() {
php_warning("can't allocate enough memory for ImageState");
return nullptr;
}
php_debug("finish image state creation of \"%s\"", k2::describe()->image_name);
php_debug("finish component state creation of \"%s\"", k2::describe()->image_name);
return component_state_ptr;
}

Expand All @@ -54,7 +54,7 @@ InstanceState *k2_create_instance() {
php_warning("cannot allocate enough memory for ComponentState");
return nullptr;
}
php_debug("finish component state creation of \"%s\"", k2::describe()->image_name);
php_debug("finish instance state creation of \"%s\"", k2::describe()->image_name);
return instance_state_ptr;
}

Expand Down
21 changes: 18 additions & 3 deletions runtime-light/state/instance-state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,22 +75,37 @@ template task_t<void> InstanceState::run_instance_prologue<ImageKind::Oneshot>()
template task_t<void> InstanceState::run_instance_prologue<ImageKind::Multishot>();

task_t<void> InstanceState::run_instance_epilogue() noexcept {
if (std::exchange(shutdown_state_, shutdown_state::in_progress) == shutdown_state::not_started) [[likely]] {
for (auto &sf : shutdown_functions) {
co_await sf;
}
}

// to prevent performing the finalization twice
if (shutdown_state_ == shutdown_state::finished) [[unlikely]] {
co_return;
}

switch (image_kind_) {
case ImageKind::Oneshot:
case ImageKind::Multishot:
co_return;
break;
case ImageKind::CLI: {
const auto &buffer{response.output_buffers[merge_output_buffers()]};
co_return co_await finalize_kphp_cli_component(buffer);
co_await finalize_kphp_cli_component(buffer);
break;
}
case ImageKind::Server: {
const auto &buffer{response.output_buffers[merge_output_buffers()]};
co_return co_await finalize_kphp_server_component(buffer);
co_await finalize_kphp_server_component(buffer);
break;
}
default: {
php_error("unexpected ImageKind");
}
}
release_all_streams();
shutdown_state_ = shutdown_state::finished;
}

void InstanceState::process_platform_updates() noexcept {
Expand Down
15 changes: 12 additions & 3 deletions runtime-light/state/instance-state.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ struct InstanceState final : vk::not_copyable {
template<typename T>
using deque = memory_resource::stl::deque<T, memory_resource::unsynchronized_pool_resource>;

template<typename T>
using list = memory_resource::stl::list<T, memory_resource::unsynchronized_pool_resource>;

InstanceState() noexcept
: allocator(INIT_INSTANCE_ALLOCATOR_SIZE, 0)
, scheduler(allocator.memory_resource)
Expand All @@ -62,9 +65,10 @@ struct InstanceState final : vk::not_copyable {
, rpc_instance_state(allocator.memory_resource)
, http_server_instance_state(allocator.memory_resource)
, regex_instance_state(allocator.memory_resource)
, incoming_streams_(deque<uint64_t>::allocator_type{allocator.memory_resource})
, opened_streams_(unordered_set<uint64_t>::allocator_type{allocator.memory_resource})
, pending_updates_(unordered_set<uint64_t>::allocator_type{allocator.memory_resource}) {}
, shutdown_functions(decltype(shutdown_functions)::allocator_type{allocator.memory_resource})
, incoming_streams_(decltype(incoming_streams_)::allocator_type{allocator.memory_resource})
, opened_streams_(decltype(opened_streams_)::allocator_type{allocator.memory_resource})
, pending_updates_(decltype(pending_updates_)::allocator_type{allocator.memory_resource}) {}

~InstanceState() = default;

Expand Down Expand Up @@ -132,9 +136,14 @@ struct InstanceState final : vk::not_copyable {
SystemInstanceState system_instance_state{};
FileStreamInstanceState file_stream_instance_state{};

list<task_t<void>> shutdown_functions;

private:
task_t<void> main_task_;

enum class shutdown_state : uint8_t { not_started, in_progress, finished };
shutdown_state shutdown_state_{shutdown_state::not_started};

ImageKind image_kind_{ImageKind::Invalid};
uint64_t standard_stream_{INVALID_PLATFORM_DESCRIPTOR};
deque<uint64_t> incoming_streams_;
Expand Down
3 changes: 1 addition & 2 deletions runtime-light/stdlib/exit/exit-functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,8 @@ task_t<void> f$exit(const mixed &v) noexcept { // TODO: make it synchronous
} else {
exit_code = 1;
}
co_await instance_st.run_instance_epilogue();
instance_st.poll_status =
instance_st.poll_status != k2::PollStatus::PollFinishedError && exit_code == 0 ? k2::PollStatus::PollFinishedOk : k2::PollStatus::PollFinishedError;
instance_st.release_all_streams();
co_await instance_st.run_instance_epilogue();
k2::exit(static_cast<int32_t>(exit_code));
}
2 changes: 0 additions & 2 deletions runtime-light/stdlib/exit/exit-functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
#include "runtime-common/core/runtime-core.h"
#include "runtime-light/coroutine/task.h"

task_t<void> shutdown_script() noexcept;

task_t<void> f$exit(const mixed &v = 0) noexcept;

inline task_t<void> f$die(const mixed &v = 0) noexcept {
Expand Down
29 changes: 29 additions & 0 deletions runtime-light/stdlib/server/handler-functions.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Compiler for PHP (aka KPHP)
// Copyright (c) 2024 LLC «V Kontakte»
// Distributed under the GPL v3 License, see LICENSE.notice.txt

#pragma once

#include <concepts>
#include <functional>
#include <utility>

#include "runtime-light/coroutine/task.h"
#include "runtime-light/state/instance-state.h"

template<typename F, typename... Args>
requires(std::invocable<F, Args...>) void f$register_shutdown_function(F &&f, Args &&...args) noexcept {
// it's a lambda coroutine, so:
// 1. don't capture anything;
// 2. parameters are passed by value.
auto shutdown_function_task{std::invoke(
[](F f, Args... args) noexcept -> task_t<void> {
if constexpr (is_async_function_v<F, Args...>) {
co_await std::invoke(f, args...);
} else {
std::invoke(f, args...);
}
},
std::forward<F>(f), std::forward<Args>(args)...)};
InstanceState::get().shutdown_functions.emplace_back(std::move(shutdown_function_task));
}
2 changes: 1 addition & 1 deletion runtime-light/stdlib/string/regex-include.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#include <memory>

#define PCRE2_CODE_UNIT_WIDTH 8
#include "build/third-party/pcre2/pcre2.h"
#include "pcre2/pcre2.h"

using regex_pcre2_general_context_t = std::unique_ptr<pcre2_general_context_8, decltype(std::addressof(pcre2_general_context_free_8))>;
using regex_pcre2_compile_context_t = std::unique_ptr<pcre2_compile_context_8, decltype(std::addressof(pcre2_compile_context_free_8))>;
Expand Down
5 changes: 0 additions & 5 deletions runtime-light/stdlib/system/system-functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,6 @@ int64_t f$estimate_memory_usage(const T &) {
php_critical_error("call to unsupported function");
}

template<typename F>
void f$register_shutdown_function(F &&f) {
php_critical_error("call to unsupported function");
}

template<typename F>
void f$register_kphp_on_warning_callback(F &&callback) {
php_critical_error("call to unsupported function");
Expand Down
4 changes: 2 additions & 2 deletions runtime-light/utils/concepts.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ template<typename T>
concept standard_layout = std::is_standard_layout_v<T>;

template<typename T>
concept hashable = requires(T a) {
{ std::hash<T>{}(a) } -> std::convertible_to<size_t>;
concept hashable = requires(T t) {
{ std::hash<T>{}(t) } -> std::convertible_to<size_t>;
};
2 changes: 1 addition & 1 deletion tests/phpt/dl/403_shutdown.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@ok k2_skip
@ok
<?php

/**
Expand Down
2 changes: 1 addition & 1 deletion tests/phpt/shutdown_functions/no_leak_in_lambda.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@ok k2_skip
@ok
<?php

function test_no_leak_in_shutdown_functions() {
Expand Down
4 changes: 4 additions & 0 deletions third-party/pcre2-cmake/pcre2.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ if(COMPILE_RUNTIME_LIGHT)
add_subdirectory(${THIRD_PARTY_DIR}/pcre2
${CMAKE_BINARY_DIR}/third-party/pcre2)

# copy the generated pcre2.h from build directory
file(COPY ${CMAKE_BINARY_DIR}/third-party/pcre2/pcre2.h
DESTINATION ${OBJS_DIR}/include/pcre2)

# restore C flags
set(CMAKE_C_FLAGS ${SAVE_C_FLAGS})

Expand Down

0 comments on commit 8490a28

Please sign in to comment.