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

Removing the dependency on the libucontext library #892

Merged
merged 1 commit into from
Sep 21, 2023
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
8 changes: 7 additions & 1 deletion common/common.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,17 @@ prepend(COMMON_TL_METHODS_SOURCES ${COMMON_DIR}/tl/methods/
rwm.cpp
string.cpp)

if (APPLE AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64")
prepend(COMMON_UCONTEXT_SOURCES ${COMMON_DIR}/ucontext/
ucontext.cpp)
endif()

set(COMMON_ALL_SOURCES
${COMMON_MAIN_SOURCES}
${COMMON_KFS_SOURCES}
${COMMON_TL_METHODS_SOURCES}
${COMMON_TL_SOURCES})
${COMMON_TL_SOURCES}
${COMMON_UCONTEXT_SOURCES})

if(COMPILER_CLANG)
set_source_files_properties(${COMMON_DIR}/string-processing.cpp PROPERTIES COMPILE_FLAGS -Wno-invalid-source-encoding)
Expand Down
2 changes: 1 addition & 1 deletion common/server/crash-dump.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#include <unistd.h>

#include "common/kprintf.h"
#include "server/ucontext-portable.h"
#include "common/ucontext/ucontext-portable.h"

struct crash_dump_buffer {
char scratchpad[1024];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,9 @@

#else
// for M1, we can't use native makecontext() and others: they compile, but hang up when called
// instead, we require the ucontext library: https://github.com/kaniini/libucontext
// see the docs: https://vkcom.github.io/kphp/kphp-internals/developing-and-extending-kphp/compiling-kphp-from-sources.html
// here we expect, that libucontext include/ folder is copied into a default include path (to homebrew)
extern "C" {
#include <libucontext/libucontext.h>
}
#include "common/ucontext/ucontext.h"

#define ucontext_t_portable libucontext_ucontext_t
#define ucontext_t_portable libucontext_ucontext
#define setcontext_portable libucontext_setcontext
#define getcontext_portable libucontext_getcontext
#define makecontext_portable libucontext_makecontext
Expand Down
199 changes: 199 additions & 0 deletions common/ucontext/ucontext.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
// Compiler for PHP (aka KPHP)
// libucontext (c) https://github.com/kaniini/libucontext/tree/master (copied as third-party and slightly modified)
// Copyright (c) 2023 LLC «V Kontakte»
// Distributed under the GPL v3 License, see LICENSE.notice.txt

#include "common/ucontext/ucontext.h"

#include <cstdarg>
#include <cstdint>
#include <cstdio>
#include <cstdlib>

enum { SP_OFFSET = 432, PC_OFFSET = 440, PSTATE_OFFSET = 448, FPSIMD_CONTEXT_OFFSET = 464 };

#define R0_OFFSET REG_OFFSET(0)

#define REG_OFFSET(__reg) (MCONTEXT_GREGS + ((__reg)*REG_SZ))

#define REG_SZ (8)
#define MCONTEXT_GREGS (184)

_Static_assert(offsetof(libucontext_ucontext, uc_mcontext.regs[0]) == R0_OFFSET, "R0_OFFSET is invalid");
_Static_assert(offsetof(libucontext_ucontext, uc_mcontext.sp) == SP_OFFSET, "SP_OFFSET is invalid");
_Static_assert(offsetof(libucontext_ucontext, uc_mcontext.pc) == PC_OFFSET, "PC_OFFSET is invalid");
_Static_assert(offsetof(libucontext_ucontext, uc_mcontext.pstate) == PSTATE_OFFSET, "PSTATE_OFFSET is invalid");

__attribute__((visibility("hidden"))) void libucontext_trampoline() {
libucontext_ucontext *uc_link = nullptr;

asm("mov %0, x19" : "=r"((uc_link)));

if (uc_link == nullptr) {
exit(0);
}

libucontext_setcontext(uc_link);
}

void libucontext_makecontext(libucontext_ucontext *ucp, void (*func)(), int argc, ...) {
unsigned long *sp;
unsigned long *regp;
va_list va;
int i;

sp = reinterpret_cast<unsigned long *>(reinterpret_cast<uintptr_t>(ucp->uc_stack.ss_sp) + ucp->uc_stack.ss_size);
sp -= argc < 8 ? 0 : argc - 8;
sp = reinterpret_cast<unsigned long *>(((reinterpret_cast<uintptr_t>(sp) & -16L)));

ucp->uc_mcontext.sp = reinterpret_cast<uintptr_t>(sp);
ucp->uc_mcontext.pc = reinterpret_cast<uintptr_t>(func);
ucp->uc_mcontext.regs[19] = reinterpret_cast<uintptr_t>(ucp->uc_link);
ucp->uc_mcontext.regs[30] = reinterpret_cast<uintptr_t>(&libucontext_trampoline);

va_start(va, argc);

regp = &(ucp->uc_mcontext.regs[0]);

for (i = 0; (i < argc && i < 8); i++) {
*regp++ = va_arg(va, unsigned long);
}

for (; i < argc; i++) {
*sp++ = va_arg(va, unsigned long);
}

va_end(va);
}

asm(R"(
.global _libucontext_getcontext;
.align 2;
_libucontext_getcontext:
str xzr, [x0, #((184) + ((0) * (8)))] // #REG_OFFSET(0)
/* save GPRs */
stp x0, x1, [x0, #((184) + ((0) * (8)))] // REG_OFFSET(0)
stp x2, x3, [x0, #((184) + ((2) * (8)))] // REG_OFFSET(2)
stp x4, x5, [x0, #((184) + ((4) * (8)))] // REG_OFFSET(4)
stp x6, x7, [x0, #((184) + ((6) * (8)))] // REG_OFFSET(6)
stp x8, x9, [x0, #((184) + ((8) * (8)))] // REG_OFFSET(8)
stp x10, x11, [x0, #((184) + ((10) * (8)))] // REG_OFFSET(10)
stp x12, x13, [x0, #((184) + ((12) * (8)))] // REG_OFFSET(12)
stp x14, x15, [x0, #((184) + ((14) * (8)))] // REG_OFFSET(14)
stp x16, x17, [x0, #((184) + ((16) * (8)))] // REG_OFFSET(16)
stp x18, x19, [x0, #((184) + ((18) * (8)))] // REG_OFFSET(18)
stp x20, x21, [x0, #((184) + ((20) * (8)))] // REG_OFFSET(20)
stp x22, x23, [x0, #((184) + ((22) * (8)))] // REG_OFFSET(22)
stp x24, x25, [x0, #((184) + ((24) * (8)))] // REG_OFFSET(24)
stp x26, x27, [x0, #((184) + ((26) * (8)))] // REG_OFFSET(26)
stp x28, x29, [x0, #((184) + ((28) * (8)))] // REG_OFFSET(28)
str x30, [x0, #((184) + ((30) * (8)))] // REG_OFFSET(30)
/* save current program counter in link register */
str x30, [x0, #440] // PC_OFFSET
/* save current stack pointer */
mov x2, sp
str x2, [x0, #432] // SP_OFFSET
/* save pstate */
str xzr, [x0, #448] // PSTATE_OFFSET
add x2, x0, #464 // FPSIMD_CONTEXT_OFFSET
stp q8, q9, [x2, #144]
stp q10, q11, [x2, #176]
stp q12, q13, [x2, #208]
stp q14, q15, [x2, #240]
mov x0, #0
ret
)");

asm(R"(
.global _libucontext_setcontext;
.align 2;
_libucontext_setcontext:
/* restore GPRs */
ldp x18, x19, [x0, #((184) + ((18) * (8)))] // REG_OFFSET(18)
ldp x20, x21, [x0, #((184) + ((20) * (8)))] // REG_OFFSET(20)
ldp x22, x23, [x0, #((184) + ((22) * (8)))] // REG_OFFSET(22)
ldp x24, x25, [x0, #((184) + ((24) * (8)))] // REG_OFFSET(24)
ldp x26, x27, [x0, #((184) + ((26) * (8)))] // REG_OFFSET(26)
ldp x28, x29, [x0, #((184) + ((28) * (8)))] // REG_OFFSET(28)
ldr x30, [x0, #((184) + ((30) * (8)))] // REG_OFFSET(30)
/* save current stack pointer */
ldr x2, [x0, #432] // SP_OFFSET
mov sp, x2
add x2, x0, #464 // FPSIMD_CONTEXT_OFFSET
ldp q8, q9, [x2, #144]
ldp q10, q11, [x2, #176]
ldp q12, q13, [x2, #208]
ldp q14, q15, [x2, #240]
/* save current program counter in link register */
ldr x16, [x0, #440] // PC_OFFSET
/* restore args */
ldp x2, x3, [x0, #((184) + ((2) * (8)))] // REG_OFFSET(2)
ldp x4, x5, [x0, #((184) + ((4) * (8)))] // REG_OFFSET(4)
ldp x6, x7, [x0, #((184) + ((6) * (8)))] // REG_OFFSET(6)
ldp x0, x1, [x0, #((184) + ((0) * (8)))] // REG_OFFSET(8)
/* jump to new PC */
br x16
)");

asm(R"(
.global _libucontext_swapcontext;
.align 2;
_libucontext_swapcontext:
str xzr, [x0, #((184) + ((0) * (8)))] // REG_OFFSET(0)
/* save GPRs */
stp x2, x3, [x0, #((184) + ((2) * (8)))] // REG_OFFSET(2)
stp x4, x5, [x0, #((184) + ((4) * (8)))] // REG_OFFSET(4)
stp x6, x7, [x0, #((184) + ((6) * (8)))] // REG_OFFSET(6)
stp x8, x9, [x0, #((184) + ((8) * (8)))] // REG_OFFSET(8)
stp x10, x11, [x0, #((184) + ((10) * (8)))] // REG_OFFSET(10)
stp x12, x13, [x0, #((184) + ((12) * (8)))] // REG_OFFSET(12)
stp x14, x15, [x0, #((184) + ((14) * (8)))] // REG_OFFSET(14)
stp x16, x17, [x0, #((184) + ((16) * (8)))] // REG_OFFSET(16)
stp x18, x19, [x0, #((184) + ((18) * (8)))] // REG_OFFSET(18)
stp x20, x21, [x0, #((184) + ((20) * (8)))] // REG_OFFSET(20)
stp x22, x23, [x0, #((184) + ((22) * (8)))] // REG_OFFSET(22)
stp x24, x25, [x0, #((184) + ((24) * (8)))] // REG_OFFSET(24)
stp x26, x27, [x0, #((184) + ((26) * (8)))] // REG_OFFSET(26)
stp x28, x29, [x0, #((184) + ((28) * (8)))] // REG_OFFSET(28)
str x30, [x0, #((184) + ((30) * (8)))] // REG_OFFSET(30)
/* save current program counter in link register */
str x30, [x0, #440] // PC_OFFSET
/* save current stack pointer */
mov x2, sp
str x2, [x0, #432] // SP_OFFSET
/* save pstate */
str xzr, [x0, #448] // PSTATE_OFFSET
add x2, x0, #464 // FPSIMD_CONTEXT_OFFSET
stp q8, q9, [x2, #144]
stp q10, q11, [x2, #176]
stp q12, q13, [x2, #208]
stp q14, q15, [x2, #240]
/* context to swap to is in x1 so... we move to x0 and call setcontext */
/* store our link register in x28 */
mov x28, x30
/* move x1 to x0 and call setcontext */
mov x0, x1
bl _libucontext_setcontext
/* hmm, we came back here try to return */
mov x30, x28
ret
)");
37 changes: 37 additions & 0 deletions common/ucontext/ucontext.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Compiler for PHP (aka KPHP)
// Copyright (c) 2018-2022 Ariadne Conill <[email protected]>
// https://github.com/kaniini/libucontext/tree/master (copied as third-party and slightly modified)
// Copyright (c) 2023 LLC «V Kontakte»
// Distributed under the GPL v3 License, see LICENSE.notice.txt

#pragma once

#include <cstddef>

struct libucontext_mcontext {
unsigned long fault_address;
unsigned long regs[31];
unsigned long sp, pc, pstate;
long double __reserved[256];
};

struct libucontext_stack {
void *ss_sp;
int ss_flags;
size_t ss_size;
};

struct libucontext_ucontext {
unsigned long uc_flags;
struct libucontext_ucontext *uc_link;
libucontext_stack uc_stack;
unsigned char __pad[136];
libucontext_mcontext uc_mcontext;
};

extern "C" {
void libucontext_makecontext(libucontext_ucontext *, void (*)(), int, ...);
int libucontext_getcontext(libucontext_ucontext *);
int libucontext_setcontext(const libucontext_ucontext *);
int libucontext_swapcontext(libucontext_ucontext *, const libucontext_ucontext *);
}
6 changes: 0 additions & 6 deletions compiler/compiler-settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -332,12 +332,6 @@ void CompilerSettings::init() {
ld_flags.value_ += " -L /usr/local/lib";
#endif

#if defined(__APPLE__) && defined(__arm64__)
// for development under M1, manual installation of libucontext is needed
// see the docs: https://vkcom.github.io/kphp/kphp-internals/developing-and-extending-kphp/compiling-kphp-from-sources.html
ld_flags.value_ += " /opt/homebrew/lib/libucontext.a";
#endif

std::vector<vk::string_view> external_libs{"pthread", "m", "dl"};

#ifdef PDO_DRIVER_MYSQL
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,34 +107,6 @@ cmake ..
sudo make install
```

##### MacOS with Apple M1 chipset

```note
Probably, there is an easier way to do this, but I couldn't find it, at least for late 2021.
```

Follow the steps above. Later on, you'll have to patch the [libucontext](https://github.com/kaniini/libucontext) library locally.
```bash
git clone https://github.com/kaniini/libucontext
cd libucontext
nano Makefile
```
Find assignment to `LIBUCONTEXT_LINKER_FLAGS` and replace it with:
```text
LIBUCONTEXT_LINKER_FLAGS = -dynamiclib -install_name ${LIBUCONTEXT_SONAME} -current_version ${LIBUCONTEXT_SOVERSION} -compatibility_version ${LIBUCONTEXT_SOVERSION}
```
Now we are ready to make libucontext:
```
make FREESTANDING=yes ARCH=aarch64
```
Finally, copy resulting files to the default brew search folder `/opt/homebrew`:
```
cp libucontext.a /opt/homebrew/lib
cp libucontext.dylib /opt/homebrew/lib
cp -r include/* /opt/homebrew/include/
```


##### Other Linux
Make sure you are using the same package list. You may use system default libcurl package, it would work, but without DNS resolving. `uber-h3` must be installed from sources.

Expand Down
4 changes: 2 additions & 2 deletions server/php-runner.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@
#include <csetjmp>

#include "common/dl-utils-lite.h"
#include "common/kprintf.h"
#include "common/mixin/not_copyable.h"
#include "common/sanitizer.h"
#include "common/kprintf.h"
#include "common/ucontext/ucontext-portable.h"

#include "server/php-engine-vars.h"
#include "server/php-init-scripts.h"
#include "server/php-queries-types.h"
#include "server/php-query-data.h"
#include "server/ucontext-portable.h"

DECLARE_VERBOSITY(php_runner);

Expand Down
3 changes: 0 additions & 3 deletions tests/tests.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@ if(KPHP_TESTS)
set(TEST_NAME unittests-${TEST_NAME})
add_executable(${TEST_NAME} ${ARGN})
target_link_libraries(${TEST_NAME} PRIVATE GTest::GTest GTest::Main gmock ${SRC_LIBS} vk::popular_common)
if(NOT CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND APPLE)
target_link_libraries(${TEST_NAME} PRIVATE /opt/homebrew/lib/libucontext.a)
endif()
target_link_options(${TEST_NAME} PRIVATE ${NO_PIE})

# because of https://github.com/VKCOM/kphp/actions/runs/5463884925/jobs/9945150190
Expand Down