Libcinternal threads

fopen stores a valid pthread mutex in the FILE struct. Since this is exposed to the game/app, we need to handle this accurately.
This commit is contained in:
Stephen Miller 2026-02-09 20:50:08 -06:00
parent cc3d92e675
commit ebd62b525d
7 changed files with 114 additions and 15 deletions

View File

@ -494,6 +494,8 @@ set(HLE_LIBC_INTERNAL_LIB src/core/libraries/libc_internal/libc_internal.cpp
src/core/libraries/libc_internal/libc_internal_str.h
src/core/libraries/libc_internal/libc_internal_math.cpp
src/core/libraries/libc_internal/libc_internal_math.h
src/core/libraries/libc_internal/libc_internal_threads.cpp
src/core/libraries/libc_internal/libc_internal_threads.h
src/core/libraries/libc_internal/printf.h
)

View File

@ -28,6 +28,16 @@ int PS4_SYSV_ABI posix_pthread_create(PthreadT* thread, const PthreadAttrT* attr
int PS4_SYSV_ABI posix_pthread_join(PthreadT pthread, void** thread_return);
int PS4_SYSV_ABI posix_pthread_mutexattr_init(PthreadMutexAttrT* attr);
int PS4_SYSV_ABI posix_pthread_mutexattr_settype(PthreadMutexAttrT* attr, PthreadMutexType type);
int PS4_SYSV_ABI posix_pthread_mutexattr_destroy(PthreadMutexAttrT* attr);
int PS4_SYSV_ABI scePthreadMutexInit(PthreadMutexT* mutex, const PthreadMutexAttrT* mutex_attr,
const char* name);
int PS4_SYSV_ABI posix_pthread_mutex_lock(PthreadMutexT* mutex);
int PS4_SYSV_ABI posix_pthread_mutex_unlock(PthreadMutexT* mutex);
int PS4_SYSV_ABI posix_pthread_mutex_destroy(PthreadMutexT* mutex);
void RegisterThreads(Core::Loader::SymbolsResolver* sym);
class Thread {

View File

@ -11,6 +11,7 @@
#include "libc_internal_math.h"
#include "libc_internal_memory.h"
#include "libc_internal_str.h"
#include "libc_internal_threads.h"
#include "printf.h"
namespace Libraries::LibcInternal {
@ -20,6 +21,7 @@ void RegisterLib(Core::Loader::SymbolsResolver* sym) {
RegisterlibSceLibcInternalStr(sym);
RegisterlibSceLibcInternalMemory(sym);
RegisterlibSceLibcInternalIo(sym);
RegisterlibSceLibcInternalThreads(sym);
}
void ForceRegisterLib(Core::Loader::SymbolsResolver* sym) {

View File

@ -11,21 +11,18 @@
#include "core/libraries/kernel/file_system.h"
#include "core/libraries/kernel/kernel.h"
#include "core/libraries/kernel/posix_error.h"
#include "core/libraries/kernel/threads.h"
#include "core/libraries/libs.h"
#include "libc_internal_io.h"
#include "printf.h"
namespace Libraries::LibcInternal {
s32 PS4_SYSV_ABI internal_snprintf(char* s, size_t n, VA_ARGS) {
s32 PS4_SYSV_ABI internal_snprintf(char* s, u64 n, VA_ARGS) {
VA_CTX(ctx);
return snprintf_ctx(s, n, &ctx);
}
void RegisterlibSceLibcInternalIo(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("eLdDw6l0-bU", "libSceLibcInternal", 1, "libSceLibcInternal", internal_snprintf);
}
std::vector<OrbisFILE*> g_files{};
// Constants for tracking accurate file indexes.
// Since the file struct is exposed to the application, accuracy is important.
@ -88,7 +85,14 @@ s32 PS4_SYSV_ABI internal_fclose(OrbisFILE* stream) {
return 0;
}
void RegisterlibSceLibcInternalIo(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("eLdDw6l0-bU", "libSceLibcInternal", 1, "libSceLibcInternal", internal_snprintf);
LIB_FUNCTION("xGT4Mc55ViQ", "libSceLibcInternal", 1, "libSceLibcInternal", internal__Fofind);
LIB_FUNCTION("dREVnZkAKRE", "libSceLibcInternal", 1, "libSceLibcInternal", internal__Foprep);
}
void ForceRegisterlibSceLibcInternalIo(Core::Loader::SymbolsResolver* sym) {
// Goal is to be minimally intrusive here to allow LLE for printf/stdout writes.
LIB_FUNCTION("xeYO4u7uyJ0", "libSceLibcInternal", 1, "libSceLibcInternal", internal_fopen);
LIB_FUNCTION("rQFVBXp-Cxg", "libSceLibcInternal", 1, "libSceLibcInternal", internal_fseek);
LIB_FUNCTION("lbB+UlZqVG0", "libSceLibcInternal", 1, "libSceLibcInternal", internal_fread);

View File

@ -39,18 +39,16 @@ struct OrbisFILE {
u16 _Mode;
u8 _Idx;
s32 _Handle;
u8 *_Buf, *_Bend, *_Next;
u8 *_Rend, *_Wend, *_Rback;
u16 *_WRback, _WBack[2];
u16 unk1;
u8 *_Rsave, *_WRend, *_WWend;
Orbis_Mbstatet _Wstate;
u8* _Tmpnam;
u8 _Back[6], _Cbuf;
u8 unk2;
void* _Mutex;
u8* _p;
s32 _r;
s32 _w;
@ -58,25 +56,19 @@ struct OrbisFILE {
s16 _file;
Orbis__sbuf _bf;
s32 _lbfsize;
void* _cookie;
s32 PS4_SYSV_ABI (*_close)(void*);
s32 PS4_SYSV_ABI (*_read)(void*, char*, s32);
Orbisfpos_t PS4_SYSV_ABI (*_seek)(void*, Orbisfpos_t, s32);
s32 (*_write)(void*, const char*, s32);
Orbis__sbuf _ub;
u8* _up;
s32 _ur;
u8 _ubuf[3];
u8 _nbuf[1];
Orbis__sbuf _lb;
s32 _blksize;
Orbisfpos_t _offset;
void* _fl_mutex;
void* _fl_owner;
s32 _fl_count;
@ -84,6 +76,15 @@ struct OrbisFILE {
Orbis__mbstate_t _mbstate;
};
s32 PS4_SYSV_ABI internal_snprintf(char* s, u64 n, VA_ARGS);
OrbisFILE* PS4_SYSV_ABI internal__Fofind();
OrbisFILE* PS4_SYSV_ABI internal__Foprep(const char* path, const char* mode, OrbisFILE* file,
s32 fd, s32 flag1, s32 flag2);
OrbisFILE* PS4_SYSV_ABI internal_fopen(const char* path, const char* mode);
s32 PS4_SYSV_ABI internal_fseek(OrbisFILE* stream, s64 offset, s32 whence);
u64 PS4_SYSV_ABI internal_fread(void* ptr, u64 size, u64 nmemb, OrbisFILE* stream);
s32 PS4_SYSV_ABI internal_fclose(OrbisFILE* stream);
void RegisterlibSceLibcInternalIo(Core::Loader::SymbolsResolver* sym);
void ForceRegisterlibSceLibcInternalIo(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::LibcInternal

View File

@ -0,0 +1,64 @@
// SPDX-FileCopyrightText: Copyright 2026 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/libraries/kernel/threads.h"
#include "core/libraries/libc_internal/libc_internal_threads.h"
#include "core/libraries/libs.h"
namespace Libraries::LibcInternal {
void getMutexName(char* buf, u64 size, const char* name) {
if (name != nullptr) {
std::snprintf(buf, size, "SceLibcI_%s", name);
}
std::snprintf(buf, size, "SceLibcI");
}
s32 PS4_SYSV_ABI internal__Mtxinit(Libraries::Kernel::PthreadMutexT* mtx, const char* name) {
char mtx_name[0x20];
getMutexName(mtx_name, sizeof(mtx_name), name);
Libraries::Kernel::PthreadMutexAttrT attr{};
s32 result = Libraries::Kernel::posix_pthread_mutexattr_init(&attr);
if (result != 0) {
return 1;
}
result = Libraries::Kernel::posix_pthread_mutexattr_settype(
&attr, Libraries::Kernel::PthreadMutexType::Recursive);
if (result != 0) {
s32 mtx_init_result = Libraries::Kernel::scePthreadMutexInit(mtx, &attr, mtx_name);
result = Libraries::Kernel::posix_pthread_mutexattr_destroy(&attr);
if (mtx_init_result == 0 && result == 0) {
return 0;
}
} else {
Libraries::Kernel::posix_pthread_mutexattr_destroy(&attr);
}
return 1;
}
s32 PS4_SYSV_ABI internal__Mtxlock(Libraries::Kernel::PthreadMutexT* mtx) {
s32 result = Libraries::Kernel::posix_pthread_mutex_lock(mtx);
return result != 0;
}
s32 PS4_SYSV_ABI internal__Mtxunlock(Libraries::Kernel::PthreadMutexT* mtx) {
s32 result = Libraries::Kernel::posix_pthread_mutex_unlock(mtx);
return result != 0;
}
s32 PS4_SYSV_ABI internal__Mtxdst(Libraries::Kernel::PthreadMutexT* mtx) {
s32 result = Libraries::Kernel::posix_pthread_mutex_destroy(mtx);
return result != 0;
}
void RegisterlibSceLibcInternalThreads(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("z7STeF6abuU", "libSceLibcInternal", 1, "libSceLibcInternal", internal__Mtxinit);
LIB_FUNCTION("pE4Ot3CffW0", "libSceLibcInternal", 1, "libSceLibcInternal", internal__Mtxlock);
LIB_FUNCTION("cMwgSSmpE5o", "libSceLibcInternal", 1, "libSceLibcInternal", internal__Mtxunlock);
LIB_FUNCTION("LaPaA6mYA38", "libSceLibcInternal", 1, "libSceLibcInternal", internal__Mtxdst);
}
} // namespace Libraries::LibcInternal

View File

@ -0,0 +1,16 @@
// SPDX-FileCopyrightText: Copyright 2026 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <mutex>
#include "common/types.h"
namespace Core::Loader {
class SymbolsResolver;
}
namespace Libraries::LibcInternal {
void RegisterlibSceLibcInternalThreads(Core::Loader::SymbolsResolver* sym);
}