Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
3e46d15
[k2] add two errno codes to k2-api
apolyakov Mar 20, 2026
ac0e80f
[k2] move exit functions to stdlib/system/
apolyakov Mar 20, 2026
b9bf474
[k2] rename ScriptAllocatorManaged -> kphp::memory::script_allocator_…
apolyakov Mar 20, 2026
7c94510
[k2] add kphp::forks::scoped_id_managed to ease fork id management in…
apolyakov Mar 20, 2026
6c28747
[k2] make kphp::coro::event really movable and not copyable
apolyakov Mar 20, 2026
2024b0c
[k2] fix how kphp::coro::when_any works with void
apolyakov Mar 20, 2026
482810f
[k2] make kphp::coro::event safe to move
apolyakov Mar 20, 2026
210fe27
[k2] add more errno codes to k2-api
apolyakov Mar 20, 2026
90125cc
[k2] implement ignore_user_abort for HTTP server mode
apolyakov Mar 20, 2026
2a50eb8
[k2] add kphp::component::connection
apolyakov Mar 21, 2026
6777efc
[k2] make kphp::component::watcher safer
apolyakov Mar 21, 2026
40454ff
[k2] add kphp::component::stream::status method
apolyakov Mar 21, 2026
ab391a6
[k2] reimplement ignore_user_abort with kphp::component::connection
apolyakov Mar 21, 2026
a23d131
fix code style
apolyakov Mar 21, 2026
6cf724e
add id_managed to ignore_user_abort
apolyakov Mar 21, 2026
14881a9
get rid of watcher. inline its functionality into connection
apolyakov Mar 21, 2026
2e764df
integrate multipart form-data cleanup into ignore user abort
apolyakov Mar 28, 2026
1659533
throw error on unsupported ingore_user_abort call
apolyakov Mar 28, 2026
d461691
minor change
apolyakov Mar 28, 2026
4ad992f
add missing include
apolyakov Mar 28, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions builtin-functions/kphp-light/stdlib/server-functions.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ function kphp_get_runtime_config() ::: mixed;

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

/** @kphp-extern-func-info interruptible */
function ignore_user_abort ($enable ::: ?bool = null) ::: int;

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

define('PHP_URL_SCHEME', 0);
Expand Down Expand Up @@ -125,8 +128,6 @@ define('LC_MESSAGES', 5);

function debug_backtrace() ::: string[][];

/** @kphp-extern-func-info stub generation-required */
function ignore_user_abort ($enable ::: ?bool = null) ::: int;
/** @kphp-extern-func-info stub generation-required */
function flush() ::: void;

Expand Down
10 changes: 7 additions & 3 deletions runtime-common/core/allocator/script-allocator-managed.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@

#include "runtime-common/core/allocator/runtime-allocator.h"

class ScriptAllocatorManaged {
namespace kphp::memory {

class script_allocator_managed {
public:
static void* operator new(size_t size) noexcept {
return RuntimeAllocator::get().alloc_script_memory(size);
}

static void* operator new(size_t, void* ptr) noexcept {
static void* operator new(size_t /*unused*/, void* ptr) noexcept {
return ptr;
}

Expand All @@ -27,5 +29,7 @@ class ScriptAllocatorManaged {
static void operator delete[](void* ptr) = delete;

protected:
~ScriptAllocatorManaged() = default;
~script_allocator_managed() = default;
};

} // namespace kphp::memory
4 changes: 2 additions & 2 deletions runtime-common/core/class-instance/refcountable-php-classes.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

#include "runtime-common/core/allocator/script-allocator-managed.h"

class abstract_refcountable_php_interface : public ScriptAllocatorManaged {
class abstract_refcountable_php_interface : public kphp::memory::script_allocator_managed {
public:
abstract_refcountable_php_interface() __attribute__((always_inline)) = default;
virtual ~abstract_refcountable_php_interface() noexcept __attribute__((always_inline)) = default;
Expand Down Expand Up @@ -98,7 +98,7 @@ class refcountable_polymorphic_php_classes_virt<> : public virtual abstract_refc
};

template<class Derived>
class refcountable_php_classes : public ScriptAllocatorManaged {
class refcountable_php_classes : public kphp::memory::script_allocator_managed {
public:
void add_ref() noexcept {
if (refcnt < ExtraRefCnt::for_global_const) {
Expand Down
2 changes: 1 addition & 1 deletion runtime-light/allocator/allocator.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#include "runtime-common/core/allocator/script-allocator-managed.h"
#include "runtime-light/allocator/allocator-state.h"

template<std::derived_from<ScriptAllocatorManaged> T, typename... Args>
template<std::derived_from<kphp::memory::script_allocator_managed> T, typename... Args>
requires std::constructible_from<T, Args...>
auto make_unique_on_script_memory(Args&&... args) noexcept {
return std::make_unique<T>(std::forward<Args>(args)...);
Expand Down
13 changes: 10 additions & 3 deletions runtime-light/coroutine/detail/when-any.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#pragma once

#include <concepts>
#include <cstddef>
#include <functional>
#include <optional>
Expand Down Expand Up @@ -249,12 +250,17 @@ class when_any_task {
};

struct when_any_task_promise_void : public when_any_task_promise_common {
auto yield_value() const noexcept {
private:
std::optional<kphp::coro::void_value> m_result;

public:
auto yield_value(kphp::coro::void_value&& return_value) noexcept {
m_result.emplace(return_value);
return when_any_task_promise_common::final_suspend();
}

constexpr auto result() const noexcept -> std::optional<kphp::coro::void_value> {
return std::optional<kphp::coro::void_value>{std::in_place};
auto result() noexcept -> std::optional<kphp::coro::void_value> {
return m_result;
}

constexpr auto return_void() const noexcept -> void {}
Expand Down Expand Up @@ -296,6 +302,7 @@ template<kphp::coro::concepts::awaitable awaitable_type>
auto make_when_any_task(awaitable_type awaitable) noexcept -> when_any_task<typename kphp::coro::awaitable_traits<awaitable_type>::awaiter_return_type> {
if constexpr (std::is_void_v<typename kphp::coro::awaitable_traits<awaitable_type>::awaiter_return_type>) {
co_await std::move(awaitable);
co_yield kphp::coro::void_value{};
} else {
co_yield co_await std::move(awaitable);
}
Expand Down
81 changes: 63 additions & 18 deletions runtime-light/coroutine/event.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,43 @@

#include <concepts>
#include <coroutine>
#include <memory>
#include <utility>

#include "common/mixin/not_copyable.h"
#include "runtime-common/core/allocator/script-allocator-managed.h"
#include "runtime-light/coroutine/async-stack.h"
#include "runtime-light/coroutine/coroutine-state.h"
#include "runtime-light/stdlib/diagnostics/logs.h"

namespace kphp::coro {

class event {
// 1) nullptr => not set
// 2) awaiter* => linked list of awaiters waiting for the event to trigger
// 3) this => The event is triggered and all awaiters are resumed
void* m_state{};
struct event_controller : kphp::memory::script_allocator_managed, vk::not_copyable {
// 1) nullptr => not set
// 2) awaiter* => linked list of awaiters waiting for the event to trigger
// 3) this => The event is triggered and all awaiters are resumed
void* m_state{};

auto set() noexcept -> void;
auto unset() noexcept -> void;
auto is_set() const noexcept -> bool;
};

std::unique_ptr<event_controller> m_controller;

struct awaiter {
event& m_event;
bool m_suspended{};
event_controller& m_controller;
std::coroutine_handle<> m_awaiting_coroutine;
kphp::coro::async_stack_root& m_async_stack_root;
kphp::coro::async_stack_frame* m_caller_async_stack_frame{};

awaiter* m_next{};
awaiter* m_prev{};

explicit awaiter(event& event) noexcept
: m_event(event),
explicit awaiter(event_controller& event_controller) noexcept
: m_controller(event_controller),
m_async_stack_root(CoroutineInstanceState::get().coroutine_stack_root) {}

awaiter(const awaiter&) = delete;
Expand All @@ -55,10 +66,28 @@ class event {
};

public:
auto set() noexcept -> void;
event() noexcept
: m_controller(std::make_unique<event_controller>()) {
kphp::log::assertion(m_controller != nullptr);
}

auto unset() noexcept -> void;
event(event&& other) noexcept
: m_controller(std::move(other.m_controller)) {}

event& operator=(event&& other) noexcept {
if (this != std::addressof(other)) {
m_controller = std::move(other.m_controller);
}
return *this;
}

~event() = default;

event(const event&) = delete;
event& operator=(const event&) = delete;

auto set() noexcept -> void;
auto unset() noexcept -> void;
auto is_set() const noexcept -> bool;

auto operator co_await() noexcept;
Expand All @@ -72,14 +101,14 @@ inline auto event::awaiter::cancel_awaiter() noexcept -> void {
m_prev->m_next = m_next;
} else {
// we are the head of the awaiters list, so we need to update the head
m_event.m_state = m_next;
m_controller.m_state = m_next;
}
m_next = nullptr;
m_prev = nullptr;
}

inline auto event::awaiter::await_ready() const noexcept -> bool {
return m_event.is_set();
return m_controller.is_set();
}

template<std::derived_from<kphp::coro::async_stack_element> caller_promise_type>
Expand All @@ -90,15 +119,15 @@ auto event::awaiter::await_suspend(std::coroutine_handle<caller_promise_type> aw
m_suspended = true;
m_awaiting_coroutine = awaiting_coroutine;

m_next = static_cast<event::awaiter*>(m_event.m_state);
m_next = static_cast<event::awaiter*>(m_controller.m_state);

// ensure that the event isn't triggered
kphp::log::assertion(reinterpret_cast<event*>(m_next) != std::addressof(m_event));
kphp::log::assertion(reinterpret_cast<event_controller*>(m_next) != std::addressof(m_controller));

if (m_next != nullptr) {
m_next->m_prev = this;
}
m_event.m_state = this;
m_controller.m_state = this;
}

inline auto event::awaiter::await_resume() noexcept -> void {
Expand All @@ -109,7 +138,7 @@ inline auto event::awaiter::await_resume() noexcept -> void {
}
}

inline auto event::set() noexcept -> void {
inline auto event::event_controller::set() noexcept -> void {
void* prev_value{std::exchange(m_state, this)};
if (prev_value == this || prev_value == nullptr) [[unlikely]] {
return;
Expand All @@ -122,18 +151,34 @@ inline auto event::set() noexcept -> void {
}
}

inline auto event::unset() noexcept -> void {
inline auto event::event_controller::unset() noexcept -> void {
if (m_state == this) {
m_state = nullptr;
}
}

inline auto event::is_set() const noexcept -> bool {
inline auto event::event_controller::is_set() const noexcept -> bool {
return m_state == this;
}

inline auto event::set() noexcept -> void {
kphp::log::assertion(m_controller != nullptr);
m_controller->set();
}

inline auto event::unset() noexcept -> void {
kphp::log::assertion(m_controller != nullptr);
m_controller->unset();
}

inline auto event::is_set() const noexcept -> bool {
kphp::log::assertion(m_controller != nullptr);
return m_controller->is_set();
}

inline auto event::operator co_await() noexcept {
return event::awaiter{*this};
kphp::log::assertion(m_controller != nullptr);
return event::awaiter{*this->m_controller};
}

} // namespace kphp::coro
4 changes: 4 additions & 0 deletions runtime-light/k2-platform/k2-api.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ inline constexpr size_t DEFAULT_MEMORY_ALIGN = 16;
} // namespace k2_impl_

inline constexpr int32_t errno_ok = 0;
inline constexpr int32_t errno_ebusy = EBUSY;
inline constexpr int32_t errno_enodev = ENODEV;
inline constexpr int32_t errno_einval = EINVAL;
inline constexpr int32_t errno_enodata = ENODATA;
Expand All @@ -46,6 +47,9 @@ inline constexpr int32_t errno_eshutdown = ESHUTDOWN;
inline constexpr int32_t errno_ecanceled = ECANCELED;
inline constexpr int32_t errno_erange = ERANGE;
inline constexpr int32_t errno_enoent = ENOENT;
inline constexpr int32_t errno_eopnotsupp = EOPNOTSUPP;
inline constexpr int32_t errno_ealready = EALREADY;
inline constexpr int32_t errno_einprogress = EINPROGRESS;

using descriptor = uint64_t;
inline constexpr k2::descriptor INVALID_PLATFORM_DESCRIPTOR = 0;
Expand Down
5 changes: 3 additions & 2 deletions runtime-light/server/http/http-server-state.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@
#include <locale>
#include <optional>
#include <string_view>
#include <utility>

#include "common/mixin/not_copyable.h"
#include "runtime-common/core/allocator/script-allocator.h"
#include "runtime-common/core/runtime-core.h"
#include "runtime-common/core/std/containers.h"
#include "runtime-light/coroutine/task.h"
#include "runtime-light/streams/stream.h"
#include "runtime-light/streams/connection.h"

namespace kphp::http {

Expand Down Expand Up @@ -57,7 +58,7 @@ struct HttpServerInstanceState final : private vk::not_copyable {
static constexpr auto ENCODING_GZIP = static_cast<uint32_t>(1U << 0U);
static constexpr auto ENCODING_DEFLATE = static_cast<uint32_t>(1U << 1U);

std::optional<kphp::component::stream> request_stream;
std::optional<kphp::component::connection> connection;

std::optional<string> opt_raw_post_data;

Expand Down
Loading
Loading