Skip to content

Commit

Permalink
[k2] implement php_uname & posix_getpid (#1184)
Browse files Browse the repository at this point in the history
  • Loading branch information
apolyakov authored Dec 12, 2024
1 parent 02cdacf commit ed08ea6
Show file tree
Hide file tree
Showing 8 changed files with 123 additions and 28 deletions.
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;
}
}

0 comments on commit ed08ea6

Please sign in to comment.