test(libkernel): cover concurrent pread against seek and read
This commit is contained in:
parent
3cab3c05ec
commit
0b46b3080a
|
|
@ -292,6 +292,15 @@ if(BUILD_TESTING)
|
|||
set_tests_properties(guest_aio PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libkernel>")
|
||||
endif()
|
||||
add_test_executable(guest_positioned_race_tests ${LIBS_INCLUDE_DIR}/tests/GuestPositionedRace.cpp)
|
||||
target_include_directories(guest_positioned_race_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(guest_positioned_race_tests PRIVATE libkernel libc)
|
||||
configure_windows_unwind(guest_positioned_race_tests)
|
||||
add_test(NAME guest_positioned_race COMMAND guest_positioned_race_tests)
|
||||
if(WIN32)
|
||||
set_tests_properties(guest_positioned_race PROPERTIES TIMEOUT 60 ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libkernel>")
|
||||
endif()
|
||||
add_test_executable(guest_once_tests ${LIBS_INCLUDE_DIR}/tests/GuestOnce.cpp)
|
||||
target_include_directories(guest_once_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(guest_once_tests PRIVATE libkernel libc)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,77 @@
|
|||
#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);
|
||||
}
|
||||
Loading…
Reference in New Issue