threads: initialize tls on thread creation (take 2) (#4070)

This commit is contained in:
Vladislav Mikhalin 2026-02-24 20:35:05 +03:00 committed by GitHub
parent af9cbb8e8a
commit e1ecd8e98c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 94 additions and 68 deletions

View File

@ -12,28 +12,28 @@ void* PS4_SYSV_ABI AvPlayer::Allocate(void* handle, u32 alignment, u32 size) {
const auto* const self = reinterpret_cast<AvPlayer*>(handle);
const auto allocate = self->m_init_data_original.memory_replacement.allocate;
const auto ptr = self->m_init_data_original.memory_replacement.object_ptr;
return Core::ExecuteGuest(allocate, ptr, alignment, size);
return allocate(ptr, alignment, size);
}
void PS4_SYSV_ABI AvPlayer::Deallocate(void* handle, void* memory) {
const auto* const self = reinterpret_cast<AvPlayer*>(handle);
const auto deallocate = self->m_init_data_original.memory_replacement.deallocate;
const auto ptr = self->m_init_data_original.memory_replacement.object_ptr;
return Core::ExecuteGuest(deallocate, ptr, memory);
return deallocate(ptr, memory);
}
void* PS4_SYSV_ABI AvPlayer::AllocateTexture(void* handle, u32 alignment, u32 size) {
const auto* const self = reinterpret_cast<AvPlayer*>(handle);
const auto allocate = self->m_init_data_original.memory_replacement.allocate_texture;
const auto ptr = self->m_init_data_original.memory_replacement.object_ptr;
return Core::ExecuteGuest(allocate, ptr, alignment, size);
return allocate(ptr, alignment, size);
}
void PS4_SYSV_ABI AvPlayer::DeallocateTexture(void* handle, void* memory) {
const auto* const self = reinterpret_cast<AvPlayer*>(handle);
const auto deallocate = self->m_init_data_original.memory_replacement.deallocate_texture;
const auto ptr = self->m_init_data_original.memory_replacement.object_ptr;
return Core::ExecuteGuest(deallocate, ptr, memory);
return deallocate(ptr, memory);
}
int PS4_SYSV_ABI AvPlayer::OpenFile(void* handle, const char* filename) {
@ -42,7 +42,7 @@ int PS4_SYSV_ABI AvPlayer::OpenFile(void* handle, const char* filename) {
const auto open = self->m_init_data_original.file_replacement.open;
const auto ptr = self->m_init_data_original.file_replacement.object_ptr;
return Core::ExecuteGuest(open, ptr, filename);
return open(ptr, filename);
}
int PS4_SYSV_ABI AvPlayer::CloseFile(void* handle) {
@ -51,7 +51,7 @@ int PS4_SYSV_ABI AvPlayer::CloseFile(void* handle) {
const auto close = self->m_init_data_original.file_replacement.close;
const auto ptr = self->m_init_data_original.file_replacement.object_ptr;
return Core::ExecuteGuest(close, ptr);
return close(ptr);
}
int PS4_SYSV_ABI AvPlayer::ReadOffsetFile(void* handle, u8* buffer, u64 position, u32 length) {
@ -60,7 +60,7 @@ int PS4_SYSV_ABI AvPlayer::ReadOffsetFile(void* handle, u8* buffer, u64 position
const auto read_offset = self->m_init_data_original.file_replacement.read_offset;
const auto ptr = self->m_init_data_original.file_replacement.object_ptr;
return Core::ExecuteGuest(read_offset, ptr, buffer, position, length);
return read_offset(ptr, buffer, position, length);
}
u64 PS4_SYSV_ABI AvPlayer::SizeFile(void* handle) {
@ -69,7 +69,7 @@ u64 PS4_SYSV_ABI AvPlayer::SizeFile(void* handle) {
const auto size = self->m_init_data_original.file_replacement.size;
const auto ptr = self->m_init_data_original.file_replacement.object_ptr;
return Core::ExecuteGuest(size, ptr);
return size(ptr);
}
AvPlayerInitData AvPlayer::StubInitData(const AvPlayerInitData& data) {

View File

@ -92,7 +92,7 @@ void AvPlayerState::DefaultEventCallback(void* opaque, AvPlayerEvents event_id,
const auto callback = self->m_event_replacement.event_callback;
const auto ptr = self->m_event_replacement.object_ptr;
if (callback != nullptr) {
Core::ExecuteGuest(callback, ptr, event_id, 0, event_data);
callback(ptr, event_id, 0, event_data);
}
}

View File

@ -99,16 +99,16 @@ public:
if (m_ime_mode) {
OrbisImeParam param = m_param.ime;
if (use_param_handler) {
Core::ExecuteGuest(param.handler, param.arg, event);
param.handler(param.arg, event);
} else {
Core::ExecuteGuest(handler, param.arg, event);
handler(param.arg, event);
}
} else {
OrbisImeKeyboardParam param = m_param.key;
if (use_param_handler) {
Core::ExecuteGuest(param.handler, param.arg, event);
param.handler(param.arg, event);
} else {
Core::ExecuteGuest(handler, param.arg, event);
handler(param.arg, event);
}
}
}

View File

@ -131,8 +131,7 @@ bool ImeDialogState::CallTextFilter() {
return false;
}
int ret =
Core::ExecuteGuest(text_filter, out_text, &out_text_length, src_text, src_text_length);
int ret = text_filter(out_text, &out_text_length, src_text, src_text_length);
if (ret != 0) {
return false;
@ -153,7 +152,7 @@ bool ImeDialogState::CallKeyboardFilter(const OrbisImeKeycode* src_keycode, u16*
return true;
}
int ret = Core::ExecuteGuest(keyboard_filter, src_keycode, out_keycode, out_status, nullptr);
int ret = keyboard_filter(src_keycode, out_keycode, out_status, nullptr);
return ret == 0;
}

View File

@ -7,6 +7,17 @@
namespace Libraries::Kernel {
void PS4_SYSV_ABI ClearStack() {
void* const stackaddr_attr = Libraries::Kernel::g_curthread->attr.stackaddr_attr;
void* volatile sp;
asm("mov %%rsp, %0" : "=rm"(sp));
// leave a safety net of 64 bytes for memset
const size_t size = ((uintptr_t)sp - (uintptr_t)stackaddr_attr) - 64;
void* volatile buf = alloca(size);
memset(buf, 0, size);
sp = nullptr;
}
void RegisterThreads(Core::Loader::SymbolsResolver* sym) {
RegisterMutex(sym);
RegisterCond(sym);

View File

@ -27,6 +27,7 @@ int PS4_SYSV_ABI posix_pthread_create(PthreadT* thread, const PthreadAttrT* attr
PthreadEntryFunc start_routine, void* arg);
int PS4_SYSV_ABI posix_pthread_join(PthreadT pthread, void** thread_return);
int PS4_SYSV_ABI posix_pthread_detach(PthreadT pthread);
int PS4_SYSV_ABI posix_pthread_mutexattr_init(PthreadMutexAttrT* attr);
int PS4_SYSV_ABI posix_pthread_mutexattr_settype(PthreadMutexAttrT* attr, PthreadMutexType type);
@ -40,6 +41,8 @@ int PS4_SYSV_ABI posix_pthread_mutex_destroy(PthreadMutexT* mutex);
void RegisterThreads(Core::Loader::SymbolsResolver* sym);
void PS4_SYSV_ABI ClearStack();
class Thread {
public:
explicit Thread() = default;

View File

@ -317,7 +317,7 @@ int PS4_SYSV_ABI sceKernelRaiseException(PthreadT thread, int signum) {
u64 res = NtQueueApcThreadEx(reinterpret_cast<HANDLE>(thread->native_thr.GetHandle()), option,
ExceptionHandler, (void*)thread->name.c_str(),
(void*)native_signum, nullptr);
(void*)(s64)native_signum, nullptr);
ASSERT(res == 0);
#endif
return ORBIS_OK;

View File

@ -199,10 +199,17 @@ static void RunThread(void* arg) {
g_curthread = curthread;
Common::SetCurrentThreadName(curthread->name.c_str());
DebugState.AddCurrentThreadToGuestList();
Core::InitializeTLS();
curthread->native_thr.Initialize();
// Clear the stack before running the guest thread
if (False(g_curthread->attr.flags & PthreadAttrFlags::StackUser)) {
ClearStack();
}
/* Run the current thread's start routine with argument: */
curthread->native_thr.Initialize();
void* ret = Core::ExecuteGuest(curthread->start_routine, curthread->arg);
void* ret = curthread->start_routine(curthread->arg);
/* Remove thread from tracking */
DebugState.RemoveCurrentThreadFromGuestList();

View File

@ -84,7 +84,7 @@ void _thread_cleanupspecific() {
* destructor:
*/
lk.unlock();
Core::ExecuteGuest(destructor, data);
destructor(data);
lk.lock();
}
}

View File

@ -50,7 +50,7 @@ void NetCtlInternal::CheckCallback() {
: ORBIS_NET_CTL_EVENT_TYPE_DISCONNECTED;
for (const auto [func, arg] : callbacks) {
if (func != nullptr) {
Core::ExecuteGuest(func, event, arg);
func(event, arg);
}
}
}
@ -61,7 +61,7 @@ void NetCtlInternal::CheckNpToolkitCallback() {
: ORBIS_NET_CTL_EVENT_TYPE_DISCONNECTED;
for (const auto [func, arg] : nptool_callbacks) {
if (func != nullptr) {
Core::ExecuteGuest(func, event, arg);
func(event, arg);
}
}
}

View File

@ -160,13 +160,13 @@ s32 PS4_SYSV_ABI sceNgs2SystemCreateWithAllocator(const OrbisNgs2SystemOption* o
result = SystemSetup(option, &bufferInfo, 0, 0);
if (result >= 0) {
uintptr_t sysUserData = allocator->userData;
result = Core::ExecuteGuest(hostAlloc, &bufferInfo);
result = hostAlloc(&bufferInfo);
if (result >= 0) {
OrbisNgs2Handle* handleCopy = outHandle;
result = SystemSetup(option, &bufferInfo, hostFree, handleCopy);
if (result < 0) {
if (hostFree) {
Core::ExecuteGuest(hostFree, &bufferInfo);
hostFree(&bufferInfo);
}
}
}

View File

@ -3,6 +3,9 @@
#include "dimensions.h"
#include "core/libraries/kernel/threads.h"
#include "core/tls.h"
#include <mutex>
#include <thread>
@ -619,22 +622,46 @@ libusb_transfer_status DimensionsBackend::HandleAsyncTransfer(libusb_transfer* t
return LIBUSB_TRANSFER_COMPLETED;
}
struct WriteThreadArgs {
DimensionsBackend* self;
libusb_transfer* transfer;
};
void* PS4_SYSV_ABI DimensionsBackend::WriteThread(void* arg) {
auto* args = reinterpret_cast<WriteThreadArgs*>(arg);
auto* self = args->self;
auto* transfer = args->transfer;
self->HandleAsyncTransfer(transfer);
const u8 flags = transfer->flags;
transfer->status = LIBUSB_TRANSFER_COMPLETED;
transfer->actual_length = transfer->length;
if (transfer->callback) {
transfer->callback(transfer);
}
if (flags & LIBUSB_TRANSFER_FREE_TRANSFER) {
libusb_free_transfer(transfer);
}
delete args;
return nullptr;
}
s32 DimensionsBackend::SubmitTransfer(libusb_transfer* transfer) {
if (transfer->endpoint == 0x01) {
std::thread write_thread([this, transfer] {
HandleAsyncTransfer(transfer);
using namespace Libraries::Kernel;
PthreadAttrT attr{};
posix_pthread_attr_init(&attr);
PthreadT thread{};
auto* args = new WriteThreadArgs();
args->self = this;
args->transfer = transfer;
posix_pthread_create(&thread, &attr, HOST_CALL(DimensionsBackend::WriteThread), args);
posix_pthread_attr_destroy(&attr);
posix_pthread_detach(thread);
const u8 flags = transfer->flags;
transfer->status = LIBUSB_TRANSFER_COMPLETED;
transfer->actual_length = transfer->length;
if (transfer->callback) {
transfer->callback(transfer);
}
if (flags & LIBUSB_TRANSFER_FREE_TRANSFER) {
libusb_free_transfer(transfer);
}
});
write_thread.detach();
return LIBUSB_SUCCESS;
}

View File

@ -103,6 +103,8 @@ protected:
std::queue<std::array<u8, 32>> m_queries;
private:
static void* PS4_SYSV_ABI WriteThread(void* arg);
std::shared_ptr<DimensionsToypad> m_dimensions_toypad = std::make_shared<DimensionsToypad>();
std::array<u8, 9> m_endpoint_out_extra = {0x09, 0x21, 0x11, 0x01, 0x00, 0x01, 0x22, 0x1d, 0x00};

View File

@ -135,7 +135,8 @@ void Linker::Execute(const std::vector<std::string>& args) {
}
}
params.entry_addr = module->GetEntryAddress();
ExecuteGuest(RunMainEntry, &params);
Libraries::Kernel::ClearStack();
RunMainEntry(&params);
});
}
@ -379,8 +380,7 @@ void* Linker::TlsGetAddr(u64 module_index, u64 offset) {
if (!addr) {
// Module was just loaded by above code. Allocate TLS block for it.
const u32 init_image_size = module->tls.init_image_size;
u8* dest = reinterpret_cast<u8*>(
Core::ExecuteGuest(heap_api->heap_malloc, module->tls.image_size));
u8* dest = reinterpret_cast<u8*>(heap_api->heap_malloc(module->tls.image_size));
const u8* src = reinterpret_cast<const u8*>(module->tls.image_virtual_addr);
std::memcpy(dest, src, init_image_size);
std::memset(dest + init_image_size, 0, module->tls.image_size - init_image_size);
@ -412,7 +412,7 @@ void* Linker::AllocateTlsForThread(bool is_primary) {
ASSERT_MSG(ret == 0, "Unable to allocate TLS+TCB for the primary thread");
} else {
if (heap_api) {
addr_out = Core::ExecuteGuest(heap_api->heap_malloc, total_tls_size);
addr_out = heap_api->heap_malloc(total_tls_size);
} else {
addr_out = std::malloc(total_tls_size);
}
@ -422,7 +422,7 @@ void* Linker::AllocateTlsForThread(bool is_primary) {
void Linker::FreeTlsForNonPrimaryThread(void* pointer) {
if (heap_api) {
Core::ExecuteGuest(heap_api->heap_free, pointer);
heap_api->heap_free(pointer);
} else {
std::free(pointer);
}

View File

@ -97,7 +97,7 @@ Module::~Module() = default;
s32 Module::Start(u64 args, const void* argp, void* param) {
LOG_INFO(Core_Linker, "Module started : {}", name);
const VAddr addr = dynamic_info.init_virtual_addr + GetBaseAddress();
return ExecuteGuest(reinterpret_cast<EntryFunc>(addr), args, argp, param);
return reinterpret_cast<EntryFunc>(addr)(args, argp, param);
}
void Module::LoadModuleToMemory(u32& max_tls_index) {

View File

@ -198,7 +198,7 @@ Tcb* GetTcbBase() {
thread_local std::once_flag init_tls_flag;
void EnsureThreadInitialized() {
void InitializeTLS() {
std::call_once(init_tls_flag, [] { SetTcbBase(Libraries::Kernel::g_curthread->tcb); });
}

View File

@ -43,30 +43,7 @@ void SetTcbBase(void* image_address);
Tcb* GetTcbBase();
/// Makes sure TLS is initialized for the thread before entering guest.
void EnsureThreadInitialized();
template <size_t size>
#ifdef __clang__
__attribute__((optnone))
#else
__attribute__((optimize("O0")))
#endif
void ClearStack() {
volatile void* buf = alloca(size);
memset(const_cast<void*>(buf), 0, size);
buf = nullptr;
}
template <class ReturnType, class... FuncArgs, class... CallArgs>
ReturnType ExecuteGuest(PS4_SYSV_ABI ReturnType (*func)(FuncArgs...), CallArgs&&... args) {
EnsureThreadInitialized();
// clear stack to avoid trash from EnsureThreadInitialized
auto* tcb = GetTcbBase();
if (tcb != nullptr && tcb->tcb_fiber == nullptr) {
ClearStack<12_KB>();
}
return func(std::forward<CallArgs>(args)...);
}
void InitializeTLS();
template <class F, F f>
struct HostCallWrapperImpl;