Merge pull request #8885 from hypermoist/feat/libc-sce-v2-thread-sync

feat(libc): add the std::__sce_v2 mutex, condition and thread calls
This commit is contained in:
Dean authored and GitHub committed 2026-10-24 21:09:55 +13:00
commit aeeaefad98
4 files changed
+261

No files matched your search

+19
View File
@@ -70,6 +70,25 @@ struct ThreadForwards_nid_no_patch {
void (APS5_VABI* exit)(void*);
};
extern "C" void RegisterThreadForwards_nid_no_patch(const ThreadForwards_nid_no_patch* forwards);
struct PthreadSyncForwards_nid_no_patch {
int (APS5_VABI* mutexattrInit)(void**);
int (APS5_VABI* mutexattrSettype)(void**, int);
int (APS5_VABI* mutexattrDestroy)(void**);
int (APS5_VABI* mutexInit)(void**, void* const*, const char*);
int (APS5_VABI* mutexDestroy)(void**);
int (APS5_VABI* mutexLock)(void**);
int (APS5_VABI* mutexTrylock)(void**);
int (APS5_VABI* mutexUnlock)(void**);
int (APS5_VABI* condInit)(void**, void* const*, const char*);
int (APS5_VABI* condDestroy)(void**);
int (APS5_VABI* condWait)(void**, void**);
int (APS5_VABI* condSignal)(void**);
int (APS5_VABI* condBroadcast)(void**);
int (APS5_VABI* detach)(void*);
int (APS5_VABI* join)(void*, void**);
void (APS5_VABI* yield)();
};
extern "C" void RegisterPthreadSyncForwards_nid_no_patch(const PthreadSyncForwards_nid_no_patch* forwards);
#define APS5_INVALID_ARG_EX throw std::invalid_argument(std::string(__func__) + ": invalid argument")
+118
View File
@@ -554,5 +554,123 @@ int APS5_VABI _Mtx_current_owns_nid_postfix(void**) {
return 1;
}
static std::atomic<const PthreadSyncForwards_nid_no_patch*> registeredPthreadSyncForwards{nullptr};
void RegisterPthreadSyncForwards_nid_no_patch(const PthreadSyncForwards_nid_no_patch* forwards) {
registeredPthreadSyncForwards.store(forwards, std::memory_order_release);
}
static const PthreadSyncForwards_nid_no_patch& PthreadSync(const char* function) {
const auto* forwards = registeredPthreadSyncForwards.load(std::memory_order_acquire);
if (!forwards) throw std::runtime_error(std::string(function) + ": libkernel synchronization is not registered");
return *forwards;
}
constexpr int KernelDeadlock = static_cast<int>(0x8002000b);
constexpr int KernelNoMemory = static_cast<int>(0x8002000c);
constexpr int KernelBusy = static_cast<int>(0x80020010);
constexpr int RecursiveMutexType = 0x100;
constexpr int KernelRecursiveMutex = 2;
static int CreateResult(int result) {
if (result == 0) return threadSuccess;
return result == KernelNoMemory ? threadNomem : threadError;
}
static const char* SyncObjectName(const char* name) {
return name != nullptr && name[0] != '\0' ? name : nullptr;
}
int APS5_VABI _ZNSt8__sce_v219_Mtx_init_with_nameEPP13pthread_mutexiPKc_nid_postfix(void** mutex, int type, const char* name) {
const auto& sync = PthreadSync(__func__);
*mutex = nullptr;
void* attr = nullptr;
const int created = sync.mutexattrInit(&attr);
if (created != 0) return CreateResult(created);
if ((type & RecursiveMutexType) != 0 && sync.mutexattrSettype(&attr, KernelRecursiveMutex) != 0) {
sync.mutexattrDestroy(&attr);
return threadError;
}
const int initialized = sync.mutexInit(mutex, &attr, SyncObjectName(name));
const int released = sync.mutexattrDestroy(&attr);
if (initialized != 0) return CreateResult(initialized);
if (released != 0) {
sync.mutexDestroy(mutex);
return threadError;
}
return threadSuccess;
}
int APS5_VABI _ZNSt8__sce_v29_Mtx_initEPP13pthread_mutexi_nid_postfix(void** mutex, int type) {
return _ZNSt8__sce_v219_Mtx_init_with_nameEPP13pthread_mutexiPKc_nid_postfix(mutex, type, "SceLibcI_Mtx");
}
int APS5_VABI _ZNSt8__sce_v212_Mtx_destroyEPP13pthread_mutex_nid_postfix(void** mutex) {
return PthreadSync(__func__).mutexDestroy(mutex);
}
int APS5_VABI _ZNSt8__sce_v29_Mtx_lockEPP13pthread_mutex_nid_postfix(void** mutex) {
const int result = PthreadSync(__func__).mutexLock(mutex);
if (result == 0) return threadSuccess;
return result == KernelDeadlock ? threadBusy : threadError;
}
int APS5_VABI _ZNSt8__sce_v212_Mtx_trylockEPP13pthread_mutex_nid_postfix(void** mutex) {
const int result = PthreadSync(__func__).mutexTrylock(mutex);
if (result == 0) return threadSuccess;
return result == KernelBusy ? threadBusy : threadError;
}
int APS5_VABI _ZNSt8__sce_v211_Mtx_unlockEPP13pthread_mutex_nid_postfix(void** mutex) {
PthreadSync(__func__).mutexUnlock(mutex);
return threadSuccess;
}
int APS5_VABI _ZNSt8__sce_v219_Cnd_init_with_nameEPP12pthread_condPKc_nid_postfix(void** condition, const char* name) {
return CreateResult(PthreadSync(__func__).condInit(condition, nullptr, SyncObjectName(name)));
}
int APS5_VABI _ZNSt8__sce_v29_Cnd_initEPP12pthread_cond_nid_postfix(void** condition) {
return CreateResult(PthreadSync(__func__).condInit(condition, nullptr, "SceLibcI_Cnd"));
}
int APS5_VABI _ZNSt8__sce_v212_Cnd_destroyEPP12pthread_cond_nid_postfix(void** condition) {
return PthreadSync(__func__).condDestroy(condition);
}
int APS5_VABI _ZNSt8__sce_v29_Cnd_waitEPP12pthread_condPP13pthread_mutex_nid_postfix(void** condition, void** mutex) {
PthreadSync(__func__).condWait(condition, mutex);
return threadSuccess;
}
int APS5_VABI _ZNSt8__sce_v211_Cnd_signalEPP12pthread_cond_nid_postfix(void** condition) {
PthreadSync(__func__).condSignal(condition);
return threadSuccess;
}
int APS5_VABI _ZNSt8__sce_v214_Cnd_broadcastEPP12pthread_cond_nid_postfix(void** condition) {
PthreadSync(__func__).condBroadcast(condition);
return threadSuccess;
}
int APS5_VABI _ZNSt8__sce_v212_Thrd_detachEP7pthread_nid_postfix(void* thread) {
return PthreadSync(__func__).detach(thread) == 0 ? threadSuccess : threadError;
}
int APS5_VABI _ZNSt8__sce_v210_Thrd_joinEP7pthreadPi_nid_postfix(void* thread, int* code) {
void* result = nullptr;
if (PthreadSync(__func__).join(thread, &result) != 0) return threadError;
if (code) *code = static_cast<int>(reinterpret_cast<std::intptr_t>(result));
return threadSuccess;
}
void APS5_VABI _ZNSt8__sce_v211_Thrd_yieldEv_nid_postfix() {
PthreadSync(__func__).yield();
}
void* APS5_VABI _ZNSt8__sce_v28_Thrd_idEv_nid_postfix() {
return _Thrd_current_nid_postfix();
}
}
@@ -28,6 +28,19 @@ int APS5_VABI scePthreadKeyCreate(PthreadKey* key, pthread_key_destructor_func_t
int APS5_VABI scePthreadKeyDelete(PthreadKey key);
void* APS5_VABI scePthreadGetspecific(PthreadKey key);
int APS5_VABI scePthreadSetspecific(PthreadKey key, void* value);
int APS5_VABI scePthreadMutexattrInit(PthreadMutexattr* attr);
int APS5_VABI scePthreadMutexattrSettype(PthreadMutexattr* attr, int type);
int APS5_VABI scePthreadMutexattrDestroy(PthreadMutexattr* attr);
int APS5_VABI scePthreadMutexInit(PthreadMutex* mutex, const PthreadMutexattr* attr, const char* name);
int APS5_VABI scePthreadMutexDestroy(PthreadMutex* mutex);
int APS5_VABI scePthreadMutexLock(PthreadMutex* mutex);
int APS5_VABI scePthreadMutexTrylock(PthreadMutex* mutex);
int APS5_VABI scePthreadMutexUnlock(PthreadMutex* mutex);
int APS5_VABI scePthreadCondInit(PthreadCond* cond, const PthreadCondattr* attr, const char* name);
int APS5_VABI scePthreadCondDestroy(PthreadCond* cond);
int APS5_VABI scePthreadCondWait(PthreadCond* cond, PthreadMutex* mutex);
int APS5_VABI scePthreadCondSignal(PthreadCond* cond);
int APS5_VABI scePthreadCondBroadcast(PthreadCond* cond);
int APS5_VABI scePthreadCancel(Pthread thread);
int APS5_VABI scePthreadSetcancelstate(int state, int* old_state);
int APS5_VABI scePthreadSetcanceltype(int type, int* old_type);
@@ -265,6 +278,25 @@ struct RegisterPthreadOnLoad {
scePthreadExit,
};
RegisterThreadForwards_nid_no_patch(&forwards);
static const PthreadSyncForwards_nid_no_patch sync{
reinterpret_cast<decltype(sync.mutexattrInit)>(scePthreadMutexattrInit),
reinterpret_cast<decltype(sync.mutexattrSettype)>(scePthreadMutexattrSettype),
reinterpret_cast<decltype(sync.mutexattrDestroy)>(scePthreadMutexattrDestroy),
reinterpret_cast<decltype(sync.mutexInit)>(scePthreadMutexInit),
reinterpret_cast<decltype(sync.mutexDestroy)>(scePthreadMutexDestroy),
reinterpret_cast<decltype(sync.mutexLock)>(scePthreadMutexLock),
reinterpret_cast<decltype(sync.mutexTrylock)>(scePthreadMutexTrylock),
reinterpret_cast<decltype(sync.mutexUnlock)>(scePthreadMutexUnlock),
reinterpret_cast<decltype(sync.condInit)>(scePthreadCondInit),
reinterpret_cast<decltype(sync.condDestroy)>(scePthreadCondDestroy),
reinterpret_cast<decltype(sync.condWait)>(scePthreadCondWait),
reinterpret_cast<decltype(sync.condSignal)>(scePthreadCondSignal),
reinterpret_cast<decltype(sync.condBroadcast)>(scePthreadCondBroadcast),
reinterpret_cast<decltype(sync.detach)>(scePthreadDetach),
reinterpret_cast<decltype(sync.join)>(scePthreadJoin),
scePthreadYield,
};
RegisterPthreadSyncForwards_nid_no_patch(&sync);
}
};
const RegisterPthreadOnLoad gRegisterPthread;
+92
View File
@@ -54,6 +54,25 @@ int APS5_VABI _Tss_set_nid_postfix(int key, void* value);
int APS5_VABI _Thrd_equal_nid_postfix(void* first, void* second);
void* APS5_VABI _Thrd_current_nid_postfix(void);
int APS5_VABI _Mtx_current_owns_nid_postfix(void** handle);
int APS5_VABI _ZNSt8__sce_v29_Mtx_initEPP13pthread_mutexi_nid_postfix(void** mutex, int type);
int APS5_VABI _ZNSt8__sce_v219_Mtx_init_with_nameEPP13pthread_mutexiPKc_nid_postfix(void** mutex, int type, const char* name);
int APS5_VABI _ZNSt8__sce_v212_Mtx_destroyEPP13pthread_mutex_nid_postfix(void** mutex);
int APS5_VABI _ZNSt8__sce_v29_Mtx_lockEPP13pthread_mutex_nid_postfix(void** mutex);
int APS5_VABI _ZNSt8__sce_v212_Mtx_trylockEPP13pthread_mutex_nid_postfix(void** mutex);
int APS5_VABI _ZNSt8__sce_v211_Mtx_unlockEPP13pthread_mutex_nid_postfix(void** mutex);
int APS5_VABI _ZNSt8__sce_v29_Cnd_initEPP12pthread_cond_nid_postfix(void** condition);
int APS5_VABI _ZNSt8__sce_v219_Cnd_init_with_nameEPP12pthread_condPKc_nid_postfix(void** condition, const char* name);
int APS5_VABI _ZNSt8__sce_v212_Cnd_destroyEPP12pthread_cond_nid_postfix(void** condition);
int APS5_VABI _ZNSt8__sce_v29_Cnd_waitEPP12pthread_condPP13pthread_mutex_nid_postfix(void** condition, void** mutex);
int APS5_VABI _ZNSt8__sce_v211_Cnd_signalEPP12pthread_cond_nid_postfix(void** condition);
int APS5_VABI _ZNSt8__sce_v214_Cnd_broadcastEPP12pthread_cond_nid_postfix(void** condition);
int APS5_VABI _ZNSt8__sce_v212_Thrd_detachEP7pthread_nid_postfix(void* thread);
int APS5_VABI _ZNSt8__sce_v210_Thrd_joinEP7pthreadPi_nid_postfix(void* thread, int* code);
void APS5_VABI _ZNSt8__sce_v211_Thrd_yieldEv_nid_postfix();
void* APS5_VABI _ZNSt8__sce_v28_Thrd_idEv_nid_postfix();
int APS5_VABI scePthreadCreate(void** thread, const void* attr, void* (APS5_VABI* entry)(void*), void* argument, const char* name);
int APS5_VABI scePthreadMutexUnlock(void** mutex);
int APS5_VABI scePthreadCondWait(void** condition, void** mutex);
void* APS5_VABI scePthreadSelf();
int APS5_VABI _Thrd_yield_nid_postfix();
}
@@ -375,6 +394,78 @@ static void ForwardedCalls() {
RequireThrows<std::runtime_error>([] { _Tss_get_nid_postfix(0); });
}
struct VersionedShared {
void* mutex = nullptr;
void* condition = nullptr;
std::atomic<int> stage{0};
int tryResult = -1;
};
static void* APS5_VABI VersionedWorker(void* argument) {
auto* shared = static_cast<VersionedShared*>(argument);
shared->tryResult = _ZNSt8__sce_v212_Mtx_trylockEPP13pthread_mutex_nid_postfix(&shared->mutex);
shared->stage = 1;
Require(_ZNSt8__sce_v29_Mtx_lockEPP13pthread_mutex_nid_postfix(&shared->mutex) == success);
shared->stage = 2;
Require(_ZNSt8__sce_v211_Cnd_signalEPP12pthread_cond_nid_postfix(&shared->condition) == success);
Require(_ZNSt8__sce_v211_Mtx_unlockEPP13pthread_mutex_nid_postfix(&shared->mutex) == success);
return reinterpret_cast<void*>(std::intptr_t{42});
}
static void* APS5_VABI DetachedWorker(void*) { return nullptr; }
static void VersionedSync() {
void* recursiveMutex = reinterpret_cast<void*>(std::uintptr_t{1});
Require(_ZNSt8__sce_v29_Mtx_initEPP13pthread_mutexi_nid_postfix(&recursiveMutex, plain | recursive) == success && recursiveMutex != nullptr);
Require(_ZNSt8__sce_v29_Mtx_lockEPP13pthread_mutex_nid_postfix(&recursiveMutex) == success);
Require(_ZNSt8__sce_v29_Mtx_lockEPP13pthread_mutex_nid_postfix(&recursiveMutex) == success);
Require(_ZNSt8__sce_v212_Mtx_trylockEPP13pthread_mutex_nid_postfix(&recursiveMutex) == success);
for (int unlock = 0; unlock < 3; ++unlock) Require(_ZNSt8__sce_v211_Mtx_unlockEPP13pthread_mutex_nid_postfix(&recursiveMutex) == success);
Require(_ZNSt8__sce_v212_Mtx_destroyEPP13pthread_mutex_nid_postfix(&recursiveMutex) == success);
void* plainMutex = nullptr;
Require(_ZNSt8__sce_v219_Mtx_init_with_nameEPP13pthread_mutexiPKc_nid_postfix(&plainMutex, plain, "") == success);
Require(_ZNSt8__sce_v29_Mtx_lockEPP13pthread_mutex_nid_postfix(&plainMutex) == success);
Require(_ZNSt8__sce_v29_Mtx_lockEPP13pthread_mutex_nid_postfix(&plainMutex) == busy);
Require(_ZNSt8__sce_v211_Mtx_unlockEPP13pthread_mutex_nid_postfix(&plainMutex) == success);
void* unownedCondition = nullptr;
Require(_ZNSt8__sce_v29_Cnd_initEPP12pthread_cond_nid_postfix(&unownedCondition) == success);
Require(scePthreadMutexUnlock(&plainMutex) != 0);
Require(scePthreadCondWait(&unownedCondition, &plainMutex) != 0);
Require(_ZNSt8__sce_v211_Mtx_unlockEPP13pthread_mutex_nid_postfix(&plainMutex) == success);
Require(_ZNSt8__sce_v29_Cnd_waitEPP12pthread_condPP13pthread_mutex_nid_postfix(&unownedCondition, &plainMutex) == success);
Require(_ZNSt8__sce_v212_Cnd_destroyEPP12pthread_cond_nid_postfix(&unownedCondition) == success);
Require(_ZNSt8__sce_v212_Mtx_destroyEPP13pthread_mutex_nid_postfix(&plainMutex) == success);
VersionedShared shared;
Require(_ZNSt8__sce_v29_Mtx_initEPP13pthread_mutexi_nid_postfix(&shared.mutex, plain) == success);
Require(_ZNSt8__sce_v219_Cnd_init_with_nameEPP12pthread_condPKc_nid_postfix(&shared.condition, "versioned") == success);
Require(_ZNSt8__sce_v29_Mtx_lockEPP13pthread_mutex_nid_postfix(&shared.mutex) == success);
void* thread = nullptr;
Require(scePthreadCreate(&thread, nullptr, VersionedWorker, &shared, "versioned") == 0);
while (shared.stage.load() == 0) std::this_thread::yield();
while (shared.stage.load() == 1) Require(_ZNSt8__sce_v29_Cnd_waitEPP12pthread_condPP13pthread_mutex_nid_postfix(&shared.condition, &shared.mutex) == success);
Require(shared.tryResult == busy);
Require(_ZNSt8__sce_v211_Mtx_unlockEPP13pthread_mutex_nid_postfix(&shared.mutex) == success);
int code = 0;
Require(_ZNSt8__sce_v210_Thrd_joinEP7pthreadPi_nid_postfix(thread, &code) == success && code == 42);
Require(_ZNSt8__sce_v210_Thrd_joinEP7pthreadPi_nid_postfix(thread, &code) == 4);
Require(_ZNSt8__sce_v214_Cnd_broadcastEPP12pthread_cond_nid_postfix(&shared.condition) == success);
Require(_ZNSt8__sce_v212_Cnd_destroyEPP12pthread_cond_nid_postfix(&shared.condition) == success);
Require(_ZNSt8__sce_v212_Mtx_destroyEPP13pthread_mutex_nid_postfix(&shared.mutex) == success);
void* condition = nullptr;
Require(_ZNSt8__sce_v29_Cnd_initEPP12pthread_cond_nid_postfix(&condition) == success);
Require(_ZNSt8__sce_v212_Cnd_destroyEPP12pthread_cond_nid_postfix(&condition) == success);
void* detached = nullptr;
Require(scePthreadCreate(&detached, nullptr, DetachedWorker, nullptr, "detached") == 0);
Require(_ZNSt8__sce_v212_Thrd_detachEP7pthread_nid_postfix(detached) == success);
Require(_ZNSt8__sce_v212_Thrd_detachEP7pthread_nid_postfix(nullptr) == 4);
_ZNSt8__sce_v211_Thrd_yieldEv_nid_postfix();
Require(_ZNSt8__sce_v28_Thrd_idEv_nid_postfix() != nullptr);
}
static void ThreadHelpers() {
Require(_Thrd_yield_nid_postfix() == success);
std::thread other([&] {
@@ -385,6 +476,7 @@ static void ThreadHelpers() {
int main() {
KernelKeys();
VersionedSync();
ForwardedCalls();
MutexBasics();
RecursiveMutex();