Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[k2] implement php_uname & posix_getpid #1184

Merged
merged 3 commits into from
Dec 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 0 additions & 2 deletions builtin-functions/kphp-light/file.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@ function is_readable ($name ::: string) ::: bool;
/** @kphp-extern-func-info generate-stub */
function mkdir ($name ::: string, $mode ::: int = 0777, $recursive ::: bool = false) ::: bool;
/** @kphp-extern-func-info generate-stub */
function php_uname ($mode ::: string = "a") ::: string;
/** @kphp-extern-func-info generate-stub */
function realpath ($path ::: string) ::: string | false;
/** @kphp-extern-func-info generate-stub */
function rename ($oldname ::: string, $newname ::: string) ::: bool;
Expand Down
1 change: 1 addition & 0 deletions builtin-functions/kphp-light/functions.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ require_once __DIR__ . '/rpc.txt';
require_once __DIR__ . '/serialize.txt';
require_once __DIR__ . '/string.txt';
require_once __DIR__ . '/server.txt';
require_once __DIR__ . '/system.txt';
require_once __DIR__ . '/kphp-toggles.txt';
require_once __DIR__ . '/kphp_internal.txt';
require_once __DIR__ . '/math.txt';
Expand Down
5 changes: 5 additions & 0 deletions builtin-functions/kphp-light/system.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?php

function php_uname($mode ::: string = "a"): string;

function posix_getpid(): int;
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,6 @@ function memory_get_static_usage() ::: int;
/** @kphp-extern-func-info generate-stub */
function memory_get_detailed_stats() ::: int[];

/** @kphp-extern-func-info generate-stub */
function posix_getpid() ::: int;
/** @kphp-extern-func-info generate-stub */
function posix_getuid() ::: int;
/** @kphp-extern-func-info generate-stub */
Expand Down
9 changes: 9 additions & 0 deletions runtime-light/k2-platform/k2-api.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <cstddef>
#include <cstdint>
#include <memory>
#include <sys/utsname.h>
#include <utility>

#define K2_API_HEADER_H
Expand Down Expand Up @@ -85,6 +86,14 @@ inline void free_checked(void *ptr, size_t size, size_t align) noexcept {
k2_exit(exit_code);
}

inline uint32_t getpid() noexcept {
return k2_getpid();
}

inline int32_t uname(struct utsname *addr) noexcept {
return k2_uname(addr);
}

inline int32_t open(uint64_t *stream_d, size_t name_len, const char *name) noexcept {
return k2_open(stream_d, name_len, name);
}
Expand Down
42 changes: 28 additions & 14 deletions runtime-light/k2-platform/k2-header.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#endif // K2_API_HEADER_H

#include <sys/socket.h>
#include <sys/utsname.h>

#ifdef __cplusplus
#include <atomic>
Expand Down Expand Up @@ -149,6 +150,19 @@ void k2_free_checked(void *ptr, size_t size, size_t align);
*/
[[noreturn]] void k2_exit(int32_t exit_code);

/**
* 'k2_getpid' returns the process ID (PID) of the calling process.
*/
uint32_t k2_getpid();

/**
* Semantically equivalent to libc's 'uname' function.
*
* Possible 'errno':
* 'EFAULT' => buf is not valid
*/
int32_t k2_uname(struct utsname *buf);

/**
* @return return `0` on success. libc-like `errno` otherwise
* `stream_d` will be assigned new descriptor on success.
Expand Down Expand Up @@ -326,13 +340,13 @@ int32_t k2_connect(uint64_t socket_d, const struct sockaddr_storage *addr, size_
* Perform sequentially `k2_lookup_host` -> `k2_socket` -> `k2_connect`
* @return: `0` on success, `errno != 0` otherwise
*/
int32_t k2_udp_connect(uint64_t *socket_d, const char *host, size_t host_len);
int32_t k2_udp_connect(uint64_t *socket_d, const char *hostport, size_t hostport_len);

/**
* Perform sequentially `k2_lookup_host` -> `k2_socket` -> `k2_connect`
* @return: `0` on success, `errno != 0` otherwise
*/
int32_t k2_tcp_connect(uint64_t *socket_d, const char *host, size_t host_len);
int32_t k2_tcp_connect(uint64_t *socket_d, const char *hostport, size_t hostport_len);

struct SockAddr {
uint16_t is_v6;
Expand All @@ -343,28 +357,28 @@ struct SockAddr {
};

/**
* Optimistically tries to parse `host` as `ip` + `port`.
* Optimistically tries to parse `hostport` as `ip` + `port`.
* Examples:
* IpV4 `host` format: `"123.123.123.123:8080"`.
* IpV6 `host` format: `"[2001:db8::1]:8080"`.
* IpV4 `hostport` format: `"123.123.123.123:8080"`.
* IpV6 `hostport` format: `"[2001:db8::1]:8080"`.
*
* Then performs a DNS resolution with `man 3 getaddrinfo` (implementation depends on the host machine settings).
* Examples:
* `host = "localhost:8080"`
* `host = "vk.com:443"`
* `hostport = "localhost:8080"`
* `hostport = "vk.com:443"`
*
*
* Although the function signature is synchronous DNS resolution may perform file reading and networking.
* k2-node will attempt to do this work in the background, but the component execution and associated work will be suspended.
* Thus, this is an expensive operation that should have an asynchronous signature, but it does not.
*
* @param `host` should be valid utf-8.
* @param `hostport` should be valid utf-8.
* @return: `0` on success, `errno != 0` otherwise
* on success:
* `result_buf_len` is set to the number of resolved addresses. `0 <= result_buf_len <= min(result_buf_len, 128)`.
* the first `result_buf_len` items of `result_buf` will be filled with resolved addresses
*/
int32_t k2_lookup_host(const char *host, size_t host_len, struct SockAddr *result_buf, size_t *result_buf_len);
int32_t k2_lookup_host(const char *hostport, size_t hostport_len, struct SockAddr *result_buf, size_t *result_buf_len);

/**
* Only available during `k2_create_component` call. Returns `0` in other context.
Expand All @@ -374,22 +388,22 @@ int32_t k2_lookup_host(const char *host, size_t host_len, struct SockAddr *resul
uint32_t k2_args_count();

/**
* @param `arg_num` must satisfy `0 <= arg_num <= k2_args_count()`
* @param `arg_num` must satisfy `0 <= arg_num < k2_args_count()`
* @return length of argument key with number `arg_num` in bytes
*/
uint32_t k2_args_key_len(uint32_t arg_num);

/**
* @param `arg_num` must satisfy `0 <= arg_num <= k2_args_count()`
* @param `arg_num` must satisfy `0 <= arg_num < k2_args_count()`
* @return length of argumen value with number `arg_num` in bytes
*/
uint32_t k2_args_value_len(uint32_t arg_num);

/**
* Note: key and value are **not** null-terminated.
* @param `arg_num` must satisfy `0 <= arg_num <= k2_args_count()`
* @param `key` buffer where key will be written, buffer len must staisfy `0 <= len <= k2_args_key_len(arg_num)`
* @param `value` buffer where value will be written, buffer len must staisfy `0 <= len <= k2_args_value_len(arg_num)`
* @param `arg_num` must satisfy `0 <= arg_num < k2_args_count()`
* @param `key` buffer where key will be written, buffer len must staisfy `len >= k2_args_key_len(arg_num)`
* @param `value` buffer where value will be written, buffer len must staisfy `len >= k2_args_value_len(arg_num)`
*/
void k2_args_fetch(uint32_t arg_num, char *key, char *value);

Expand Down
49 changes: 46 additions & 3 deletions runtime-light/state/image-state.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,15 @@
#pragma once

#include <cstddef>
#include <cstdint>
#include <memory>
#include <sys/utsname.h>

#include "common/mixin/not_copyable.h"
#include "common/php-functions.h"
#include "runtime-common/core/allocator/runtime-allocator.h"
#include "runtime-common/core/runtime-core.h"
#include "runtime-common/core/utils/kphp-assert-core.h"
#include "runtime-light/k2-platform/k2-api.h"
#include "runtime-light/stdlib/rpc/rpc-state.h"
#include "runtime-light/stdlib/string/string-state.h"
Expand All @@ -16,11 +22,48 @@ struct ImageState final : private vk::not_copyable {
RuntimeAllocator allocator;

char *c_linear_mem{nullptr};
RpcImageState rpc_image_state{};
StringImageState string_image_state{};
uint32_t pid{};
string uname_info_s;
string uname_info_n;
string uname_info_r;
string uname_info_v;
string uname_info_m;
string uname_info_a;

RpcImageState rpc_image_state;
StringImageState string_image_state;

ImageState() noexcept
: allocator(INIT_IMAGE_ALLOCATOR_SIZE, 0) {}
: allocator(INIT_IMAGE_ALLOCATOR_SIZE, 0)
, pid(k2::getpid()) {
utsname uname_info{};
if (const auto err{k2::uname(std::addressof(uname_info))}; err != k2::errno_ok) [[unlikely]] {
php_error("can't get uname, error '%d'", err);
}
uname_info_s = string{uname_info.sysname};
uname_info_n = string{uname_info.nodename};
uname_info_r = string{uname_info.release};
uname_info_v = string{uname_info.version};
uname_info_m = string{uname_info.machine};
// +4 for whitespaces
uname_info_a.reserve_at_least(uname_info_s.size() + uname_info_n.size() + uname_info_r.size() + uname_info_v.size() + uname_info_m.size() + 4);
uname_info_a.append(uname_info_s);
uname_info_a.push_back(' ');
uname_info_a.append(uname_info_n);
uname_info_a.push_back(' ');
uname_info_a.append(uname_info_r);
uname_info_a.push_back(' ');
uname_info_a.append(uname_info_v);
uname_info_a.push_back(' ');
uname_info_a.append(uname_info_m);
// prevent race condition on reference counter
uname_info_s.set_reference_counter_to(ExtraRefCnt::for_global_const);
uname_info_n.set_reference_counter_to(ExtraRefCnt::for_global_const);
uname_info_r.set_reference_counter_to(ExtraRefCnt::for_global_const);
uname_info_v.set_reference_counter_to(ExtraRefCnt::for_global_const);
uname_info_m.set_reference_counter_to(ExtraRefCnt::for_global_const);
uname_info_a.set_reference_counter_to(ExtraRefCnt::for_global_const);
}

static const ImageState &get() noexcept {
return *k2::image_state();
Expand Down
41 changes: 34 additions & 7 deletions runtime-light/stdlib/system/system-functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,39 @@

#pragma once

#include <cstdint>

#include "runtime-common/core/runtime-core.h"
#include "runtime-common/core/utils/kphp-assert-core.h"
#include "runtime-light/state/image-state.h"
#include "runtime-light/stdlib/system/system-state.h"

template<typename T>
int64_t f$estimate_memory_usage(const T &) {
int64_t f$estimate_memory_usage(const T & /*unused*/) {
php_critical_error("call to unsupported function");
}

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

template<typename F>
bool f$register_kphp_on_oom_callback(F &&callback) {
bool f$register_kphp_on_oom_callback(F && /*callback*/) {
php_critical_error("call to unsupported function");
}

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

inline int64_t f$system(const string &command, int64_t &result_code = SystemInstanceState::get().result_code_dummy) {
inline int64_t f$system(const string & /*command*/, int64_t & /*result_code*/ = SystemInstanceState::get().result_code_dummy) {
php_critical_error("call to unsupported function");
}

inline Optional<array<mixed>> f$getopt(const string &options, array<string> longopts = {},
Optional<int64_t> &rest_index = SystemInstanceState::get().rest_index_dummy) {
inline Optional<array<mixed>> f$getopt(const string & /*options*/, const array<string> & /*longopts*/ = {},
Optional<int64_t> & /*rest_index*/ = SystemInstanceState::get().rest_index_dummy) {
php_critical_error("call to unsupported function");
}

Expand All @@ -42,3 +46,26 @@ inline int64_t f$numa_get_bound_node() noexcept {

inline void f$kphp_set_context_on_error([[maybe_unused]] const array<mixed> &tags, [[maybe_unused]] const array<mixed> &extra_info,
[[maybe_unused]] const string &env = {}) noexcept {}

inline int64_t f$posix_getpid() noexcept {
return static_cast<int64_t>(ImageState::get().pid);
}

inline string f$php_uname(const string &mode = string{1, 'a'}) noexcept {
const auto &image_st{ImageState::get()};
const char mode_c{mode.empty() ? 'a' : mode[0]};
switch (mode_c) {
case 's':
return image_st.uname_info_s;
case 'n':
return image_st.uname_info_n;
case 'r':
return image_st.uname_info_r;
case 'v':
return image_st.uname_info_v;
case 'm':
return image_st.uname_info_m;
default:
return image_st.uname_info_a;
}
}
Loading