Skip to content
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
7 changes: 6 additions & 1 deletion core/libs/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -330,12 +330,17 @@ if(BUILD_TESTING)
configure_windows_unwind(guest_kernel_sys_barrier_tests)
add_test(NAME guest_kernel_sys_barrier COMMAND guest_kernel_sys_barrier_tests)
set_tests_properties(guest_kernel_sys_barrier PROPERTIES TIMEOUT 20)
add_test_executable(guest_kernel_sys_pthread_tests tests/GuestKernelSysPthread.cpp)
target_include_directories(guest_kernel_sys_pthread_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(guest_kernel_sys_pthread_tests PRIVATE libkernel_sys libkernel libc)
configure_windows_unwind(guest_kernel_sys_pthread_tests)
add_test(NAME guest_kernel_sys_pthread COMMAND guest_kernel_sys_pthread_tests)
if(Python3_Interpreter_FOUND)
add_test(NAME nid_verneed COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/nid/tests/test_verneed.py $<TARGET_FILE:nid_patcher>)
endif()
if(WIN32)
set_tests_properties(guest_kernel_sys guest_kernel_sys_thread_defaults guest_kernel_sys_barrier PROPERTIES ENVIRONMENT_MODIFICATION
set_tests_properties(guest_kernel_sys guest_kernel_sys_thread_defaults guest_kernel_sys_barrier guest_kernel_sys_pthread PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libkernel_sys>")
endif()
if(APPLE)
Expand Down
24 changes: 12 additions & 12 deletions core/libs/prx/libkernel_sys/Export.Discovery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ int APS5_VABI pthread_barrierattr_getpshared_nid_postfix(void* const* attr, int*
int APS5_VABI pthread_barrierattr_setpshared_nid_postfix(void** attr, int pshared);
int APS5_VABI pthread_getcpuclockid_nid_postfix(void* thread, int* clockId);
int APS5_VABI pthread_getconcurrency_nid_postfix();
int APS5_VABI pthread_setconcurrency_nid_postfix(int level);
int APS5_VABI pthread_attr_getscope_nid_postfix(void* const* attr, int* scope);
int APS5_VABI pthread_attr_setscope_nid_postfix(void** attr, int scope);
int APS5_VABI pthread_atfork_nid_postfix(void (APS5_VABI* prepare)(), void (APS5_VABI* parent)(), void (APS5_VABI* child)());
int APS5_VABI msync_nid_postfix(void* address, std::size_t length, int flags);
}

Expand Down Expand Up @@ -2271,24 +2275,21 @@ int APS5_VABI sceLibcMspaceCreateForMonoMutex(void) {
return 0;
}

int APS5_VABI scePthreadAtfork(void) {
NotImplemented_nid_no_patch(__func__);
return 0;
int APS5_VABI scePthreadAtfork(void (APS5_VABI* prepare)(), void (APS5_VABI* parent)(), void (APS5_VABI* child)()) {
return SceResult(pthread_atfork_nid_postfix(prepare, parent, child));
}

int APS5_VABI scePthreadAttrGetscope(void) {
NotImplemented_nid_no_patch(__func__);
return 0;
int APS5_VABI scePthreadAttrGetscope(void* const* attr, int* scope) {
return SceResult(pthread_attr_getscope_nid_postfix(attr, scope));
}

int APS5_VABI scePthreadAttrSetcreatesuspend(void) {
NotImplemented_nid_no_patch(__func__);
return 0;
}

int APS5_VABI scePthreadAttrSetscope(void) {
NotImplemented_nid_no_patch(__func__);
return 0;
int APS5_VABI scePthreadAttrSetscope(void** attr, int scope) {
return SceResult(pthread_attr_setscope_nid_postfix(attr, scope));
}

int APS5_VABI scePthreadBarrierDestroy(void** barrier) {
Expand Down Expand Up @@ -2404,9 +2405,8 @@ int APS5_VABI scePthreadSetBesteffort(void) {
return 0;
}

int APS5_VABI scePthreadSetconcurrency(void) {
NotImplemented_nid_no_patch(__func__);
return 0;
int APS5_VABI scePthreadSetconcurrency(int level) {
return SceResult(pthread_setconcurrency_nid_postfix(level));
}

int APS5_VABI scePthreadSingle(void) {
Expand Down
66 changes: 66 additions & 0 deletions core/libs/tests/GuestKernelSysPthread.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#include "SceTypes.hpp"
#include "prx/libkernel/Pthread/include/Atfork.hpp"
#include <cstdlib>

extern "C" {
int APS5_VABI scePthreadAttrInit(PthreadAttr* attr);
int APS5_VABI scePthreadAttrDestroy(PthreadAttr* attr);
int APS5_VABI scePthreadAttrGetscope(const PthreadAttr* attr, int* scope);
int APS5_VABI scePthreadAttrSetscope(PthreadAttr* attr, int scope);
int APS5_VABI scePthreadAtfork(PthreadAtforkHandler prepare, PthreadAtforkHandler parent, PthreadAtforkHandler child);
int APS5_VABI scePthreadSetconcurrency(int level);
int APS5_VABI scePthreadGetconcurrency();
}

static constexpr int SCE_KERNEL_ERROR_EINVAL = static_cast<int>(0x80020016);
static constexpr int SCOPE_PROCESS = 0;
static constexpr int SCOPE_SYSTEM = 2;

static void Require(bool value) { if (!value) std::abort(); }

static void APS5_VABI Prepare() {}
static void APS5_VABI Parent() {}
static void APS5_VABI Child() {}

static void TestScope() {
PthreadAttr attr{};
Require(scePthreadAttrInit(&attr) == 0);
int scope = -1;
Require(scePthreadAttrGetscope(&attr, &scope) == 0 && scope == SCOPE_SYSTEM);
Require(scePthreadAttrSetscope(&attr, SCOPE_PROCESS) == 0);
Require(scePthreadAttrGetscope(&attr, &scope) == 0 && scope == SCOPE_PROCESS);
for (const int invalid : {1, 3, -1}) {
Require(scePthreadAttrSetscope(&attr, invalid) == SCE_KERNEL_ERROR_EINVAL);
scope = -1;
Require(scePthreadAttrGetscope(&attr, &scope) == 0 && scope == SCOPE_PROCESS);
}
Require(scePthreadAttrSetscope(&attr, SCOPE_SYSTEM) == 0);
Require(scePthreadAttrGetscope(&attr, &scope) == 0 && scope == SCOPE_SYSTEM);
Require(scePthreadAttrGetscope(&attr, nullptr) == SCE_KERNEL_ERROR_EINVAL);
Require(scePthreadAttrGetscope(nullptr, &scope) == SCE_KERNEL_ERROR_EINVAL);
Require(scePthreadAttrSetscope(nullptr, SCOPE_PROCESS) == SCE_KERNEL_ERROR_EINVAL);
Require(scePthreadAttrDestroy(&attr) == 0);
}

static void TestConcurrency() {
Require(scePthreadSetconcurrency(3) == 0 && scePthreadGetconcurrency() == 3);
Require(scePthreadSetconcurrency(-1) == SCE_KERNEL_ERROR_EINVAL && scePthreadGetconcurrency() == 3);
Require(scePthreadSetconcurrency(0) == 0 && scePthreadGetconcurrency() == 0);
}

static void TestAtfork() {
const auto before = PthreadAtforkHandlers_nid_no_patch().size();
Require(scePthreadAtfork(Prepare, Parent, Child) == 0);
Require(scePthreadAtfork(nullptr, nullptr, nullptr) == 0);
const auto handlers = PthreadAtforkHandlers_nid_no_patch();
Require(handlers.size() == before + 2);
Require(handlers[before].prepare == Prepare && handlers[before].parent == Parent && handlers[before].child == Child);
Require(handlers[before + 1].prepare == nullptr && handlers[before + 1].parent == nullptr && handlers[before + 1].child == nullptr);
}

int main() {
TestScope();
TestConcurrency();
TestAtfork();
return 0;
}
1 change: 1 addition & 0 deletions docs/dev/debt/libkernel_sys.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,4 @@
### Unknown function info

- [scePthreadBarrier*, scePthreadBarrierattr*, scePthreadGetcpuclockid, scePthreadGetconcurrency and sceKernelMsync](../../../core/libs/prx/libkernel_sys/Export.Discovery.cpp) (libkernel_sys) call libkernel's `pthread_barrier*`, `pthread_getcpuclockid`, `pthread_getconcurrency` and `msync` and turn a POSIX error into `0x80020000 | errno`; that the console's `sce` forms do the same is not measured. Signatures follow the [Orbital type database](https://github.com/AlexAltea/orbital/blob/master/tools/ida/db_types.json); `scePthreadBarrierInit` ignores its name, and `scePthreadBarrierWait` returns -1 to the serial thread, both as in [shadPS4](https://github.com/shadps4-emu/shadPS4/blob/main/src/core/libraries/kernel/threads/barrier.cpp) (PS4). `scePthreadGetconcurrency` returns the level unchanged
- [scePthreadAttrGetscope, scePthreadAttrSetscope, scePthreadAtfork and scePthreadSetconcurrency](../../../core/libs/prx/libkernel_sys/Export.Discovery.cpp) (libkernel_sys) call libkernel's `pthread_attr_getscope`, `pthread_attr_setscope`, `pthread_atfork` and `pthread_setconcurrency` and turn a POSIX error into `0x80020000 | errno`, as [shadPS4](https://github.com/shadps4-emu/shadPS4/blob/15abf68c9b52c4b04d094f2837719fdb871021f3/src/core/libraries/kernel/threads/pthread_attr.cpp#L392) exports `scePthreadAttrGetscope` as `ORBIS(posix_pthread_attr_getscope)`; shadPS4 has no export for the other three, whose names and NIDs are in the [symbol database](https://github.com/zecoxao/sce_symbols/blob/2883963a0a514ba6e77407a08ef4730a65e88254/aerolib.csv) and whose signatures follow the same POSIX forms. Not measured on a console. As in libkernel, the scope is 0 (process) or 2 (system), and `scePthreadAtfork` handlers are only recorded, as no process forks
Loading