mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-27 00:28:14 +00:00
94 lines
3.4 KiB
C++
94 lines
3.4 KiB
C++
#include "prx/libkernel/KernelErrors.hpp"
|
|
#include "prx/libkernel/include/Api.hpp"
|
|
#include "prx/libkernel/Time/include/Time.hpp"
|
|
#include "prx/libkernel/Pthread/include/Mutex.hpp"
|
|
#include "prx/libkernel/Pthread/include/Cond.hpp"
|
|
#include "SceTypes.hpp"
|
|
#include <atomic>
|
|
#include <cstdint>
|
|
#include <cstdlib>
|
|
#include <thread>
|
|
|
|
static constexpr int SCE_OK = 0;
|
|
static constexpr int POSIX_EPERM = 1;
|
|
static constexpr int POSIX_EINVAL = 22;
|
|
static constexpr std::uintptr_t ADAPTIVE_INITIALIZER = 1;
|
|
|
|
static void Require(bool value) { if (!value) std::abort(); }
|
|
|
|
static int PosixTimed(PthreadCond* cond, PthreadMutex* mutex) {
|
|
KernelTimespec deadline{};
|
|
Require(clock_gettime_nid_postfix(0, &deadline) == 0);
|
|
deadline.tv_sec += 60;
|
|
return pthread_cond_timedwait_nid_postfix(cond, mutex, &deadline);
|
|
}
|
|
|
|
struct Wait {
|
|
int (*run)(PthreadCond*, PthreadMutex*);
|
|
int notOwned;
|
|
int destroyed;
|
|
};
|
|
|
|
static int SceWait(PthreadCond* cond, PthreadMutex* mutex) { return scePthreadCondWait(cond, mutex); }
|
|
static int SceTimed(PthreadCond* cond, PthreadMutex* mutex) { return scePthreadCondTimedwait(cond, mutex, 60000000); }
|
|
static int PosixWait(PthreadCond* cond, PthreadMutex* mutex) { return pthread_cond_wait_nid_postfix(cond, mutex); }
|
|
|
|
struct Holder {
|
|
PthreadMutex mutex = nullptr;
|
|
std::atomic<bool> locked{false};
|
|
std::atomic<bool> release{false};
|
|
};
|
|
|
|
static void* APS5_VABI Hold(void* arg) {
|
|
auto& holder = *static_cast<Holder*>(arg);
|
|
Require(scePthreadMutexLock(&holder.mutex) == SCE_OK);
|
|
holder.locked.store(true);
|
|
while (!holder.release.load())
|
|
std::this_thread::yield();
|
|
Require(scePthreadMutexUnlock(&holder.mutex) == SCE_OK);
|
|
return nullptr;
|
|
}
|
|
|
|
static void Check(const Wait& wait) {
|
|
PthreadCond cond = nullptr;
|
|
Require(scePthreadCondInit(&cond, nullptr, nullptr) == SCE_OK);
|
|
|
|
PthreadMutex unlocked = nullptr;
|
|
Require(scePthreadMutexInit(&unlocked, nullptr, nullptr) == SCE_OK);
|
|
Require(wait.run(&cond, &unlocked) == wait.notOwned);
|
|
Require(scePthreadMutexLock(&unlocked) == SCE_OK);
|
|
Require(scePthreadMutexUnlock(&unlocked) == SCE_OK);
|
|
Require(scePthreadMutexDestroy(&unlocked) == SCE_OK);
|
|
|
|
PthreadMutex uninitialized = nullptr;
|
|
Require(wait.run(&cond, &uninitialized) == wait.notOwned);
|
|
|
|
PthreadMutex adaptive = reinterpret_cast<PthreadMutex>(ADAPTIVE_INITIALIZER);
|
|
Require(wait.run(&cond, &adaptive) == wait.notOwned);
|
|
|
|
PthreadMutex destroyed = nullptr;
|
|
Require(scePthreadMutexInit(&destroyed, nullptr, nullptr) == SCE_OK);
|
|
Require(scePthreadMutexDestroy(&destroyed) == SCE_OK);
|
|
Require(wait.run(&cond, &destroyed) == wait.destroyed);
|
|
|
|
Holder holder;
|
|
Require(scePthreadMutexInit(&holder.mutex, nullptr, nullptr) == SCE_OK);
|
|
Pthread thread = nullptr;
|
|
Require(scePthreadCreate(&thread, nullptr, Hold, &holder, nullptr) == SCE_OK);
|
|
while (!holder.locked.load())
|
|
std::this_thread::yield();
|
|
Require(wait.run(&cond, &holder.mutex) == wait.notOwned);
|
|
holder.release.store(true);
|
|
Require(scePthreadJoin(thread, nullptr) == SCE_OK);
|
|
Require(scePthreadMutexDestroy(&holder.mutex) == SCE_OK);
|
|
|
|
Require(scePthreadCondDestroy(&cond) == SCE_OK);
|
|
}
|
|
|
|
int main() {
|
|
Check({SceWait, SCE_KERNEL_ERROR_EPERM, SCE_KERNEL_ERROR_EINVAL});
|
|
Check({SceTimed, SCE_KERNEL_ERROR_EPERM, SCE_KERNEL_ERROR_EINVAL});
|
|
Check({PosixWait, POSIX_EPERM, POSIX_EINVAL});
|
|
Check({PosixTimed, POSIX_EPERM, POSIX_EINVAL});
|
|
}
|