Merge pull request #2543 from overlordxrz-source/feat/libkernel-kill

feat(libkernel): implement kill
This commit is contained in:
Adrià 2026-10-10 11:21:08 +02:00 committed by GitHub
commit 3afc78464c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 64 additions and 0 deletions

View File

@ -422,6 +422,16 @@ if(BUILD_TESTING)
set_tests_properties(guest_signals PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libkernel>")
endif()
add_test_executable(guest_kill_tests ${LIBS_INCLUDE_DIR}/tests/GuestKill.cpp)
target_include_directories(guest_kill_tests PRIVATE ${LIBS_INCLUDE_DIR})
target_link_libraries(guest_kill_tests PRIVATE libkernel libc)
configure_windows_unwind(guest_kill_tests)
add_test(NAME guest_kill COMMAND guest_kill_tests)
set_tests_properties(guest_kill PROPERTIES TIMEOUT 20)
if(WIN32)
set_tests_properties(guest_kill PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libkernel>")
endif()
add_test_executable(guest_signal_set_tests ${LIBS_INCLUDE_DIR}/tests/GuestSignalSets.cpp)
target_include_directories(guest_signal_set_tests PRIVATE ${LIBS_INCLUDE_DIR})
target_link_libraries(guest_signal_set_tests PRIVATE libkernel libc)

View File

@ -8,6 +8,7 @@
#include <stdexcept>
extern "C" int* APS5_VABI __error_nid_postfix();
extern "C" int APS5_VABI getpid_nid_postfix(void);
struct GuestSignalSet {
std::uint32_t bits[4];
@ -120,6 +121,12 @@ int APS5_VABI raise_nid_postfix(int guest) {
if (result) *__error_nid_postfix() = 22;
return result ? -1 : 0;
}
int APS5_VABI kill_nid_postfix(int pid, int guest) {
if (guest < 0 || guest > MaxSignal) { *__error_nid_postfix() = 22; return -1; }
const int self = getpid_nid_postfix();
if (pid != self && pid != 0 && pid != -self) { *__error_nid_postfix() = 3; return -1; }
return guest == 0 ? 0 : raise_nid_postfix(guest);
}
int APS5_VABI sigaltstack_nid_postfix(const GuestStack* stack, GuestStack* previous) {
GuestStack replacement = alternateStack;
if (stack != nullptr) {

View File

@ -0,0 +1,46 @@
#include "prx/libc/include/general/VabiMacros.hpp"
#include <csignal>
#include <cstdint>
#include <cstdlib>
#include <initializer_list>
using Handler = void (APS5_VABI *)(int);
extern "C" {
Handler APS5_VABI signal_nid_postfix(int, Handler);
int APS5_VABI kill_nid_postfix(int, int);
int APS5_VABI getpid_nid_postfix(void);
int* APS5_VABI __error_nid_postfix();
}
volatile std::sig_atomic_t received = 0;
void APS5_VABI Callback(int value) { received = value; }
static void Require(bool value) { if (!value) std::abort(); }
static void Fails(int pid, int guest, int error) {
*__error_nid_postfix() = 0;
Require(kill_nid_postfix(pid, guest) == -1 && *__error_nid_postfix() == error);
}
int main() {
const int self = getpid_nid_postfix();
const auto invalid = reinterpret_cast<Handler>(static_cast<std::uintptr_t>(-1));
const auto ignore = reinterpret_cast<Handler>(std::uintptr_t{1});
for (int target : {self, 0, -self}) Require(kill_nid_postfix(target, 0) == 0);
for (int target : {self + 1, -1, -(self + 1)}) {
Fails(target, 0, 3);
Fails(target, 15, 3);
}
for (int guest : {-1, 129}) {
Fails(self, guest, 22);
Fails(self + 1, guest, 22);
}
Require(signal_nid_postfix(15, Callback) != invalid);
for (int target : {self, 0, -self}) {
received = 0;
Require(kill_nid_postfix(target, 0) == 0 && received == 0);
Require(kill_nid_postfix(target, 15) == 0 && received == 15);
}
received = 0;
Fails(self + 1, 15, 3);
Require(received == 0);
Require(signal_nid_postfix(15, ignore) == Callback);
Require(kill_nid_postfix(self, 15) == 0 && received == 0);
Require(signal_nid_postfix(15, nullptr) == ignore);
Fails(self, 100, 22);
}

View File

@ -445,5 +445,6 @@ Throughout the project, every function at every stage either **does exactly what
- [sceVideodec2CreateDecoder](../../core/libs/prx/libSceVideodec2/Export.cpp) (libSceVideodec2) decodes HEVC (codec type 974921) and VP9 (2382845) through FFmpeg, besides H.264. The tags come from SharpProspero's `Videodec2CodecType` and EVO-PLAYER-PS5's `sce_videodec2.h`, which records them from hardware runs. HEVC input is converted from length-prefixed NAL units to Annex B as for H.264, and VP9 frames are passed through. Output is the same 8-bit NV12 for every codec; a decoder for HEVC Main10 or VP9 Profile 2 is created, but a frame deeper than 8 bits throws, since the console's 10-bit output layout is unknown, and `QueryDecoderMemoryInfo` reports the 8-bit frame size for it. `sceVideodec2GetPictureInfo` and `sceVideodec2GetAvcPictureInfo` throw for HEVC and VP9 pictures, which use other layouts (`SceVideodec2HevcPictureInfo`, `SceVideodec2Vp9PictureInfo`), and `sceVideodec2GetHevcPictureInfo` and `sceVideodec2GetVp9PictureInfo` are not exported
- [syslog](../../core/libs/prx/libc/src/Syslog.cpp) (libc) writes each message to `stderr` as `[syslog:<priority>] <message>`, with a newline added when missing, instead of sending it to the console's system log. Priority and facility handling follow FreeBSD's `vsyslog`: `%m` expands to the guest errno's message, unknown bits are reported (as priority 0x23, since FreeBSD passes `LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID` as the priority) and masked, a missing facility becomes `LOG_USER`, and errno is preserved. `openlog`, `setlogmask` and `closelog` are not implemented, so the identity, options and mask they set are not applied
- [sigaction](../../core/libs/prx/libkernel/System/src/Signals.cpp) (libkernel) records the handler, flags and mask of every signal from 1 to 128 and reports them back, following FreeBSD's `sigaction` (`EINVAL` for other signals, and for a handler on `SIGKILL` or `SIGSTOP`); `signal` records its handler with `SA_RESTART`, as FreeBSD's libc does. Only handlers without `SA_SIGINFO` on the signals `signal` already delivers (`SIGINT`, `SIGILL`, `SIGABRT`, `SIGFPE`, `SIGSEGV`, `SIGTERM`) run, the same way `signal` handlers do; their mask and flags are not applied. `SA_SIGINFO` handlers and other signals (`SIGBUS`, `SIGHUP`, ...) are recorded but never called, since that needs FreeBSD's `siginfo_t` and `ucontext_t`; `raise` of an `SA_SIGINFO` handler on a signal `signal` delivers throws instead of terminating, and `raise` of the other signals still returns `EINVAL`
- [kill](../../core/libs/prx/libkernel/System/src/Signals.cpp) (libkernel) follows FreeBSD's `kern_kill` and `killpg1` for the only guest process: `EINVAL` for signals outside 0 to 128, signal 0 only checks that the target exists, and its own pid, 0 and minus its own pid (the guest is taken to lead its own process group) signal it through `raise`, so they share `raise`'s limits above. Any other pid, and -1, which skips the caller, report `ESRCH`, so `EPERM` is never reported
- [AJM](../../core/libs/prx/libSceAjm.native/src/Ajm.cpp), [APR](../../core/libs/prx/libkernel/Apr/src/Apr.cpp) and [NGS2](../../core/libs/prx/libSceNgs2.native/src/System.cpp) state is allocated with `new` and never freed on purpose: title threads still call into these libraries while `std::exit` runs static destructors, so ordinary statics would be destroyed under them. Keep them leaked; `guest_ajm_teardown` covers the AJM case on Unix.
- [Null vertex buffer V#](../../core/libs/prx/libSceAgcDriver/Graphics/include/VertexInput.hpp) (libSceAgcDriver) - a V# whose four dwords are all zero is bound to a zeroed vertex buffer of the attribute's size with stride 0, so every component of its attribute reads 0. This follows the V# fields in the [AMD RDNA2 ISA](https://gpuopen.com/download/rdna2-shader-instruction-set-architecture.pdf) (`NUM_RECORDS` 0, `DST_SEL` 0 selects 0), not measured on hardware.