kernel: index pthread key values per thread

This commit is contained in:
nmzik
2026-09-11 13:14:30 +04:00
parent 73363f1272
commit 733842cad4
+84 -175
View File
@@ -17,14 +17,18 @@
#include "loader/timer.h"
#include <algorithm>
#include <array>
#include <atomic>
#include <cerrno>
#include <chrono>
#include <condition_variable>
#include <cstring>
#include <ctime>
#include <memory>
#include <mutex>
#include <new>
#include <thread>
#include <utility>
#include <vector>
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
@@ -612,35 +616,21 @@ private:
Common::Mutex m_mutex;
};
class PthreadKeys {
public:
PthreadKeys() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); }
virtual ~PthreadKeys() { KYTY_NOT_IMPLEMENTED; }
KYTY_CLASS_NO_COPY(PthreadKeys);
bool Create(int* key, pthread_key_destructor_func_t destructor);
bool Delete(int key);
void Destruct(int thread_id);
bool Set(int key, int thread_id, void* data);
bool Get(int key, int thread_id, void** data);
private:
struct Map {
int thread_id = -1;
void* data = nullptr;
};
struct Key {
bool used = false;
pthread_key_destructor_func_t destructor = nullptr;
std::vector<Map> specific_values;
};
Common::Mutex m_mutex;
Key m_keys[KEYS_MAX];
struct PthreadSpecificValue {
uint64_t generation = 0;
void* data = nullptr;
};
struct PthreadKeyState {
// Odd generations are allocated; deletion advances to the next even generation.
std::atomic<uint64_t> generation {0};
pthread_key_destructor_func_t destructor = nullptr;
};
static std::array<PthreadKeyState, KEYS_MAX> g_pthread_keys;
static std::mutex g_pthread_keys_mutex;
static thread_local std::unique_ptr<PthreadSpecificValue[]> g_pthread_specific;
class PthreadPool {
public:
PthreadPool() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); }
@@ -676,8 +666,6 @@ public:
void SetPthreadPool(PthreadPool* pool) { m_pthread_pool = pool; }
PthreadStaticObjects* GetPthreadStaticObjects() { return m_pthread_static_objects; }
void SetPthreadStaticObjects(PthreadStaticObjects* objs) { m_pthread_static_objects = objs; }
PthreadKeys* GetPthreadKeys() { return m_pthread_keys; }
void SetPthreadKeys(PthreadKeys* keys) { m_pthread_keys = keys; }
[[nodiscard]] thread_dtors_func_t GetThreadDtors() const { return m_thread_dtors; }
void SetThreadDtors(thread_dtors_func_t dtors) { m_thread_dtors = dtors; }
@@ -690,7 +678,6 @@ private:
PthreadAttr m_default_attr = nullptr;
PthreadPool* m_pthread_pool = nullptr;
PthreadStaticObjects* m_pthread_static_objects = nullptr;
PthreadKeys* m_pthread_keys = nullptr;
std::atomic<thread_dtors_func_t> m_thread_dtors = nullptr;
};
@@ -1140,7 +1127,6 @@ void Initialize() {
g_pthread_context->SetPthreadStaticObjects(new PthreadStaticObjects);
g_pthread_context->SetPthreadPool(new PthreadPool);
g_pthread_context->SetPthreadKeys(new PthreadKeys);
Common::CondVar::SetWaitPollCallback(KernelDispatchPendingSignalForCurrentThread);
PthreadMutexattr default_mutexattr = nullptr;
@@ -1600,119 +1586,37 @@ void PthreadPool::FreeDetachedThreads() {
}
}
bool PthreadKeys::Create(int* key, pthread_key_destructor_func_t destructor) {
EXIT_IF(key == nullptr);
Common::LockGuard lock(m_mutex);
for (int index = 0; index < KEYS_MAX; 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;
}
static void DestructPthreadSpecific() {
if (g_pthread_specific == nullptr) {
return;
}
return false;
}
bool PthreadKeys::Delete(int key) {
Common::LockGuard lock(m_mutex);
if (key < 0 || key >= KEYS_MAX || !m_keys[key].used) {
return false;
}
m_keys[key].used = false;
m_keys[key].destructor = nullptr;
m_keys[key].specific_values.clear();
return true;
}
void PthreadKeys::Destruct(int thread_id) {
struct CallInfo {
pthread_key_destructor_func_t destructor;
void* data;
};
std::unique_lock lock(g_pthread_keys_mutex);
for (int iter = 0; iter < DESTRUCTOR_ITERATIONS; iter++) {
std::vector<CallInfo> delete_list;
{
Common::LockGuard lock(m_mutex);
for (auto& key: m_keys) {
if (key.used && key.destructor != nullptr) {
for (auto& v: key.specific_values) {
if (v.thread_id == thread_id && v.data != nullptr) {
delete_list.push_back(CallInfo {key.destructor, v.data});
v.data = nullptr;
}
}
}
bool called = false;
for (int index = 0; index < KEYS_MAX; index++) {
const auto value = std::exchange(g_pthread_specific[index], {});
if (value.data == nullptr) {
continue;
}
}
if (delete_list.empty()) {
return;
const auto& entry = g_pthread_keys[index];
const auto generation = entry.generation.load(std::memory_order_relaxed);
if ((generation & 1u) == 0 || generation != value.generation ||
entry.destructor == nullptr) {
continue;
}
const auto destructor = entry.destructor;
lock.unlock();
destructor(value.data);
lock.lock();
called = true;
}
for (auto& d: delete_list) {
d.destructor(d.data);
if (!called) {
break;
}
}
Common::LockGuard lock(m_mutex);
for (auto& key: m_keys) {
auto& values = key.specific_values;
values.erase(std::remove_if(values.begin(), values.end(),
[thread_id](const Map& v) { return v.thread_id == thread_id; }),
values.end());
}
}
bool PthreadKeys::Set(int key, int thread_id, void* data) {
Common::LockGuard lock(m_mutex);
if (key < 0 || key >= KEYS_MAX || !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;
}
}
m_keys[key].specific_values.push_back(Map({thread_id, data}));
return true;
}
bool PthreadKeys::Get(int key, int thread_id, void** data) {
EXIT_IF(data == nullptr);
Common::LockGuard lock(m_mutex);
if (key < 0 || key >= KEYS_MAX || !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;
g_pthread_specific.reset();
}
int KYTY_SYSV_ABI PthreadMutexattrInit(PthreadMutexattr* attr) {
@@ -3380,7 +3284,7 @@ static void CleanupThread(void* arg) {
thread_dtors();
}
g_pthread_context->GetPthreadKeys()->Destruct(thread->unique_id);
DestructPthreadSpecific();
auto* rt = Common::Singleton<Loader::RuntimeLinker>::Instance();
rt->DeleteTlss(thread->unique_id);
@@ -4096,62 +4000,71 @@ int KYTY_SYSV_ABI KernelNanosleep(const KernelTimespec* rqtp, KernelTimespec* rm
}
int KYTY_SYSV_ABI PthreadKeyCreate(PthreadKey* key, pthread_key_destructor_func_t destructor) {
PRINT_NAME();
if (key == nullptr) {
return KERNEL_ERROR_EINVAL;
}
if (!g_pthread_context->GetPthreadKeys()->Create(key, destructor)) {
return KERNEL_ERROR_EAGAIN;
std::lock_guard lock(g_pthread_keys_mutex);
for (int index = 0; index < KEYS_MAX; index++) {
auto& entry = g_pthread_keys[index];
const auto generation = entry.generation.load(std::memory_order_relaxed);
if ((generation & 1u) == 0) {
entry.destructor = destructor;
entry.generation.store(generation + 1, std::memory_order_release);
*key = index;
return OK;
}
}
LOGF("\t destructor = %016" PRIx64 "\n"
"\t key = %d\n",
reinterpret_cast<uint64_t>(destructor), *key);
return OK;
return KERNEL_ERROR_EAGAIN;
}
int KYTY_SYSV_ABI PthreadKeyDelete(PthreadKey key) {
PRINT_NAME();
LOGF("\t key = %d\n", key);
if (!g_pthread_context->GetPthreadKeys()->Delete(key)) {
if (key < 0 || key >= KEYS_MAX) {
return KERNEL_ERROR_EINVAL;
}
std::lock_guard lock(g_pthread_keys_mutex);
auto& entry = g_pthread_keys[key];
const auto generation = entry.generation.load(std::memory_order_relaxed);
if ((generation & 1u) == 0) {
return KERNEL_ERROR_EINVAL;
}
entry.generation.store(generation + 1, std::memory_order_release);
entry.destructor = nullptr;
return OK;
}
int KYTY_SYSV_ABI PthreadSetspecific(PthreadKey key, void* value) {
// PRINT_NAME();
int thread_id = Common::Thread::GetThreadIdUnique();
LOGF("\t key = %d\n"
"\t thread_id = %d\n"
"\t value = %016" PRIx64 "\n",
key, thread_id, reinterpret_cast<uint64_t>(value));
if (!g_pthread_context->GetPthreadKeys()->Set(key, thread_id, value)) {
if (key < 0 || key >= KEYS_MAX) {
return KERNEL_ERROR_EINVAL;
}
const auto generation = g_pthread_keys[key].generation.load(std::memory_order_acquire);
if ((generation & 1u) == 0) {
return KERNEL_ERROR_EINVAL;
}
if (g_pthread_specific == nullptr) {
if (value == nullptr) {
return OK;
}
g_pthread_specific.reset(new (std::nothrow) PthreadSpecificValue[KEYS_MAX] {});
if (g_pthread_specific == nullptr) {
return KERNEL_ERROR_ENOMEM;
}
}
g_pthread_specific[key] = {generation, value};
return OK;
}
void* KYTY_SYSV_ABI PthreadGetspecific(PthreadKey key) {
int thread_id = Common::Thread::GetThreadIdUnique();
void* value = nullptr;
if (!g_pthread_context->GetPthreadKeys()->Get(key, thread_id, &value)) {
if (key < 0 || key >= KEYS_MAX || g_pthread_specific == nullptr) {
return nullptr;
}
return value;
const auto generation = g_pthread_keys[key].generation.load(std::memory_order_acquire);
const auto& value = g_pthread_specific[key];
if ((generation & 1u) != 0 && generation == value.generation) {
return value.data;
}
return nullptr;
}
} // namespace LibKernel
@@ -4581,15 +4494,11 @@ int KYTY_SYSV_ABI pthread_key_delete(LibKernel::PthreadKey key) {
}
int KYTY_SYSV_ABI pthread_setspecific(LibKernel::PthreadKey key, void* value) {
PRINT_NAME();
return POSIX_PTHREAD_CALL(LibKernel::PthreadSetspecific(key, value));
}
void* KYTY_SYSV_ABI pthread_getspecific(LibKernel::PthreadKey key) {
PRINT_NAME();
return (LibKernel::PthreadGetspecific(key));
return LibKernel::PthreadGetspecific(key);
}
int KYTY_SYSV_ABI pthread_mutex_destroy(LibKernel::PthreadMutex* mutex) {