mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-27 00:28:14 +00:00
scePthreadMutexTimedlock on a mutex the caller holds, and scePthreadRwlockTimedrdlock and scePthreadRwlockTimedwrlock on a rwlock it holds for writing, returned EDEADLK at once. The console returns ETIMEDOUT, as the prosper console oracle measured. They now sleep until the timeout and return ETIMEDOUT, as FreeBSD libthr does. The POSIX timed locks call these and change with them. Co-Authored-By: Claude Opus 5.5 <[email protected]>
146 lines
7.2 KiB
C++
146 lines
7.2 KiB
C++
#include "prx/libkernel/KernelErrors.hpp"
|
|
#include "prx/libkernel/include/Api.hpp"
|
|
#include "prx/libkernel/Pthread/include/Mutex.hpp"
|
|
#include "SceTypes.hpp"
|
|
#include <cstdint>
|
|
#include <cstdlib>
|
|
#include <initializer_list>
|
|
#include <stdexcept>
|
|
|
|
static constexpr int SCE_OK = 0;
|
|
|
|
static constexpr int POSIX_EDEADLK = 11;
|
|
static constexpr int POSIX_EINVAL = 22;
|
|
static constexpr int POSIX_ETIMEDOUT = 60;
|
|
static const PthreadMutex AdaptiveInitializer = reinterpret_cast<PthreadMutex>(std::uintptr_t{1});
|
|
static const PthreadMutex DestroyedMutex = reinterpret_cast<PthreadMutex>(std::uintptr_t{2});
|
|
|
|
static void Require(bool value) { if (!value) std::abort(); }
|
|
|
|
template <typename Call>
|
|
static bool Throws(Call call) {
|
|
try {
|
|
call();
|
|
} catch (const std::exception&) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
struct OtherThread {
|
|
PthreadMutex* mutex;
|
|
int isowned = -1;
|
|
int reltimedlock = -1;
|
|
};
|
|
|
|
static void* APS5_VABI CheckFromOtherThread(void* arg) {
|
|
auto& other = *static_cast<OtherThread*>(arg);
|
|
other.isowned = pthread_mutex_isowned_np_nid_postfix(other.mutex);
|
|
other.reltimedlock = pthread_mutex_reltimedlock_np_nid_postfix(other.mutex, 1000);
|
|
return nullptr;
|
|
}
|
|
|
|
static void CheckOwnershipAndRelativeLock() {
|
|
PthreadMutex mutex = nullptr;
|
|
Require(pthread_mutex_isowned_np_nid_postfix(&mutex) == 0 && mutex == nullptr);
|
|
PthreadMutex adaptive = AdaptiveInitializer;
|
|
Require(pthread_mutex_isowned_np_nid_postfix(&adaptive) == 0 && adaptive == AdaptiveInitializer);
|
|
Require(pthread_mutex_reltimedlock_np_nid_postfix(&mutex, 1000) == 0 && mutex != nullptr);
|
|
Require(pthread_mutex_isowned_np_nid_postfix(&mutex) == 1);
|
|
Require(pthread_mutex_reltimedlock_np_nid_postfix(&mutex, 1000) == POSIX_ETIMEDOUT);
|
|
OtherThread other{&mutex};
|
|
Pthread thread = nullptr;
|
|
Require(scePthreadCreate(&thread, nullptr, CheckFromOtherThread, &other, nullptr) == SCE_OK);
|
|
Require(scePthreadJoin(thread, nullptr) == SCE_OK);
|
|
Require(other.isowned == 0 && other.reltimedlock == POSIX_ETIMEDOUT);
|
|
Require(pthread_mutex_unlock_nid_postfix(&mutex) == 0);
|
|
Require(pthread_mutex_isowned_np_nid_postfix(&mutex) == 0);
|
|
Require(pthread_mutex_reltimedlock_np_nid_postfix(&mutex, 0) == 0);
|
|
Require(pthread_mutex_unlock_nid_postfix(&mutex) == 0);
|
|
Require(pthread_mutex_destroy_nid_postfix(&mutex) == 0);
|
|
Require(mutex == DestroyedMutex);
|
|
Require(pthread_mutex_isowned_np_nid_postfix(&mutex) == 0);
|
|
Require(pthread_mutex_reltimedlock_np_nid_postfix(&mutex, 1000) == POSIX_EINVAL);
|
|
Require(Throws([] { pthread_mutex_isowned_np_nid_postfix(nullptr); }));
|
|
}
|
|
|
|
static void CheckLoops(PthreadMutexattr* attr) {
|
|
PthreadMutex mutex = nullptr;
|
|
int count = -1;
|
|
Require(pthread_mutex_getspinloops_np_nid_postfix(&mutex, &count) == 0 && count == 0 && mutex != nullptr);
|
|
Require(pthread_mutex_getyieldloops_np_nid_postfix(&mutex, &count) == 0 && count == 0);
|
|
Require(pthread_mutex_destroy_nid_postfix(&mutex) == 0);
|
|
|
|
PthreadMutex adaptive = AdaptiveInitializer;
|
|
Require(scePthreadMutexGetspinloops(&adaptive, &count) == SCE_OK && count == 2000 && adaptive != AdaptiveInitializer);
|
|
Require(scePthreadMutexGetyieldloops(&adaptive, &count) == SCE_OK && count == 0);
|
|
Require(scePthreadMutexDestroy(&adaptive) == SCE_OK);
|
|
|
|
Require(scePthreadMutexattrSettype(attr, 4) == SCE_OK);
|
|
Require(scePthreadMutexInit(&mutex, attr, "adaptive") == SCE_OK);
|
|
Require(scePthreadMutexGetspinloops(&mutex, &count) == SCE_OK && count == 2000);
|
|
Require(scePthreadMutexSetspinloops(&mutex, 7) == SCE_OK);
|
|
Require(pthread_mutex_getspinloops_np_nid_postfix(&mutex, &count) == 0 && count == 7);
|
|
Require(pthread_mutex_setspinloops_np_nid_postfix(&mutex, -3) == 0);
|
|
Require(scePthreadMutexGetspinloops(&mutex, &count) == SCE_OK && count == -3);
|
|
Require(scePthreadMutexSetyieldloops(&mutex, 9) == SCE_OK);
|
|
Require(pthread_mutex_getyieldloops_np_nid_postfix(&mutex, &count) == 0 && count == 9);
|
|
Require(pthread_mutex_setyieldloops_np_nid_postfix(&mutex, 11) == 0);
|
|
Require(scePthreadMutexGetyieldloops(&mutex, &count) == SCE_OK && count == 11);
|
|
Require(pthread_mutex_lock_nid_postfix(&mutex) == 0);
|
|
Require(pthread_mutex_lock_nid_postfix(&mutex) == POSIX_EDEADLK);
|
|
Require(pthread_mutex_unlock_nid_postfix(&mutex) == 0);
|
|
Require(Throws([&] { scePthreadMutexGetspinloops(&mutex, nullptr); }));
|
|
Require(Throws([&] { scePthreadMutexGetyieldloops(&mutex, nullptr); }));
|
|
Require(scePthreadMutexDestroy(&mutex) == SCE_OK);
|
|
|
|
count = -1;
|
|
Require(scePthreadMutexGetspinloops(&mutex, &count) == SCE_KERNEL_ERROR_EINVAL && count == -1);
|
|
Require(scePthreadMutexSetspinloops(&mutex, 1) == SCE_KERNEL_ERROR_EINVAL);
|
|
Require(scePthreadMutexGetyieldloops(&mutex, &count) == SCE_KERNEL_ERROR_EINVAL && count == -1);
|
|
Require(pthread_mutex_getspinloops_np_nid_postfix(&mutex, &count) == POSIX_EINVAL);
|
|
Require(pthread_mutex_setspinloops_np_nid_postfix(&mutex, 1) == POSIX_EINVAL);
|
|
Require(pthread_mutex_getyieldloops_np_nid_postfix(&mutex, &count) == POSIX_EINVAL && count == -1);
|
|
Require(scePthreadMutexSetyieldloops(&mutex, 1) == SCE_OK);
|
|
Require(pthread_mutex_setyieldloops_np_nid_postfix(&mutex, 1) == 0);
|
|
Require(mutex == DestroyedMutex);
|
|
|
|
for (const int type : {1, 2, 3}) {
|
|
Require(scePthreadMutexattrSettype(attr, type) == SCE_OK);
|
|
Require(scePthreadMutexInit(&mutex, attr, nullptr) == SCE_OK);
|
|
Require(scePthreadMutexGetspinloops(&mutex, &count) == SCE_OK && count == 0);
|
|
Require(scePthreadMutexDestroy(&mutex) == SCE_OK);
|
|
}
|
|
}
|
|
|
|
int main() {
|
|
PthreadMutexattr attr = nullptr;
|
|
Require(scePthreadMutexattrInit(&attr) == SCE_OK);
|
|
for (int type : {-1, 0, 5}) Require(scePthreadMutexattrSettype(&attr, type) == SCE_KERNEL_ERROR_EINVAL);
|
|
for (int type : {1, 2, 3, 4}) Require(scePthreadMutexattrSettype(&attr, type) == SCE_OK);
|
|
for (int protocol : {-1, 3}) Require(scePthreadMutexattrSetprotocol(&attr, protocol) == SCE_KERNEL_ERROR_EINVAL);
|
|
for (int protocol : {0, 1, 2}) Require(scePthreadMutexattrSetprotocol(&attr, protocol) == SCE_OK);
|
|
|
|
PthreadMutexattr unset = nullptr;
|
|
Require(scePthreadMutexattrSettype(&unset, 1) == SCE_KERNEL_ERROR_EINVAL);
|
|
Require(scePthreadMutexattrSetprotocol(&unset, 0) == SCE_KERNEL_ERROR_EINVAL);
|
|
Require(scePthreadMutexattrDestroy(&unset) == SCE_KERNEL_ERROR_EINVAL);
|
|
Require(scePthreadMutexattrSettype(nullptr, 1) == SCE_KERNEL_ERROR_EINVAL);
|
|
Require(scePthreadMutexattrDestroy(nullptr) == SCE_KERNEL_ERROR_EINVAL);
|
|
|
|
PthreadMutex mutex = nullptr;
|
|
Require(scePthreadMutexInit(&mutex, &unset, "unset") == SCE_OK);
|
|
Require(scePthreadMutexLock(&mutex) == SCE_OK);
|
|
Require(scePthreadMutexDestroy(&mutex) == SCE_KERNEL_ERROR_EBUSY);
|
|
Require(scePthreadMutexUnlock(&mutex) == SCE_OK);
|
|
Require(scePthreadMutexDestroy(&mutex) == SCE_OK);
|
|
Require(mutex == reinterpret_cast<PthreadMutex>(std::uintptr_t{2}));
|
|
Require(scePthreadMutexDestroy(&mutex) == SCE_KERNEL_ERROR_EINVAL);
|
|
|
|
Require(scePthreadMutexInit(&mutex, &attr, "attr") == SCE_OK);
|
|
Require(scePthreadMutexDestroy(&mutex) == SCE_OK);
|
|
CheckLoops(&attr);
|
|
CheckOwnershipAndRelativeLock();
|
|
Require(scePthreadMutexattrDestroy(&attr) == SCE_OK);
|
|
}
|