78 lines
2.8 KiB
C++
78 lines
2.8 KiB
C++
#include "SceTypes.hpp"
|
|
#include "prx/libc/include/general/VabiMacros.hpp"
|
|
#include "prx/libkernel/File/include/FileFlags.hpp"
|
|
#include "prx/libkernel/KernelErrors.hpp"
|
|
#include <array>
|
|
#include <atomic>
|
|
#include <chrono>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <filesystem>
|
|
#include <fstream>
|
|
#include <string>
|
|
#include <thread>
|
|
extern "C" {
|
|
int APS5_VABI sceKernelOpen(const char* path, int flags, std::uint16_t mode);
|
|
int APS5_VABI sceKernelClose(int d);
|
|
std::int64_t APS5_VABI sceKernelRead(int d, void* buf, std::size_t nbytes);
|
|
std::int64_t APS5_VABI sceKernelPread(int d, void* buf, std::size_t nbytes, std::int64_t offset);
|
|
std::int64_t APS5_VABI sceKernelLseek(int d, std::int64_t offset, int whence);
|
|
}
|
|
static void Check(bool value, int line) {
|
|
if (!value) {
|
|
std::fprintf(stderr, "Positioned race check failed at line %d\n", line);
|
|
std::abort();
|
|
}
|
|
}
|
|
#define Require(value) Check((value), __LINE__)
|
|
int main() {
|
|
const auto root = std::filesystem::path("anyps5-positioned-race-" +
|
|
std::to_string(std::chrono::steady_clock::now().time_since_epoch().count()));
|
|
Require(std::filesystem::create_directory(root));
|
|
const auto file = root / "blocks.bin";
|
|
constexpr std::int64_t kBlocks = 8;
|
|
constexpr std::size_t kBlockSize = 4096;
|
|
{
|
|
std::ofstream stream(file, std::ios::binary);
|
|
Require(static_cast<bool>(stream));
|
|
for (std::int64_t block = 0; block < kBlocks; ++block) {
|
|
stream << std::string(kBlockSize, static_cast<char>('A' + block));
|
|
}
|
|
}
|
|
const int fd = sceKernelOpen(file.string().c_str(), SCE_KERNEL_O_RDONLY, 0);
|
|
Require(fd >= 0);
|
|
std::array<char, 64> expected{};
|
|
expected.fill('A');
|
|
std::atomic<bool> stop{false};
|
|
std::atomic<bool> misread{false};
|
|
std::array<char, 64> seeked{};
|
|
seeked.fill('H');
|
|
std::thread seeker([&] {
|
|
std::array<char, 64> sink{};
|
|
while (!stop.load()) {
|
|
if (sceKernelLseek(fd, (kBlocks - 1) * kBlockSize, 0) != (kBlocks - 1) * kBlockSize) {
|
|
misread = true;
|
|
return;
|
|
}
|
|
if (sceKernelRead(fd, sink.data(), sink.size()) != static_cast<std::int64_t>(sink.size()) ||
|
|
std::memcmp(sink.data(), seeked.data(), seeked.size()) != 0) {
|
|
misread = true;
|
|
return;
|
|
}
|
|
}
|
|
});
|
|
for (int i = 0; i < 5000 && !misread.load(); ++i) {
|
|
std::array<char, 64> bytes{};
|
|
const auto got = sceKernelPread(fd, bytes.data(), bytes.size(), 0);
|
|
if (got != static_cast<std::int64_t>(bytes.size()) || std::memcmp(bytes.data(), expected.data(), expected.size()) != 0) {
|
|
misread = true;
|
|
}
|
|
}
|
|
stop = true;
|
|
seeker.join();
|
|
Require(!misread);
|
|
Require(sceKernelClose(fd) == 0);
|
|
Require(std::filesystem::remove_all(root) > 0);
|
|
}
|