mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-11-04 13:07:32 +00:00
Each clears its 128-byte option structure, as sceUltMutexOptParamInitialize and sceUltUlthreadRuntimeOptParamInitialize already do.
96 lines
3.3 KiB
C++
96 lines
3.3 KiB
C++
#include "SceTypes.hpp"
|
|
#include <atomic>
|
|
#include <cstdint>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <initializer_list>
|
|
#include <thread>
|
|
|
|
extern "C" {
|
|
int APS5_VABI sceUltInitialize();
|
|
int APS5_VABI sceUltFinalize();
|
|
int APS5_VABI _sceUltMutexCreate(void*, const char*, void*, const void*, std::uint32_t);
|
|
int APS5_VABI sceUltMutexLock(void*);
|
|
int APS5_VABI sceUltMutexTryLock(void*);
|
|
int APS5_VABI sceUltMutexUnlock(void*);
|
|
int APS5_VABI sceUltMutexDestroy(void*);
|
|
int APS5_VABI sceUltSemaphoreOptParamInitialize(void*, std::uint32_t);
|
|
int APS5_VABI sceUltQueueOptParamInitialize(void*, std::uint32_t);
|
|
int APS5_VABI sceUltQueueDataResourcePoolOptParamInitialize(void*, std::uint32_t);
|
|
int APS5_VABI sceUltWaitingQueueResourcePoolOptParamInitialize(void*, std::uint32_t);
|
|
int APS5_VABI sceUltUlthreadOptParamInitialize(void*, std::uint32_t);
|
|
}
|
|
|
|
namespace {
|
|
|
|
constexpr int Ok = 0;
|
|
constexpr int Null = -2139029503;
|
|
constexpr int State = -2139029498;
|
|
constexpr int Busy = -2139029497;
|
|
|
|
void Require(bool value, int line) {
|
|
if (value) return;
|
|
std::fprintf(stderr, "ULT sync check failed at line %d\n", line);
|
|
std::abort();
|
|
}
|
|
|
|
#define CHECK(value) Require((value), __LINE__)
|
|
|
|
struct alignas(8) Object {
|
|
std::uint8_t bytes[256];
|
|
};
|
|
|
|
void MutexTryLock() {
|
|
Object mutex{};
|
|
CHECK(sceUltMutexTryLock(nullptr) == Null);
|
|
CHECK(sceUltMutexTryLock(&mutex) == State);
|
|
CHECK(_sceUltMutexCreate(&mutex, "trylock", nullptr, nullptr, 0) == Ok);
|
|
CHECK(sceUltMutexTryLock(&mutex) == Ok);
|
|
CHECK(sceUltMutexTryLock(&mutex) == Ok);
|
|
std::atomic<int> other{0};
|
|
std::thread([&] { other = sceUltMutexTryLock(&mutex); }).join();
|
|
CHECK(other == Busy);
|
|
CHECK(sceUltMutexUnlock(&mutex) == Ok);
|
|
std::thread([&] { other = sceUltMutexTryLock(&mutex); }).join();
|
|
CHECK(other == Busy);
|
|
CHECK(sceUltMutexUnlock(&mutex) == Ok);
|
|
CHECK(sceUltMutexUnlock(&mutex) == State);
|
|
std::thread([&] {
|
|
other = sceUltMutexTryLock(&mutex);
|
|
if (other == Ok) other = sceUltMutexUnlock(&mutex);
|
|
}).join();
|
|
CHECK(other == Ok);
|
|
CHECK(sceUltMutexLock(&mutex) == Ok);
|
|
CHECK(sceUltMutexDestroy(&mutex) == Busy);
|
|
CHECK(sceUltMutexUnlock(&mutex) == Ok);
|
|
CHECK(sceUltMutexDestroy(&mutex) == Ok);
|
|
CHECK(sceUltMutexTryLock(&mutex) == State);
|
|
}
|
|
|
|
void OptParams() {
|
|
using Initializer = int (APS5_VABI *)(void*, std::uint32_t);
|
|
for (const Initializer initialize : {sceUltSemaphoreOptParamInitialize, sceUltQueueOptParamInitialize, sceUltQueueDataResourcePoolOptParamInitialize,
|
|
sceUltWaitingQueueResourcePoolOptParamInitialize, sceUltUlthreadOptParamInitialize}) {
|
|
std::uint8_t bytes[136];
|
|
std::memset(bytes, 0xa5, sizeof(bytes));
|
|
CHECK(initialize(nullptr, 0) == Null);
|
|
CHECK(initialize(bytes, 0) == Ok);
|
|
for (std::size_t index = 0; index < 128; ++index) CHECK(bytes[index] == 0);
|
|
for (std::size_t index = 128; index < sizeof(bytes); ++index) CHECK(bytes[index] == 0xa5);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
int main(int argc, char** argv) {
|
|
if (argc != 2) return 2;
|
|
CHECK(sceUltInitialize() == Ok);
|
|
if (std::strcmp(argv[1], "mutex-trylock") == 0) MutexTryLock();
|
|
else if (std::strcmp(argv[1], "opt-params") == 0) OptParams();
|
|
else return 2;
|
|
CHECK(sceUltFinalize() == Ok);
|
|
std::puts("ULT sync tests passed");
|
|
return 0;
|
|
}
|