diff --git a/CMakeLists.txt b/CMakeLists.txt index 913bf8123..d5cb24076 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -107,6 +107,7 @@ set(KERNEL_LIB src/core/libraries/kernel/event_flag/event_flag_obj.h src/core/libraries/kernel/threads/rwlock.cpp src/core/libraries/kernel/threads/semaphore.cpp + src/core/libraries/kernel/threads/keys.cpp src/core/libraries/kernel/threads/threads.h src/core/libraries/kernel/cpu_management.cpp src/core/libraries/kernel/cpu_management.h diff --git a/src/core/libraries/kernel/thread_management.cpp b/src/core/libraries/kernel/thread_management.cpp index 507f6c6ba..689a65a52 100644 --- a/src/core/libraries/kernel/thread_management.cpp +++ b/src/core/libraries/kernel/thread_management.cpp @@ -41,6 +41,7 @@ void init_pthreads() { scePthreadRwlockattrInit(&default_rwattr); g_pthread_cxt->setDefaultRwattr(default_rwattr); + g_pthread_cxt->setPthreadKeys(new PthreadKeys); g_pthread_cxt->SetPthreadPool(new PThreadPool); } @@ -1323,4 +1324,6 @@ void pthreadSymbolsRegister(Core::Loader::SymbolsResolver* sym) { SemaphoreSymbolsRegister(sym); } + + } // namespace Libraries::Kernel diff --git a/src/core/libraries/kernel/thread_management.h b/src/core/libraries/kernel/thread_management.h index a97def169..b0964fcaf 100644 --- a/src/core/libraries/kernel/thread_management.h +++ b/src/core/libraries/kernel/thread_management.h @@ -10,6 +10,7 @@ #include #include #include "common/types.h" +#include namespace Core::Loader { class SymbolsResolver; @@ -28,6 +29,7 @@ struct PthreadCondInternal; struct PthreadCondAttrInternal; struct PthreadRwInternal; struct PthreadRwLockAttrInernal; +class PthreadKeys; using SceKernelSchedParam = ::sched_param; using ScePthread = PthreadInternal*; @@ -38,6 +40,9 @@ using ScePthreadCond = PthreadCondInternal*; using ScePthreadCondattr = PthreadCondAttrInternal*; using OrbisPthreadRwlock = PthreadRwInternal*; using OrbisPthreadRwlockattr = PthreadRwLockAttrInernal*; +using OrbisPthreadKey = int; + +using PthreadKeyDestructor = PS4_SYSV_ABI void (*)(void*); using pthreadEntryFunc = PS4_SYSV_ABI void* (*)(void*); @@ -106,6 +111,30 @@ private: std::mutex m_mutex; }; +class PthreadKeys { +public: + PthreadKeys() {} + virtual ~PthreadKeys() {} + + bool CreateKey(int* key, PthreadKeyDestructor destructor); + bool GetKey(int key, int thread_id, void** data); + bool SetKey(int key, int thread_id, void* data); + +private: + struct Map { + int thread_id = -1; + void* data = nullptr; + }; + + struct Key { + bool used = false; + PthreadKeyDestructor destructor = nullptr; + std::vector specific_values; + }; + + std::mutex m_mutex; + Key m_keys[256]; +}; class PThreadCxt { public: ScePthreadMutexattr* getDefaultMutexattr() { @@ -138,6 +167,12 @@ public: void setDefaultRwattr(OrbisPthreadRwlockattr attr) { m_default_Rwattr = attr; } + PthreadKeys* getPthreadKeys() { + return m_pthread_keys; + } + void setPthreadKeys(PthreadKeys* keys) { + m_pthread_keys = keys; + } private: ScePthreadMutexattr m_default_mutexattr = nullptr; @@ -145,6 +180,7 @@ private: ScePthreadAttr m_default_attr = nullptr; PThreadPool* m_pthread_pool = nullptr; OrbisPthreadRwlockattr m_default_Rwattr = nullptr; + PthreadKeys* m_pthread_keys = nullptr; }; void init_pthreads(); diff --git a/src/core/libraries/kernel/threads/keys.cpp b/src/core/libraries/kernel/threads/keys.cpp new file mode 100644 index 000000000..777ef1167 --- /dev/null +++ b/src/core/libraries/kernel/threads/keys.cpp @@ -0,0 +1,102 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/logging/log.h" +#include "core/libraries/error_codes.h" +#include "core/libraries/libs.h" +#include "threads.h" + +namespace Libraries::Kernel { + +extern PThreadCxt* g_pthread_cxt; + +bool PthreadKeys::CreateKey(int* key, PthreadKeyDestructor destructor) { + std::scoped_lock lk{m_mutex}; + + for (int index = 0; index < 256; index++) { + if (!m_keys[index].used) { + *key = index; + m_keys[index].used = true; + m_keys[index].destructor = destructor; + m_keys[index].specific_values.clear(); + return true; + } + } + + return false; +} +bool PthreadKeys::GetKey(int key, int thread_id, void** data) { + std::scoped_lock lk{m_mutex}; + + if (key < 0 || key >= 256 || !m_keys[key].used) { + return false; + } + + for (auto& v : m_keys[key].specific_values) { + if (v.thread_id == thread_id) { + *data = v.data; + return true; + } + } + + *data = nullptr; + + return true; +} +bool PthreadKeys::SetKey(int key, int thread_id, void* data) { + std::scoped_lock lk{m_mutex}; + + if (key < 0 || key >= 256 || !m_keys[key].used) { + return false; + } + + for (auto& v : m_keys[key].specific_values) { + if (v.thread_id == thread_id) { + v.data = data; + return true; + } + } + + Map keymap = {thread_id, data}; + m_keys[key].specific_values.push_back(keymap); + + return true; +} + +int PS4_SYSV_ABI scePthreadKeyCreate(OrbisPthreadKey* key, PthreadKeyDestructor destructor) { + if (key == nullptr) { + return SCE_KERNEL_ERROR_EINVAL; + } + + if (!g_pthread_cxt->getPthreadKeys()->CreateKey(key, destructor)) { + return SCE_KERNEL_ERROR_EAGAIN; + } + + return SCE_OK; +} + +void* PS4_SYSV_ABI scePthreadGetspecific(OrbisPthreadKey key) { + auto id = std::this_thread::get_id(); + int thread_id = *(unsigned*)&id; + + void* value = nullptr; + if (!g_pthread_cxt->getPthreadKeys()->GetKey(key, thread_id, &value)) { + return nullptr; + } + + return value; +} + +int PS4_SYSV_ABI scePthreadSetspecific(OrbisPthreadKey key, /* const*/ void* value) { + + auto id = std::this_thread::get_id(); + int thread_id = *(unsigned*)&id; + + if (!g_pthread_cxt->getPthreadKeys()->SetKey(key, thread_id, value)) { + return SCE_KERNEL_ERROR_EINVAL; + } + + return SCE_OK; +} + +} // namespace Libraries::Kernel \ No newline at end of file