Merge pull request #4918 from Feuris/feat/libc-mtx-init-with-name

feat(libc): implement _Mtx_init_with_name
This commit is contained in:
Adrià 2026-10-13 10:30:43 +02:00 committed by GitHub
commit cee54cdade
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 58 additions and 0 deletions

View File

@ -627,6 +627,18 @@ if(BUILD_TESTING)
endif()
endif()
add_test_executable(guest_libc_mutex_init_with_name_tests EXCLUDE_FROM_ALL ${LIBS_INCLUDE_DIR}/tests/GuestLibcMutexInitWithName.cpp)
target_include_directories(guest_libc_mutex_init_with_name_tests PRIVATE ${LIBS_INCLUDE_DIR})
target_link_libraries(guest_libc_mutex_init_with_name_tests PRIVATE libc)
configure_windows_unwind(guest_libc_mutex_init_with_name_tests)
if(BUILD_TESTING)
set_target_properties(guest_libc_mutex_init_with_name_tests PROPERTIES EXCLUDE_FROM_ALL FALSE)
add_test(NAME guest_libc_mutex_init_with_name COMMAND guest_libc_mutex_init_with_name_tests)
if(WIN32)
set_tests_properties(guest_libc_mutex_init_with_name PROPERTIES ENVIRONMENT_MODIFICATION "PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
endif()
endif()
if(MINGW)
if(BUILD_TESTING)
enable_language(ASM)

View File

@ -107,6 +107,10 @@ int APS5_VABI _Mtx_init_nid_postfix(void** handle, int type) {
return threadSuccess;
}
int APS5_VABI _Mtx_init_with_name_nid_postfix(void** handle, int type, const char*) {
return _Mtx_init_nid_postfix(handle, type);
}
void APS5_VABI _Mtx_destroy_nid_postfix(void** handle) {
if (!handle)
throw std::invalid_argument("_Mtx_destroy: null mutex handle pointer");

View File

@ -0,0 +1,41 @@
#include "prx/libc/include/general/VabiMacros.hpp"
#include <cstdlib>
#include <stdexcept>
extern "C" {
int APS5_VABI _Mtx_init_with_name_nid_postfix(void** handle, int type, const char* name);
void APS5_VABI _Mtx_destroy_nid_postfix(void** handle);
int APS5_VABI _Mtx_lock_nid_postfix(void** handle);
int APS5_VABI _Mtx_unlock_nid_postfix(void** handle);
}
static void Require(bool value) { if (!value) std::abort(); }
template<typename TException, typename TCall>
static void RequireThrows(TCall call) {
try {
call();
} catch (const TException&) {
return;
}
std::abort();
}
constexpr int success = 0;
constexpr int busy = 3;
constexpr int plain = 0x01;
int main() {
void* mutex = nullptr;
Require(_Mtx_init_with_name_nid_postfix(&mutex, plain, "GameMutex") == success);
Require(mutex != nullptr);
Require(_Mtx_lock_nid_postfix(&mutex) == success);
Require(_Mtx_lock_nid_postfix(&mutex) == busy);
Require(_Mtx_unlock_nid_postfix(&mutex) == success);
_Mtx_destroy_nid_postfix(&mutex);
Require(mutex == nullptr);
RequireThrows<std::invalid_argument>([] {
_Mtx_init_with_name_nid_postfix(nullptr, plain, "NullHandle");
});
}

View File

@ -5,6 +5,7 @@
- [_Mtx_trylock](../../../core/libs/prx/libc/src/Threads.cpp) (libc, NID `k6pGNMwJB08`) - returns busy for a non-recursive mutex already owned by the caller, assumed to match `_Mtx_lock`'s ownership handling; exact console behavior is unverified.
- [nearbyintf](../../../core/libs/prx/libc/src/Math.cpp) (libc, NID `c+4r-T-tEIc`) uses the host rounding mode, not the console's; console rounding mode state remains unverified.
- [_Thrd_sleep](../../../core/libs/prx/libc/src/Threads.cpp) (libc, NID `jfRI3snge3o`) follows the Dinkumware threads library shipped with [Visual C++ 2013](https://github.com/adityaramesh/concurrency_runtime/tree/master/VS2013_SP2/crt/src/thr) (`xtime.c`) and C11 Annex K, without console verification. It reads a 16-byte xtime (64-bit seconds and nanoseconds) on the guest `CLOCK_REALTIME`, normalizes the nanoseconds and sleeps through `nanosleep`, retrying on `EINTR`, so it is a cancellation point; a null xtime or one whose normalization overflows throws. The console's `_Thrd_sleep` (disassembled from a title's `libc.prx`) also takes an optional `xtime*` of remaining time and returns `int`; here the sleep is never cut short, so it returns 0 and leaves the remaining time untouched.
- [_Mtx_init_with_name](../../../core/libs/prx/libc/src/Threads.cpp) (libc, NID `tgioGpKtmbE`) forwards to `_Mtx_init` and ignores the mutex name parameter.
- [Guest arena](../../../core/libs/prx/libc/src/GuestArena.cpp) (libc) - the application map area is assumed to end at 0xFC_0000_0000, as `SCE_KERNEL_APP_MAP_AREA_END_ADDR` does on the PS4. On Windows, host allocations made in the arena before libc loads stay, and a fixed guest mapping over one throws
- [sceLibcInternalBacktraceForGame](../../../core/libs/prx/libc/src/HeapDiagnostics.cpp) (libSceLibcInternal, implemented in libc) - `(const char* heapName)` and its return follow the `libc.prx` ASTRO BOT (PPSA21564 01.007.000) bundles: its four calls (0x6801, 0x7F46, 0xE75E, 0xEE02) are in the `malloc_stats` and `sceLibcMspaceMallocStats` paths, each after a `[%s] ...` line printed with the same heap name buffer, and the caller ignores the result and continues. The console's backtrace output is not reproduced: the heap name and the guest return address are written to the host standard error
- [sceLibcInternalHeapErrorReportForGame](../../../core/libs/prx/libc/src/HeapDiagnostics.cpp) (libSceLibcInternal, implemented in libc) - `(void* heap, void* block, uint32 error)` follows the same `libc.prx` (call at 0xF634): it passes the heap, the block and the nonzero result of its block check, and then calls a function that never returns, so the report only has to return. The meaning of the error values is unknown; the three values and the guest return address are written to the host standard error