diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml index ac19aeb8c7..10558ae2b0 100644 --- a/.github/workflows/Build.yml +++ b/.github/workflows/Build.yml @@ -14,12 +14,24 @@ env: jobs: clang-format: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v3 - - name: Install clang-format - run: wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - && \ - apt-get update && apt-get install clang-format-18 + - name: Add LLVM GPG key + run: | + sudo wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | gpg --dearmor -o /etc/apt/trusted.gpg.d/llvm.gpg + shell: bash + + - name: Add LLVM repository + run: | + echo "deb [signed-by=/etc/apt/trusted.gpg.d/llvm.gpg] http://apt.llvm.org/jammy/ llvm-toolchain-jammy-17 main" | sudo tee /etc/apt/sources.list.d/llvm.list + shell: bash + + - name: Update and Install LLVM + run: | + sudo apt update + sudo apt install -y clang-format-18 + shell: bash - name: debug run: which clang-format-18 - name: Run clang-format diff --git a/common/dl-utils-lite.cpp b/common/dl-utils-lite.cpp index 8648274d6c..8315eaa5b2 100644 --- a/common/dl-utils-lite.cpp +++ b/common/dl-utils-lite.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include "common/server/crash-dump.h" #include "common/stats/provider.h" @@ -49,9 +50,9 @@ double dl_time() { } void dl_print_backtrace(void **trace, int trace_size) { - write (2, "\n------- Stack Backtrace -------\n", 33); + std::ignore = write (2, "\n------- Stack Backtrace -------\n", 33); backtrace_symbols_fd (trace, trace_size, 2); - write (2, "-------------------------------\n", 32); + std::ignore = write (2, "-------------------------------\n", 32); } void dl_print_backtrace() { @@ -71,7 +72,7 @@ void dl_print_backtrace_gdb() { name_buf[res] = 0; int child_pid = fork(); if (child_pid < 0) { - write (2, "Can't fork() to run gdb\n", 24); + std::ignore = write (2, "Can't fork() to run gdb\n", 24); _exit (0); } if (!child_pid) { @@ -83,7 +84,7 @@ void dl_print_backtrace_gdb() { waitpid (child_pid, nullptr, 0); } } else { - write (2, "can't get name of executable file to pass to gdb\n", 49); + std::ignore = write (2, "can't get name of executable file to pass to gdb\n", 49); } } diff --git a/runtime-light/header.h b/runtime-light/header.h index 5bae9daf93..d513554a0f 100644 --- a/runtime-light/header.h +++ b/runtime-light/header.h @@ -107,8 +107,7 @@ struct PlatformCtx { * `stream_d` will be assigned `0`. * however `stream_d=0` itself is not an error marker */ - enum OpenStreamResult (*open)(size_t name_len, const char *name, - uint64_t *stream_d); + enum OpenStreamResult (*open)(size_t name_len, const char *name, uint64_t *stream_d); /* * If the write or read status is `Blocked` - then the platform ensures that * the component receives this `stream_d` via `take_update` when the status is @@ -118,8 +117,7 @@ struct PlatformCtx { * `new_status` will be assigned as * `{.read_status = 0, .write_status = 0, .please_shutdown = 0}`. */ - enum GetStatusResult (*get_stream_status)(uint64_t stream_d, - struct StreamStatus *new_status); + enum GetStatusResult (*get_stream_status)(uint64_t stream_d, struct StreamStatus *new_status); /* * Return processed bytes (written or read). * Guaranteed to return `0` if the stream is `Closed`, `Blocked` or @@ -190,8 +188,7 @@ struct PlatformCtx { * * `deadline` will be assigned `0` if `timer_d` invalid */ - enum TimerStatus (*get_timer_status)(uint64_t timer_d, - struct TimePoint *deadline); + enum TimerStatus (*get_timer_status)(uint64_t timer_d, struct TimePoint *deadline); /* * Return: `bool`. * If `True`: the update was successfully received. @@ -262,15 +259,11 @@ struct ImageInfo { }; // Every image should provide these symbols -enum PollStatus vk_k2_poll(const struct ImageState *image_state, - const struct PlatformCtx *pt_ctx, - struct ComponentState *component_ctx); +enum PollStatus vk_k2_poll(const struct ImageState *image_state, const struct PlatformCtx *pt_ctx, struct ComponentState *component_ctx); // platform_ctx without IO stuff (nullptr instead io-functions) // for now, returning nullptr will indicate error -struct ComponentState * -vk_k2_create_component_state(const struct ImageState *image_state, - const struct PlatformCtx *pt_ctx); +struct ComponentState *vk_k2_create_component_state(const struct ImageState *image_state, const struct PlatformCtx *pt_ctx); // platform_ctx without IO stuff (nullptr instead io-functions) // for now, returning nullptr will indicate error diff --git a/runtime-light/stdlib/rpc/rpc-buffer.h b/runtime-light/stdlib/rpc/rpc-buffer.h index 3d8f0b0f3e..64bb74ea0b 100644 --- a/runtime-light/stdlib/rpc/rpc-buffer.h +++ b/runtime-light/stdlib/rpc/rpc-buffer.h @@ -43,7 +43,7 @@ class RpcBuffer : private vk::not_copyable { } void reset(size_t pos) noexcept { - php_assert(pos >= 0 && pos <= size()); + php_assert(pos > 0 && pos <= size()); m_pos = pos; m_remaining = size() - m_pos; } diff --git a/runtime-light/utils/concepts.h b/runtime-light/utils/concepts.h index 4969436e7d..963a9c6b95 100644 --- a/runtime-light/utils/concepts.h +++ b/runtime-light/utils/concepts.h @@ -5,13 +5,6 @@ #pragma once #include -#include -#include template concept standard_layout = std::is_standard_layout_v; - -template -concept hashable = requires(T a) { - { std::hash{}(a) } -> std::convertible_to; -}; diff --git a/runtime-light/utils/json-functions.cpp b/runtime-light/utils/json-functions.cpp index 5fde8e0723..58d88c05a2 100644 --- a/runtime-light/utils/json-functions.cpp +++ b/runtime-light/utils/json-functions.cpp @@ -7,13 +7,13 @@ #include "common/algorithms/find.h" #include "runtime-light/component/component.h" // -//#include "runtime/string_functions.h" +// #include "runtime/string_functions.h" // note: json-functions.cpp is used for non-typed json implementation: for json_encode() and json_decode() // for classes, e.g. `JsonEncoder::encode(new A)`, see json-writer.cpp and from/to visitors namespace { -void json_append_one_char(unsigned int c, string_buffer & sb) noexcept { +void json_append_one_char(unsigned int c, string_buffer &sb) noexcept { sb.append_char('\\'); sb.append_char('u'); sb.append_char("0123456789abcdef"[c >> 12]); @@ -22,7 +22,7 @@ void json_append_one_char(unsigned int c, string_buffer & sb) noexcept { sb.append_char("0123456789abcdef"[c & 15]); } -bool json_append_char(unsigned int c, string_buffer & sb) noexcept { +bool json_append_char(unsigned int c, string_buffer &sb) noexcept { if (c < 0x10000) { if (0xD7FF < c && c < 0xE000) { return false; @@ -39,8 +39,7 @@ bool json_append_char(unsigned int c, string_buffer & sb) noexcept { return false; } - -bool do_json_encode_string_php(const JsonPath &json_path, const char *s, int len, int64_t options, string_buffer & sb) noexcept { +bool do_json_encode_string_php(const JsonPath &json_path, const char *s, int len, int64_t options, string_buffer &sb) noexcept { int begin_pos = sb.size(); if (options & JSON_UNESCAPED_UNICODE) { sb.reserve(2 * len + 2); @@ -178,7 +177,7 @@ string JsonPath::to_string() const { } unsigned num_parts = std::clamp(depth, 0U, static_cast(arr.size())); string result; - result.reserve_at_least((num_parts+1) * 8); + result.reserve_at_least((num_parts + 1) * 8); result.push_back('/'); for (unsigned i = 0; i < num_parts; i++) { const char *key = arr[i]; @@ -200,13 +199,12 @@ string JsonPath::to_string() const { namespace impl_ { -JsonEncoder::JsonEncoder(int64_t options, bool simple_encode, const char *json_obj_magic_key) noexcept: - options_(options), - simple_encode_(simple_encode), - json_obj_magic_key_(json_obj_magic_key) { -} +JsonEncoder::JsonEncoder(int64_t options, bool simple_encode, const char *json_obj_magic_key) noexcept + : options_(options) + , simple_encode_(simple_encode) + , json_obj_magic_key_(json_obj_magic_key) {} -bool JsonEncoder::encode(bool b, string_buffer & sb) noexcept { +bool JsonEncoder::encode(bool b, string_buffer &sb) noexcept { if (b) { sb.append("true", 4); } else { @@ -215,17 +213,17 @@ bool JsonEncoder::encode(bool b, string_buffer & sb) noexcept { return true; } -bool JsonEncoder::encode_null(string_buffer & sb) const noexcept { +bool JsonEncoder::encode_null(string_buffer &sb) const noexcept { sb.append("null", 4); return true; } -bool JsonEncoder::encode(int64_t i, string_buffer & sb) noexcept { +bool JsonEncoder::encode(int64_t i, string_buffer &sb) noexcept { sb << i; return true; } -bool JsonEncoder::encode(double d, string_buffer & sb) noexcept { +bool JsonEncoder::encode(double d, string_buffer &sb) noexcept { if (vk::any_of_equal(std::fpclassify(d), FP_INFINITE, FP_NAN)) { php_warning("%s: strange double %lf in function json_encode", json_path_.to_string().c_str(), d); if (options_ & JSON_PARTIAL_OUTPUT_ON_ERROR) { @@ -234,17 +232,17 @@ bool JsonEncoder::encode(double d, string_buffer & sb) noexcept { return false; } } else { - //todo:k2 implement f$number_format - sb << /*(simple_encode_ ? f$number_format(d, 6, string{"."}, string{}) : */ string{d}/*)*/; + // todo:k2 implement f$number_format + sb << /*(simple_encode_ ? f$number_format(d, 6, string{"."}, string{}) : */ string{d} /*)*/; } return true; } -bool JsonEncoder::encode(const string &s, string_buffer & sb) noexcept { +bool JsonEncoder::encode(const string &s, string_buffer &sb) noexcept { return do_json_encode_string_php(json_path_, s.c_str(), s.size(), options_, sb); } -bool JsonEncoder::encode(const mixed &v, string_buffer & sb) noexcept { +bool JsonEncoder::encode(const mixed &v, string_buffer &sb) noexcept { switch (v.get_type()) { case mixed::type::NUL: return encode_null(sb); @@ -280,29 +278,22 @@ bool do_json_decode(const char *s, int s_len, int &i, mixed &v, const char *json json_skip_blanks(s, i); switch (s[i]) { case 'n': - if (s[i + 1] == 'u' && - s[i + 2] == 'l' && - s[i + 3] == 'l') { + if (s[i + 1] == 'u' && s[i + 2] == 'l' && s[i + 3] == 'l') { i += 4; return true; } break; case 't': - if (s[i + 1] == 'r' && - s[i + 2] == 'u' && - s[i + 3] == 'e') { + if (s[i + 1] == 'r' && s[i + 2] == 'u' && s[i + 3] == 'e') { i += 4; - new(&v) mixed(true); + new (&v) mixed(true); return true; } break; case 'f': - if (s[i + 1] == 'a' && - s[i + 2] == 'l' && - s[i + 3] == 's' && - s[i + 4] == 'e') { + if (s[i + 1] == 'a' && s[i + 2] == 'l' && s[i + 3] == 's' && s[i + 4] == 'e') { i += 5; - new(&v) mixed(false); + new (&v) mixed(false); return true; } break; @@ -364,8 +355,7 @@ bool do_json_decode(const char *s, int s_len, int &i, mixed &v, const char *json } if (0xD7FF < num && num < 0xE000) { - if (s[i + 1] == '\\' && s[i + 2] == 'u' && - isxdigit(s[i + 3]) && isxdigit(s[i + 4]) && isxdigit(s[i + 5]) && isxdigit(s[i + 6])) { + if (s[i + 1] == '\\' && s[i + 2] == 'u' && isxdigit(s[i + 3]) && isxdigit(s[i + 4]) && isxdigit(s[i + 5]) && isxdigit(s[i + 6])) { i += 2; int u = 0; for (int t = 0; t < 4; t++) { @@ -419,7 +409,7 @@ bool do_json_decode(const char *s, int s_len, int &i, mixed &v, const char *json } value.shrink(l); - new(&v) mixed(value); + new (&v) mixed(value); i++; return true; } @@ -446,7 +436,7 @@ bool do_json_decode(const char *s, int s_len, int &i, mixed &v, const char *json i++; } - new(&v) mixed(res); + new (&v) mixed(res); return true; } case '{': { @@ -483,7 +473,7 @@ bool do_json_decode(const char *s, int s_len, int &i, mixed &v, const char *json res[string{json_obj_magic_key}] = true; } - new(&v) mixed(res); + new (&v) mixed(res); return true; } default: { @@ -495,7 +485,7 @@ bool do_json_decode(const char *s, int s_len, int &i, mixed &v, const char *json int64_t intval = 0; if (php_try_to_int(s + i, j - i, &intval)) { i = j; - new(&v) mixed(intval); + new (&v) mixed(intval); return true; } @@ -503,7 +493,7 @@ bool do_json_decode(const char *s, int s_len, int &i, mixed &v, const char *json double floatval = strtod(s + i, &end_ptr); if (end_ptr == s + j) { i = j; - new(&v) mixed(floatval); + new (&v) mixed(floatval); return true; } } diff --git a/runtime-light/utils/json-functions.h b/runtime-light/utils/json-functions.h index 15626a7e23..7805da79d9 100644 --- a/runtime-light/utils/json-functions.h +++ b/runtime-light/utils/json-functions.h @@ -9,7 +9,6 @@ #include "common/mixin/not_copyable.h" #include "runtime-core/runtime-core.h" - constexpr int64_t JSON_UNESCAPED_UNICODE = 1; constexpr int64_t JSON_FORCE_OBJECT = 16; constexpr int64_t JSON_PRETTY_PRINT = 128; // TODO: add actual support to untyped @@ -22,7 +21,7 @@ constexpr int64_t JSON_AVAILABLE_FLAGS_TYPED = JSON_PRETTY_PRINT | JSON_PRESERVE struct JsonPath { constexpr static int MAX_DEPTH = 8; - std::array arr; + std::array arr; unsigned depth = 0; void enter(const char *key) noexcept { @@ -47,31 +46,31 @@ class JsonEncoder : vk::not_copyable { public: JsonEncoder(int64_t options, bool simple_encode, const char *json_obj_magic_key = nullptr) noexcept; - //todo:k2 change static_SB everywhere to string_buffer arg - bool encode(bool b, string_buffer & sb) noexcept; - bool encode(int64_t i, string_buffer & sb) noexcept; - bool encode(const string &s, string_buffer & sb) noexcept; - bool encode(double d, string_buffer & sb) noexcept; - bool encode(const mixed &v, string_buffer & sb) noexcept; + // todo:k2 change static_SB everywhere to string_buffer arg + bool encode(bool b, string_buffer &sb) noexcept; + bool encode(int64_t i, string_buffer &sb) noexcept; + bool encode(const string &s, string_buffer &sb) noexcept; + bool encode(double d, string_buffer &sb) noexcept; + bool encode(const mixed &v, string_buffer &sb) noexcept; template - bool encode(const array &arr, string_buffer & sb) noexcept; + bool encode(const array &arr, string_buffer &sb) noexcept; template - bool encode(const Optional &opt, string_buffer & sb) noexcept; + bool encode(const Optional &opt, string_buffer &sb) noexcept; private: - bool encode_null(string_buffer & sb) const noexcept; + bool encode_null(string_buffer &sb) const noexcept; JsonPath json_path_; const int64_t options_{0}; - //todo:k2 use simple_encode + // todo:k2 use simple_encode [[maybe_unused]] const bool simple_encode_{false}; const char *json_obj_magic_key_{nullptr}; }; template -bool JsonEncoder::encode(const array &arr, string_buffer & sb) noexcept { +bool JsonEncoder::encode(const array &arr, string_buffer &sb) noexcept { bool is_vector = arr.is_vector(); const bool force_object = static_cast(JSON_FORCE_OBJECT & options_); if (!force_object && !is_vector && arr.is_pseudo_vector()) { @@ -142,7 +141,7 @@ bool JsonEncoder::encode(const array &arr, string_buffer & sb) noexcept { } template -bool JsonEncoder::encode(const Optional &opt, string_buffer & sb) noexcept { +bool JsonEncoder::encode(const Optional &opt, string_buffer &sb) noexcept { switch (opt.value_state()) { case OptionalState::has_value: return encode(opt.val(), sb); @@ -170,7 +169,7 @@ Optional f$json_encode(const T &v, int64_t options = 0, bool simple_enco return sb.c_str(); } -//todo:k2 implement string f$vk_json_encode_safe(const T &v, bool simple_encode = true) noexcept +// todo:k2 implement string f$vk_json_encode_safe(const T &v, bool simple_encode = true) noexcept template inline Optional f$vk_json_encode(const T &v) noexcept { diff --git a/runtime-light/utils/panic.h b/runtime-light/utils/panic.h new file mode 100644 index 0000000000..7dfe5e956a --- /dev/null +++ b/runtime-light/utils/panic.h @@ -0,0 +1,24 @@ +// 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 "context.h" +#include "runtime-light/component/component.h" +#include "runtime-light/utils/logs.h" + +inline void critical_error_handler() { + constexpr const char *message = "script panic"; + const PlatformCtx &ptx = *get_platform_context(); + ComponentState &ctx = *get_component_context(); + ptx.log(Debug, strlen(message), message); + + if (ctx.not_finished()) { + ctx.poll_status = PollStatus::PollFinishedError; + } + ptx.abort(); + exit(1); +} diff --git a/runtime-light/utils/php_assert.cpp b/runtime-light/utils/php_assert.cpp index 190caca8d3..0d869406bd 100644 --- a/runtime-light/utils/php_assert.cpp +++ b/runtime-light/utils/php_assert.cpp @@ -2,6 +2,9 @@ // 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 @@ -13,10 +16,7 @@ #include #include -#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" +#include "runtime-light/utils/panic.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 new file mode 100644 index 0000000000..81d534e5dd --- /dev/null +++ b/runtime-light/utils/php_assert.h @@ -0,0 +1,13 @@ +// 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/mixin/not_copyable.h" +#include "common/wrappers/likely.h" + +#include "runtime-core/utils/kphp-assert-core.h" diff --git a/runtime-light/utils/timer.cpp b/runtime-light/utils/timer.cpp new file mode 100644 index 0000000000..3cb712012d --- /dev/null +++ b/runtime-light/utils/timer.cpp @@ -0,0 +1,21 @@ +// Compiler for PHP (aka KPHP) +// Copyright (c) 2024 LLC «V Kontakte» +// Distributed under the GPL v3 License, see LICENSE.notice.txt + +#include "runtime-light/utils/timer.h" + +void set_timer_impl(int64_t timeout_ms, on_timer_callback_t &&callback) { + const PlatformCtx &ptx = *get_platform_context(); + ComponentState &ctx = *get_component_context(); + uint64_t nanoseconds = static_cast(timeout_ms * 1e6); + uint64_t timer_d = 0; + SetTimerResult res = ptx.set_timer(&timer_d, nanoseconds); + if (res != SetTimerOk) { + php_warning("timer limit exceeded"); + return; + } + php_debug("set up timer %lu for %lu ms", timer_d, timeout_ms); + + ctx.opened_streams[timer_d] = StreamRuntimeStatus::Timer; + ctx.timer_callbacks[timer_d] = callback; +} \ No newline at end of file diff --git a/runtime-light/utils/timer.h b/runtime-light/utils/timer.h new file mode 100644 index 0000000000..e7ba0b5202 --- /dev/null +++ b/runtime-light/utils/timer.h @@ -0,0 +1,20 @@ +// 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 "runtime-core/memory-resource/resource_allocator.h" +#include "runtime-light/component/component.h" + +// todo:k2 std::function use heap +using on_timer_callback_t = std::function; + +void set_timer_impl(int64_t timeout_ms, on_timer_callback_t &&callback); + +template +void f$set_timer(int64_t timeout, CallBack &&callback) { + set_timer_impl(timeout, on_timer_callback_t(std::forward(callback))); +} \ No newline at end of file diff --git a/runtime-light/utils/to-array-processor.h b/runtime-light/utils/to-array-processor.h index 19ac809395..47ff7ec4a2 100644 --- a/runtime-light/utils/to-array-processor.h +++ b/runtime-light/utils/to-array-processor.h @@ -86,7 +86,7 @@ class ToArrayVisitor { add_value(field_name, instance.is_null() ? mixed{} : f$to_array_debug(instance, with_class_names_)); } - template + template void process_impl(const char *field_name, const std::tuple &value) { ToArrayVisitor tuple_processor{with_class_names_}; tuple_processor.result_.reserve(sizeof...(Args), true); @@ -95,7 +95,7 @@ class ToArrayVisitor { add_value(field_name, std::move(tuple_processor).flush_result()); } - template + template void process_impl(const char *field_name, const shape, T...> &value) { ToArrayVisitor shape_processor{with_class_names_}; shape_processor.result_.reserve(sizeof...(Is), true); diff --git a/runtime-light/utils/utils.cmake b/runtime-light/utils/utils.cmake index f74079da0d..2106bb3bb7 100644 --- a/runtime-light/utils/utils.cmake +++ b/runtime-light/utils/utils.cmake @@ -1 +1,5 @@ -prepend(RUNTIME_UTILS_SRC utils/ panic.cpp php_assert.cpp json-functions.cpp context.cpp) +prepend(RUNTIME_UTILS_SRC ${BASE_DIR}/runtime-light/utils/ + php_assert.cpp + json-functions.cpp + context.cpp + timer.cpp)