Skip to content

Commit c21e48a

Browse files
authored
[k2] implement ignore_user_abort for HTTP server mode (#1556)
* add new kphp::component::connection class: encapsulates stream, user abort handling, and ignore_user_abort level management * add ignore_user_abort implementation: currently supports HTTP server mode only * make kphp::coro::event improvements: made it movable * fix kphp::coro::when_any for void tasks: fixed void task handling to properly yield and return results
1 parent a649b58 commit c21e48a

21 files changed

Lines changed: 464 additions & 95 deletions

File tree

builtin-functions/kphp-light/stdlib/server-functions.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ function kphp_get_runtime_config() ::: mixed;
1010

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

13+
/** @kphp-extern-func-info interruptible */
14+
function ignore_user_abort ($enable ::: ?bool = null) ::: int;
15+
1316
// === URL ========================================================================================
1417

1518
define('PHP_URL_SCHEME', 0);
@@ -125,8 +128,6 @@ define('LC_MESSAGES', 5);
125128

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

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

runtime-common/core/allocator/script-allocator-managed.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@
88

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

11-
class ScriptAllocatorManaged {
11+
namespace kphp::memory {
12+
13+
class script_allocator_managed {
1214
public:
1315
static void* operator new(size_t size) noexcept {
1416
return RuntimeAllocator::get().alloc_script_memory(size);
1517
}
1618

17-
static void* operator new(size_t, void* ptr) noexcept {
19+
static void* operator new(size_t /*unused*/, void* ptr) noexcept {
1820
return ptr;
1921
}
2022

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

2931
protected:
30-
~ScriptAllocatorManaged() = default;
32+
~script_allocator_managed() = default;
3133
};
34+
35+
} // namespace kphp::memory

runtime-common/core/class-instance/refcountable-php-classes.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

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

12-
class abstract_refcountable_php_interface : public ScriptAllocatorManaged {
12+
class abstract_refcountable_php_interface : public kphp::memory::script_allocator_managed {
1313
public:
1414
abstract_refcountable_php_interface() __attribute__((always_inline)) = default;
1515
virtual ~abstract_refcountable_php_interface() noexcept __attribute__((always_inline)) = default;
@@ -98,7 +98,7 @@ class refcountable_polymorphic_php_classes_virt<> : public virtual abstract_refc
9898
};
9999

100100
template<class Derived>
101-
class refcountable_php_classes : public ScriptAllocatorManaged {
101+
class refcountable_php_classes : public kphp::memory::script_allocator_managed {
102102
public:
103103
void add_ref() noexcept {
104104
if (refcnt < ExtraRefCnt::for_global_const) {

runtime-light/allocator/allocator.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
#include "runtime-common/core/allocator/script-allocator-managed.h"
1111
#include "runtime-light/allocator/allocator-state.h"
1212

13-
template<std::derived_from<ScriptAllocatorManaged> T, typename... Args>
13+
template<std::derived_from<kphp::memory::script_allocator_managed> T, typename... Args>
1414
requires std::constructible_from<T, Args...>
1515
auto make_unique_on_script_memory(Args&&... args) noexcept {
1616
return std::make_unique<T>(std::forward<Args>(args)...);

runtime-light/coroutine/detail/when-any.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#pragma once
66

7+
#include <concepts>
78
#include <cstddef>
89
#include <functional>
910
#include <optional>
@@ -249,12 +250,17 @@ class when_any_task {
249250
};
250251

251252
struct when_any_task_promise_void : public when_any_task_promise_common {
252-
auto yield_value() const noexcept {
253+
private:
254+
std::optional<kphp::coro::void_value> m_result;
255+
256+
public:
257+
auto yield_value(kphp::coro::void_value&& return_value) noexcept {
258+
m_result.emplace(return_value);
253259
return when_any_task_promise_common::final_suspend();
254260
}
255261

256-
constexpr auto result() const noexcept -> std::optional<kphp::coro::void_value> {
257-
return std::optional<kphp::coro::void_value>{std::in_place};
262+
auto result() noexcept -> std::optional<kphp::coro::void_value> {
263+
return m_result;
258264
}
259265

260266
constexpr auto return_void() const noexcept -> void {}
@@ -296,6 +302,7 @@ template<kphp::coro::concepts::awaitable awaitable_type>
296302
auto make_when_any_task(awaitable_type awaitable) noexcept -> when_any_task<typename kphp::coro::awaitable_traits<awaitable_type>::awaiter_return_type> {
297303
if constexpr (std::is_void_v<typename kphp::coro::awaitable_traits<awaitable_type>::awaiter_return_type>) {
298304
co_await std::move(awaitable);
305+
co_yield kphp::coro::void_value{};
299306
} else {
300307
co_yield co_await std::move(awaitable);
301308
}

runtime-light/coroutine/event.h

Lines changed: 63 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,32 +6,43 @@
66

77
#include <concepts>
88
#include <coroutine>
9+
#include <memory>
910
#include <utility>
1011

12+
#include "common/mixin/not_copyable.h"
13+
#include "runtime-common/core/allocator/script-allocator-managed.h"
1114
#include "runtime-light/coroutine/async-stack.h"
1215
#include "runtime-light/coroutine/coroutine-state.h"
1316
#include "runtime-light/stdlib/diagnostics/logs.h"
1417

1518
namespace kphp::coro {
1619

1720
class event {
18-
// 1) nullptr => not set
19-
// 2) awaiter* => linked list of awaiters waiting for the event to trigger
20-
// 3) this => The event is triggered and all awaiters are resumed
21-
void* m_state{};
21+
struct event_controller : kphp::memory::script_allocator_managed, vk::not_copyable {
22+
// 1) nullptr => not set
23+
// 2) awaiter* => linked list of awaiters waiting for the event to trigger
24+
// 3) this => The event is triggered and all awaiters are resumed
25+
void* m_state{};
26+
27+
auto set() noexcept -> void;
28+
auto unset() noexcept -> void;
29+
auto is_set() const noexcept -> bool;
30+
};
31+
32+
std::unique_ptr<event_controller> m_controller;
2233

2334
struct awaiter {
24-
event& m_event;
2535
bool m_suspended{};
36+
event_controller& m_controller;
2637
std::coroutine_handle<> m_awaiting_coroutine;
2738
kphp::coro::async_stack_root& m_async_stack_root;
2839
kphp::coro::async_stack_frame* m_caller_async_stack_frame{};
2940

3041
awaiter* m_next{};
3142
awaiter* m_prev{};
3243

33-
explicit awaiter(event& event) noexcept
34-
: m_event(event),
44+
explicit awaiter(event_controller& event_controller) noexcept
45+
: m_controller(event_controller),
3546
m_async_stack_root(CoroutineInstanceState::get().coroutine_stack_root) {}
3647

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

5768
public:
58-
auto set() noexcept -> void;
69+
event() noexcept
70+
: m_controller(std::make_unique<event_controller>()) {
71+
kphp::log::assertion(m_controller != nullptr);
72+
}
5973

60-
auto unset() noexcept -> void;
74+
event(event&& other) noexcept
75+
: m_controller(std::move(other.m_controller)) {}
76+
77+
event& operator=(event&& other) noexcept {
78+
if (this != std::addressof(other)) {
79+
m_controller = std::move(other.m_controller);
80+
}
81+
return *this;
82+
}
83+
84+
~event() = default;
6185

86+
event(const event&) = delete;
87+
event& operator=(const event&) = delete;
88+
89+
auto set() noexcept -> void;
90+
auto unset() noexcept -> void;
6291
auto is_set() const noexcept -> bool;
6392

6493
auto operator co_await() noexcept;
@@ -72,14 +101,14 @@ inline auto event::awaiter::cancel_awaiter() noexcept -> void {
72101
m_prev->m_next = m_next;
73102
} else {
74103
// we are the head of the awaiters list, so we need to update the head
75-
m_event.m_state = m_next;
104+
m_controller.m_state = m_next;
76105
}
77106
m_next = nullptr;
78107
m_prev = nullptr;
79108
}
80109

81110
inline auto event::awaiter::await_ready() const noexcept -> bool {
82-
return m_event.is_set();
111+
return m_controller.is_set();
83112
}
84113

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

93-
m_next = static_cast<event::awaiter*>(m_event.m_state);
122+
m_next = static_cast<event::awaiter*>(m_controller.m_state);
94123

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

98127
if (m_next != nullptr) {
99128
m_next->m_prev = this;
100129
}
101-
m_event.m_state = this;
130+
m_controller.m_state = this;
102131
}
103132

104133
inline auto event::awaiter::await_resume() noexcept -> void {
@@ -109,7 +138,7 @@ inline auto event::awaiter::await_resume() noexcept -> void {
109138
}
110139
}
111140

112-
inline auto event::set() noexcept -> void {
141+
inline auto event::event_controller::set() noexcept -> void {
113142
void* prev_value{std::exchange(m_state, this)};
114143
if (prev_value == this || prev_value == nullptr) [[unlikely]] {
115144
return;
@@ -122,18 +151,34 @@ inline auto event::set() noexcept -> void {
122151
}
123152
}
124153

125-
inline auto event::unset() noexcept -> void {
154+
inline auto event::event_controller::unset() noexcept -> void {
126155
if (m_state == this) {
127156
m_state = nullptr;
128157
}
129158
}
130159

131-
inline auto event::is_set() const noexcept -> bool {
160+
inline auto event::event_controller::is_set() const noexcept -> bool {
132161
return m_state == this;
133162
}
134163

164+
inline auto event::set() noexcept -> void {
165+
kphp::log::assertion(m_controller != nullptr);
166+
m_controller->set();
167+
}
168+
169+
inline auto event::unset() noexcept -> void {
170+
kphp::log::assertion(m_controller != nullptr);
171+
m_controller->unset();
172+
}
173+
174+
inline auto event::is_set() const noexcept -> bool {
175+
kphp::log::assertion(m_controller != nullptr);
176+
return m_controller->is_set();
177+
}
178+
135179
inline auto event::operator co_await() noexcept {
136-
return event::awaiter{*this};
180+
kphp::log::assertion(m_controller != nullptr);
181+
return event::awaiter{*this->m_controller};
137182
}
138183

139184
} // namespace kphp::coro

runtime-light/k2-platform/k2-api.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ inline constexpr size_t DEFAULT_MEMORY_ALIGN = 16;
3636
} // namespace k2_impl_
3737

3838
inline constexpr int32_t errno_ok = 0;
39+
inline constexpr int32_t errno_ebusy = EBUSY;
3940
inline constexpr int32_t errno_enodev = ENODEV;
4041
inline constexpr int32_t errno_einval = EINVAL;
4142
inline constexpr int32_t errno_enodata = ENODATA;
@@ -46,6 +47,9 @@ inline constexpr int32_t errno_eshutdown = ESHUTDOWN;
4647
inline constexpr int32_t errno_ecanceled = ECANCELED;
4748
inline constexpr int32_t errno_erange = ERANGE;
4849
inline constexpr int32_t errno_enoent = ENOENT;
50+
inline constexpr int32_t errno_eopnotsupp = EOPNOTSUPP;
51+
inline constexpr int32_t errno_ealready = EALREADY;
52+
inline constexpr int32_t errno_einprogress = EINPROGRESS;
4953

5054
using descriptor = uint64_t;
5155
inline constexpr k2::descriptor INVALID_PLATFORM_DESCRIPTOR = 0;

runtime-light/server/http/http-server-state.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,14 @@
99
#include <locale>
1010
#include <optional>
1111
#include <string_view>
12+
#include <utility>
1213

1314
#include "common/mixin/not_copyable.h"
1415
#include "runtime-common/core/allocator/script-allocator.h"
1516
#include "runtime-common/core/runtime-core.h"
1617
#include "runtime-common/core/std/containers.h"
1718
#include "runtime-light/coroutine/task.h"
18-
#include "runtime-light/streams/stream.h"
19+
#include "runtime-light/streams/connection.h"
1920

2021
namespace kphp::http {
2122

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

60-
std::optional<kphp::component::stream> request_stream;
61+
std::optional<kphp::component::connection> connection;
6162

6263
std::optional<string> opt_raw_post_data;
6364

0 commit comments

Comments
 (0)