thread keys implementation

This commit is contained in:
georgemoralis 2023-10-05 12:17:14 +03:00
parent ab76f33733
commit 0297a3952b
3 changed files with 246 additions and 66 deletions

View File

@ -3,16 +3,22 @@
#include <Core/PS4/HLE/ErrorCodes.h>
#include <debug.h>
#include "Util/Singleton.h"
#include <inttypes.h>
namespace HLE::Libs::LibKernel::ThreadManagement {
thread_local PthreadInternal* g_pthread_self = nullptr;
PThreadCxt* g_pthread_cxt = nullptr;
void Pthread_Init_Self_MainThread() {
g_pthread_self = new PthreadInternal{};
scePthreadAttrInit(&g_pthread_self->attr);
g_pthread_self->pth = pthread_self();
g_pthread_self->name = "Main_Thread";
// temp!
auto* threadCtx = Singleton<PThreadCxt>::Instance();
threadCtx->setPthreadKeys(new PthreadKeys);
}
int PS4_SYSV_ABI scePthreadAttrInit(ScePthreadAttr* attr) {
@ -193,6 +199,7 @@ int PS4_SYSV_ABI scePthreadMutexInit(ScePthreadMutex* mutex, const ScePthreadMut
}
int PS4_SYSV_ABI scePthreadMutexLock(ScePthreadMutex* mutex) {
printf("scePthreadMutexLock\n");
static int count = 0;
std::string name = "internal mutex ";
name += std::to_string(count);
@ -211,6 +218,7 @@ int PS4_SYSV_ABI scePthreadMutexLock(ScePthreadMutex* mutex) {
}
}
int PS4_SYSV_ABI scePthreadMutexUnlock(ScePthreadMutex* mutex) {
printf("scePthreadMutexUnlock\n");
if (mutex == nullptr) {
return SCE_KERNEL_ERROR_EINVAL;
}
@ -227,7 +235,6 @@ int PS4_SYSV_ABI scePthreadMutexUnlock(ScePthreadMutex* mutex) {
}
int PS4_SYSV_ABI scePthreadCondattrInit(ScePthreadCondattr* attr) {
*attr = new PthreadCondAttrInternal{};
int result = pthread_condattr_init(&(*attr)->cond_attr);
@ -267,7 +274,6 @@ int PS4_SYSV_ABI scePthreadCondInit(ScePthreadCond* cond, const ScePthreadCondat
}
}
int PS4_SYSV_ABI scePthreadCondBroadcast(ScePthreadCond* cond) {
static int count = 0;
std::string name = "internal cond ";
name += std::to_string(count);
@ -286,4 +292,109 @@ int PS4_SYSV_ABI scePthreadCondBroadcast(ScePthreadCond* cond) {
return (result == 0 ? SCE_OK : SCE_KERNEL_ERROR_EINVAL);
}
bool PthreadKeys::createKey(int* key, PthreadKeyDestructor destructor) {
Lib::LockMutexGuard lock(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) {
Lib::LockMutexGuard lock(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) {
Lib::LockMutexGuard lock(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;
}
}
m_keys[key].specific_values.push_back(Map({thread_id, data}));
return true;
}
int PS4_SYSV_ABI scePthreadKeyCreate(ScePthreadKey* key, PthreadKeyDestructor destructor) {
if (key == nullptr) {
return SCE_KERNEL_ERROR_EINVAL;
}
auto* threadCtx = Singleton<PThreadCxt>::Instance();
if (!threadCtx->getPthreadKeys()->createKey(key, destructor)) {
return SCE_KERNEL_ERROR_EAGAIN;
}
printf("scePthreadKeyCreate\n");
printf("destructor = %016" PRIx64 "\n", reinterpret_cast<uint64_t>(destructor));
printf("key = %d\n", *key);
return SCE_OK;
}
void* PS4_SYSV_ABI scePthreadGetspecific(ScePthreadKey key) {
int thread_id = Lib::Thread::GetThreadIdUnique();
printf("scePthreadGetspecific\n");
printf("key = %d\n", key);
printf("thread_id = %d\n", thread_id);
void* value = nullptr;
auto* threadCtx = Singleton<PThreadCxt>::Instance();
if (!threadCtx->getPthreadKeys()->getKey(key, thread_id, &value)) {
return nullptr;
}
printf("value = %016" PRIx64 "\n", reinterpret_cast<uint64_t>(value));
return value;
}
int PS4_SYSV_ABI scePthreadSetspecific(ScePthreadKey key, /* const*/ void* value) {
int thread_id = Lib::Thread::GetThreadIdUnique();
printf("scePthreadSetspecific\n");
printf("key = %d\n", key);
printf("thread_id = %d\n", thread_id);
printf("value = %016" PRIx64 "\n", reinterpret_cast<uint64_t>(value));
auto* threadCtx = Singleton<PThreadCxt>::Instance();
if (!threadCtx->getPthreadKeys()->setKey(key, thread_id, value)) {
return SCE_KERNEL_ERROR_EINVAL;
}
return SCE_OK;
}
}; // namespace HLE::Libs::LibKernel::ThreadManagement

View File

@ -3,8 +3,9 @@
#include <pthread.h>
#include <sched.h>
#include <types.h>
#include <vector>
#include <string>
#include "Lib/Threads.h"
namespace HLE::Libs::LibKernel::ThreadManagement {
@ -14,6 +15,7 @@ struct PthreadMutexAttrInternal;
struct PthreadCondAttrInternal;
struct PthreadCondInternal;
struct PtheadOnceInternal;
class PthreadKeys;
using SceKernelSchedParam = ::sched_param;
using ScePthreadAttr = PthreadAttrInternal*;
@ -22,6 +24,9 @@ using ScePthreadMutexattr = PthreadMutexAttrInternal*;
using ScePthreadCondattr = PthreadCondAttrInternal*;
using ScePthreadCond = PthreadCondInternal*;
using ScePthreadOnce = PtheadOnceInternal*;
using ScePthreadKey = int;
using PthreadKeyDestructor = PS4_SYSV_ABI void (*)(void*);
struct PthreadInternal {
u08 reserved[4096];
@ -66,7 +71,38 @@ struct PtheadOnceInternal {
pthread_once_t pthreadOnce;
};
class PThreadCxt {};
class PThreadCxt {
public:
PthreadKeys* getPthreadKeys() { return m_pthread_keys; }
void setPthreadKeys(PthreadKeys* keys) { m_pthread_keys = keys; }
private:
PthreadKeys* m_pthread_keys = nullptr;
};
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<Map> specific_values;
};
Lib::Mutex m_mutex;
Key m_keys[256];
};
void Pthread_Init_Self_MainThread();
@ -86,4 +122,8 @@ int PS4_SYSV_ABI scePthreadCondattrInit(ScePthreadCondattr* attr);
int PS4_SYSV_ABI scePthreadCondBroadcast(ScePthreadCond* cond);
int PS4_SYSV_ABI scePthreadCondInit(ScePthreadCond* cond, const ScePthreadCondattr* attr, const char* name);
int PS4_SYSV_ABI scePthreadOnce(ScePthreadOnce* once_control, void (*init_routine)(void));
int PS4_SYSV_ABI scePthreadKeyCreate(ScePthreadKey* key, PthreadKeyDestructor destructor);
void* PS4_SYSV_ABI scePthreadGetspecific(ScePthreadKey key);
int PS4_SYSV_ABI scePthreadSetspecific(ScePthreadKey key, /* const*/ void* value);
} // namespace HLE::Libs::LibKernel::ThreadManagement

View File

@ -2,6 +2,9 @@
#include <Util/log.h>
#include <debug.h>
#include <io.h>
#include <sys/types.h>
#include <windows.h>
#include "../../../Util/Singleton.h"
#include "../Loader/Elf.h"
@ -11,9 +14,6 @@
#include "Kernel/event_queues.h"
#include "Kernel/memory_management.h"
#include "Libs.h"
#include <io.h>
#include <windows.h>
#include <sys/types.h>
namespace HLE::Libs::LibKernel {
@ -41,8 +41,10 @@ PS4_SYSV_ABI void _write() { BREAKPOINT(); }
PS4_SYSV_ABI void sigaction() { BREAKPOINT(); }
PS4_SYSV_ABI void _exit() { BREAKPOINT(); }
namespace POSIX {
PS4_SYSV_ABI int pthread_cond_broadcast(ThreadManagement::ScePthreadCond* cond) {
// posix call the difference is that there is a different behaviour when it doesn't return 0 or SCE_OK
// posix call the difference is that there is a different behaviour when it doesn't return 0 or SCE_OK
int result = ThreadManagement::scePthreadCondBroadcast(cond);
if (result != 0) {
BREAKPOINT();
@ -53,7 +55,15 @@ PS4_SYSV_ABI void pthread_rwlock_wrlock() { BREAKPOINT(); }
PS4_SYSV_ABI void pthread_cond_destroy() { BREAKPOINT(); }
PS4_SYSV_ABI void pthread_rwlock_rdlock() { BREAKPOINT(); }
PS4_SYSV_ABI void pthread_setspecific() { BREAKPOINT(); }
PS4_SYSV_ABI int pthread_setspecific(ThreadManagement::ScePthreadKey key, /* const*/ void* value) {
// posix call the difference is that there is a different behaviour when it doesn't return 0 or SCE_OK
int result = ThreadManagement::scePthreadSetspecific(key, value);
if (result != 0) {
BREAKPOINT();
}
return result;
}
PS4_SYSV_ABI void pthread_equal() { BREAKPOINT(); }
PS4_SYSV_ABI int pthread_mutex_unlock(ThreadManagement::ScePthreadMutex* mutex) {
// posix call the difference is that there is a different behaviour when it doesn't return 0 or SCE_OK
@ -63,8 +73,8 @@ PS4_SYSV_ABI int pthread_mutex_unlock(ThreadManagement::ScePthreadMutex* mutex)
}
return result;
}
PS4_SYSV_ABI void pthread_cond_timedwait() { BREAKPOINT(); }
PS4_SYSV_ABI void poll() { BREAKPOINT(); }
PS4_SYSV_ABI void pthread_rwlock_unlock() { BREAKPOINT(); }
PS4_SYSV_ABI void pthread_detach() { BREAKPOINT(); }
PS4_SYSV_ABI void pthread_mutexattr_init() { BREAKPOINT(); }
@ -76,10 +86,45 @@ int PS4_SYSV_ABI pthread_mutex_lock(ThreadManagement::ScePthreadMutex* mutex) {
}
return result;
}
PS4_SYSV_ABI void munmap() { BREAKPOINT(); }
PS4_SYSV_ABI void pthread_mutex_destroy() { BREAKPOINT(); }
PS4_SYSV_ABI void sceKernelUsleep() { BREAKPOINT(); }
PS4_SYSV_ABI void pthread_mutex_trylock() { BREAKPOINT(); }
PS4_SYSV_ABI void pthread_join() { BREAKPOINT(); }
PS4_SYSV_ABI void* pthread_getspecific(ThreadManagement::ScePthreadKey key) {
return HLE::Libs::LibKernel::ThreadManagement::scePthreadGetspecific(key);
}
PS4_SYSV_ABI void pthread_mutexattr_destroy() { BREAKPOINT(); }
PS4_SYSV_ABI void pthread_self() { BREAKPOINT(); }
PS4_SYSV_ABI void pthread_mutex_init() { BREAKPOINT(); }
PS4_SYSV_ABI int _pthread_once(ThreadManagement::ScePthreadOnce* once_control, void (*init_routine)(void)) {
// posix call the difference is that there is a different behaviour when it doesn't return 0 or SCE_OK
HLE::Libs::LibKernel::ThreadManagement::ScePthreadOnce o1nce_control = 0;
*once_control = new HLE::Libs::LibKernel::ThreadManagement::PtheadOnceInternal{};
(*once_control)->pthreadOnce = 0;
int result = pthread_once(&(*once_control)->pthreadOnce, init_routine);
if (result != 0) {
BREAKPOINT();
}
return result;
}
PS4_SYSV_ABI void pthread_cond_wait() { BREAKPOINT(); }
PS4_SYSV_ABI void pthread_mutexattr_settype() { BREAKPOINT(); }
int PS4_SYSV_ABI pthread_key_create(ThreadManagement::ScePthreadKey* key, ThreadManagement::PthreadKeyDestructor destructor) {
int result = HLE::Libs::LibKernel::ThreadManagement::scePthreadKeyCreate(key, destructor);
if (result != 0) {
BREAKPOINT();
}
return result;
}
PS4_SYSV_ABI void pthread_cond_signal() { BREAKPOINT(); }
}; // namespace POSIX
PS4_SYSV_ABI void poll() { BREAKPOINT(); }
PS4_SYSV_ABI void munmap() { BREAKPOINT(); }
PS4_SYSV_ABI void sceKernelUsleep() { BREAKPOINT(); }
#define PROT_READ 0x1
#define PROT_WRITE 0x2
@ -87,7 +132,7 @@ PS4_SYSV_ABI void pthread_mutex_trylock() { BREAKPOINT(); }
int PS4_SYSV_ABI sceKernelMmap(void* addr, u64 len, int prot, int flags, int fd, off_t offset, void** res) {
DWORD flProtect;
if (prot & PROT_WRITE) {
flProtect = PAGE_READWRITE;
flProtect = PAGE_READWRITE;
}
off_t end = len + offset;
@ -115,44 +160,28 @@ int PS4_SYSV_ABI sceKernelMmap(void* addr, u64 len, int prot, int flags, int fd,
}
PS4_SYSV_ABI int mmap(void* addr, u64 len, int prot, int flags, int fd, u64 offset, void** res) {
// posix call the difference is that there is a different behaviour when it doesn't return 0 or SCE_OK
int result = sceKernelMmap(addr, len, prot, flags, fd, offset,res);
// posix call the difference is that there is a different behaviour when it doesn't return 0 or SCE_OK
int result = sceKernelMmap(addr, len, prot, flags, fd, offset, res);
if (result != 0) {
BREAKPOINT();
}
return result;
}
PS4_SYSV_ABI void pthread_join() { BREAKPOINT(); }
PS4_SYSV_ABI void pthread_getspecific() { BREAKPOINT(); }
PS4_SYSV_ABI void pthread_mutexattr_destroy() { BREAKPOINT(); }
PS4_SYSV_ABI void pthread_self() { BREAKPOINT(); }
PS4_SYSV_ABI void close() { BREAKPOINT(); }
PS4_SYSV_ABI void pthread_mutexattr_settype() { BREAKPOINT(); }
PS4_SYSV_ABI void pthread_key_create() { BREAKPOINT(); }
PS4_SYSV_ABI void pthread_mutex_init() { BREAKPOINT(); }
PS4_SYSV_ABI void madvise() { BREAKPOINT(); }
PS4_SYSV_ABI void _writev() { BREAKPOINT(); }
PS4_SYSV_ABI void lseek() { BREAKPOINT(); }
PS4_SYSV_ABI int* __error() { return _errno(); }
PS4_SYSV_ABI int _pthread_once(ThreadManagement::ScePthreadOnce* once_control, void (*init_routine)(void)) {
// posix call the difference is that there is a different behaviour when it doesn't return 0 or SCE_OK
HLE::Libs::LibKernel::ThreadManagement::ScePthreadOnce o1nce_control = 0;
*once_control = new HLE::Libs::LibKernel::ThreadManagement::PtheadOnceInternal{};
(*once_control)->pthreadOnce = 0;
int result = pthread_once(&(*once_control)->pthreadOnce, init_routine);
if (result != 0) {
BREAKPOINT();
}
return result;
}
PS4_SYSV_ABI void pthread_cond_wait() { BREAKPOINT(); }
PS4_SYSV_ABI void raise() { BREAKPOINT(); }
PS4_SYSV_ABI void pthread_cond_signal() { BREAKPOINT(); }
PS4_SYSV_ABI void _ioctl() { BREAKPOINT(); }
PS4_SYSV_ABI void fstat() { BREAKPOINT(); }
void LibKernel_Register(SymbolsResolver* sym) {
// obj
LIB_OBJ("f7uOxY9mM1U", "libkernel", 1, "libkernel", 1, 1, &HLE::Libs::LibKernel::g_stack_chk_guard);
@ -191,40 +220,40 @@ void LibKernel_Register(SymbolsResolver* sym) {
LIB_FUNCTION("FxVZqBAA7ks", "libkernel", 1, "libkernel", 1, 1, _write);
LIB_FUNCTION("KiJEPEWRyUY", "libkernel", 1, "libkernel", 1, 1, sigaction);
LIB_FUNCTION("6Z83sYWFlA8", "libkernel", 1, "libkernel", 1, 1, _exit);
LIB_FUNCTION("mkx2fVhNMsg", "libkernel", 1, "libkernel", 1, 1, pthread_cond_broadcast);
LIB_FUNCTION("sIlRvQqsN2Y", "libkernel", 1, "libkernel", 1, 1, pthread_rwlock_wrlock);
LIB_FUNCTION("RXXqi4CtF8w", "libkernel", 1, "libkernel", 1, 1, pthread_cond_destroy);
LIB_FUNCTION("iGjsr1WAtI0", "libkernel", 1, "libkernel", 1, 1, pthread_rwlock_rdlock);
LIB_FUNCTION("WrOLvHU0yQM", "libkernel", 1, "libkernel", 1, 1, pthread_setspecific);
LIB_FUNCTION("7Xl257M4VNI", "libkernel", 1, "libkernel", 1, 1, pthread_equal);
LIB_FUNCTION("2Z+PpY6CaJg", "libkernel", 1, "libkernel", 1, 1, pthread_mutex_unlock);
LIB_FUNCTION("27bAgiJmOh0", "libkernel", 1, "libkernel", 1, 1, pthread_cond_timedwait);
LIB_FUNCTION("mkx2fVhNMsg", "libkernel", 1, "libkernel", 1, 1, POSIX::pthread_cond_broadcast);
LIB_FUNCTION("sIlRvQqsN2Y", "libkernel", 1, "libkernel", 1, 1, POSIX::pthread_rwlock_wrlock);
LIB_FUNCTION("RXXqi4CtF8w", "libkernel", 1, "libkernel", 1, 1, POSIX::pthread_cond_destroy);
LIB_FUNCTION("iGjsr1WAtI0", "libkernel", 1, "libkernel", 1, 1, POSIX::pthread_rwlock_rdlock);
LIB_FUNCTION("WrOLvHU0yQM", "libkernel", 1, "libkernel", 1, 1, POSIX::pthread_setspecific);
LIB_FUNCTION("7Xl257M4VNI", "libkernel", 1, "libkernel", 1, 1, POSIX::pthread_equal);
LIB_FUNCTION("2Z+PpY6CaJg", "libkernel", 1, "libkernel", 1, 1, POSIX::pthread_mutex_unlock);
LIB_FUNCTION("27bAgiJmOh0", "libkernel", 1, "libkernel", 1, 1, POSIX::pthread_cond_timedwait);
LIB_FUNCTION("ku7D4q1Y9PI", "libkernel", 1, "libkernel", 1, 1, poll);
LIB_FUNCTION("EgmLo6EWgso", "libkernel", 1, "libkernel", 1, 1, pthread_rwlock_unlock);
LIB_FUNCTION("+U1R4WtXvoc", "libkernel", 1, "libkernel", 1, 1, pthread_detach);
LIB_FUNCTION("dQHWEsJtoE4", "libkernel", 1, "libkernel", 1, 1, pthread_mutexattr_init);
LIB_FUNCTION("7H0iTOciTLo", "libkernel", 1, "libkernel", 1, 1, pthread_mutex_lock);
LIB_FUNCTION("EgmLo6EWgso", "libkernel", 1, "libkernel", 1, 1, POSIX::pthread_rwlock_unlock);
LIB_FUNCTION("+U1R4WtXvoc", "libkernel", 1, "libkernel", 1, 1, POSIX::pthread_detach);
LIB_FUNCTION("dQHWEsJtoE4", "libkernel", 1, "libkernel", 1, 1, POSIX::pthread_mutexattr_init);
LIB_FUNCTION("7H0iTOciTLo", "libkernel", 1, "libkernel", 1, 1, POSIX::pthread_mutex_lock);
LIB_FUNCTION("UqDGjXA5yUM", "libkernel", 1, "libkernel", 1, 1, munmap);
LIB_FUNCTION("ltCfaGr2JGE", "libkernel", 1, "libkernel", 1, 1, pthread_mutex_destroy);
LIB_FUNCTION("ltCfaGr2JGE", "libkernel", 1, "libkernel", 1, 1, POSIX::pthread_mutex_destroy);
LIB_FUNCTION("1jfXLRVzisc", "libkernel", 1, "libkernel", 1, 1, sceKernelUsleep);
LIB_FUNCTION("K-jXhbt2gn4", "libkernel", 1, "libkernel", 1, 1, pthread_mutex_trylock);
LIB_FUNCTION("K-jXhbt2gn4", "libkernel", 1, "libkernel", 1, 1, POSIX::pthread_mutex_trylock);
LIB_FUNCTION("BPE9s9vQQXo", "libkernel", 1, "libkernel", 1, 1, mmap);
LIB_FUNCTION("h9CcP3J0oVM", "libkernel", 1, "libkernel", 1, 1, pthread_join);
LIB_FUNCTION("0-KXaS70xy4", "libkernel", 1, "libkernel", 1, 1, pthread_getspecific);
LIB_FUNCTION("HF7lK46xzjY", "libkernel", 1, "libkernel", 1, 1, pthread_mutexattr_destroy);
LIB_FUNCTION("EotR8a3ASf4", "libkernel", 1, "libkernel", 1, 1, pthread_self);
LIB_FUNCTION("h9CcP3J0oVM", "libkernel", 1, "libkernel", 1, 1, POSIX::pthread_join);
LIB_FUNCTION("0-KXaS70xy4", "libkernel", 1, "libkernel", 1, 1, POSIX::pthread_getspecific);
LIB_FUNCTION("HF7lK46xzjY", "libkernel", 1, "libkernel", 1, 1, POSIX::pthread_mutexattr_destroy);
LIB_FUNCTION("EotR8a3ASf4", "libkernel", 1, "libkernel", 1, 1, POSIX::pthread_self);
LIB_FUNCTION("bY-PO6JhzhQ", "libkernel", 1, "libkernel", 1, 1, close);
LIB_FUNCTION("mDmgMOGVUqg", "libkernel", 1, "libkernel", 1, 1, pthread_mutexattr_settype);
LIB_FUNCTION("mqULNdimTn0", "libkernel", 1, "libkernel", 1, 1, pthread_key_create);
LIB_FUNCTION("ttHNfU+qDBU", "libkernel", 1, "libkernel", 1, 1, pthread_mutex_init);
LIB_FUNCTION("mDmgMOGVUqg", "libkernel", 1, "libkernel", 1, 1, POSIX::pthread_mutexattr_settype);
LIB_FUNCTION("mqULNdimTn0", "libkernel", 1, "libkernel", 1, 1, POSIX::pthread_key_create);
LIB_FUNCTION("ttHNfU+qDBU", "libkernel", 1, "libkernel", 1, 1, POSIX::pthread_mutex_init);
LIB_FUNCTION("Jahsnh4KKkg", "libkernel", 1, "libkernel", 1, 1, madvise);
LIB_FUNCTION("YSHRBRLn2pI", "libkernel", 1, "libkernel", 1, 1, _writev);
LIB_FUNCTION("Oy6IpwgtYOk", "libkernel", 1, "libkernel", 1, 1, lseek);
LIB_FUNCTION("9BcDykPmo1I", "libkernel", 1, "libkernel", 1, 1, __error);
LIB_FUNCTION("Z4QosVuAsA0", "libkernel", 1, "libkernel", 1, 1, _pthread_once);
LIB_FUNCTION("Op8TBGY5KHg", "libkernel", 1, "libkernel", 1, 1, pthread_cond_wait);
LIB_FUNCTION("Z4QosVuAsA0", "libkernel", 1, "libkernel", 1, 1, POSIX::_pthread_once);
LIB_FUNCTION("Op8TBGY5KHg", "libkernel", 1, "libkernel", 1, 1, POSIX::pthread_cond_wait);
LIB_FUNCTION("0t0-MxQNwK4", "libkernel", 1, "libkernel", 1, 1, raise);
LIB_FUNCTION("2MOy+rUfuhQ", "libkernel", 1, "libkernel", 1, 1, pthread_cond_signal);
LIB_FUNCTION("2MOy+rUfuhQ", "libkernel", 1, "libkernel", 1, 1, POSIX::pthread_cond_signal);
LIB_FUNCTION("wW+k21cmbwQ", "libkernel", 1, "libkernel", 1, 1, _ioctl);
}