Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions core/libs/prx/libkernel/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1036,6 +1036,16 @@ if(BUILD_TESTING)
set_tests_properties(guest_poll PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libkernel>")
endif()
add_test_executable(guest_select_wait_tests ${LIBS_INCLUDE_DIR}/tests/GuestSelectWait.cpp)
target_include_directories(guest_select_wait_tests PRIVATE ${LIBS_INCLUDE_DIR})
target_link_libraries(guest_select_wait_tests PRIVATE libkernel libc)
configure_windows_unwind(guest_select_wait_tests)
add_test(NAME guest_select_wait COMMAND guest_select_wait_tests)
set_tests_properties(guest_select_wait PROPERTIES TIMEOUT 20)
if(WIN32)
set_tests_properties(guest_select_wait PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libkernel>")
endif()
if(NOT WIN32)
add_test_executable(guest_select_tests ${LIBS_INCLUDE_DIR}/tests/GuestSelect.cpp)
target_include_directories(guest_select_tests PRIVATE ${LIBS_INCLUDE_DIR})
Expand Down
4 changes: 2 additions & 2 deletions core/libs/prx/libkernel/Socket/src/Socket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include <cstddef>
#include "SceTypes.hpp"
#include "prx/libc/include/General.hpp"
#include "prx/libc/include/PreciseWait.hpp"
#include "prx/libkernel/File/include/RandomDevice.hpp"
#include "prx/libkernel/Socket/include/SocketPoll.hpp"
#include "prx/libkernel/Socket/include/SocketSelectDeadline.hpp"
Expand All @@ -11,7 +12,6 @@
#include <atomic>
#include <cerrno>
#include <chrono>
#include <thread>
#include <string>
#include <vector>

Expand Down Expand Up @@ -205,7 +205,7 @@ int APS5_VABI select_nid_postfix(int nfds, void* readfds, void* writefds, void*
}
if (devicesReady) waitMilliseconds = 0;
if (groups.empty()) {
if (waitMilliseconds > 0) std::this_thread::sleep_for(std::chrono::milliseconds(waitMilliseconds));
if (waitMilliseconds > 0) PreciseSleepUntil(std::min(deadline, std::chrono::steady_clock::now() + std::chrono::milliseconds(waitMilliseconds)));
} else {
const int slice = groups.size() == 1 ? waitMilliseconds : std::min(waitMilliseconds, SelectPollSliceMilliseconds);
const auto sliceEnd = std::chrono::steady_clock::now() + std::chrono::milliseconds(waitMilliseconds);
Expand Down
73 changes: 73 additions & 0 deletions core/libs/tests/GuestSelectWait.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#include "prx/libc/include/general/VabiMacros.hpp"
#include <array>
#include <chrono>
#include <cstdint>
#include <cstdio>
#include <cstdlib>

struct GuestTimeval {
std::int64_t seconds;
std::int64_t microseconds;
};

extern "C" {
int APS5_VABI select_nid_postfix(int, void*, void*, void*, const void*);
int* APS5_VABI __error_nid_postfix();
}

static void Require(bool value, const char* message) {
if (!value) {
std::fprintf(stderr, "%s\n", message);
std::abort();
}
}

int main() {
using Clock = std::chrono::steady_clock;
for (const std::int64_t micros : {0, 50, 500, 1000, 2000, 16667}) {
const GuestTimeval limit{0, micros};
for (const int count : {0, 1024}) {
const auto start = Clock::now();
Require(select_nid_postfix(count, nullptr, nullptr, nullptr, &limit) == 0,
"select without descriptors did not time out");
Require(Clock::now() - start >= std::chrono::microseconds(micros),
"select returned before its deadline");
Require(limit.seconds == 0 && limit.microseconds == micros,
"select changed the guest timeout");
}
}
const GuestTimeval shortLimit{0, 1000};
const auto shortWaitStart = Clock::now();
for (int i = 0; i < 20; ++i) {
Require(select_nid_postfix(0, nullptr, nullptr, nullptr, &shortLimit) == 0,
"repeated select without descriptors did not time out");
}
const auto shortWait = Clock::now() - shortWaitStart;
Require(shortWait >= std::chrono::milliseconds(20) && shortWait < std::chrono::milliseconds(200),
"twenty 1 ms selects did not stay close to their deadlines");
for (const GuestTimeval limit : {GuestTimeval{-1, 0}, GuestTimeval{0, -1}, GuestTimeval{0, 1000000}}) {
Require(select_nid_postfix(0, nullptr, nullptr, nullptr, &limit) == -1 && *__error_nid_postfix() == 22,
"select accepted an invalid timeout");
}
const GuestTimeval zero{};
for (const int count : {-1, 1025}) {
Require(select_nid_postfix(count, nullptr, nullptr, nullptr, &zero) == -1 && *__error_nid_postfix() == 22,
"select accepted an invalid descriptor limit");
}
std::array<std::uint64_t, 16> read{};
read[0] = 1 | (std::uint64_t{1} << 63);
const GuestTimeval limit{0, 500};
const auto start = Clock::now();
Require(select_nid_postfix(1, read.data(), nullptr, nullptr, &limit) == 0,
"select with no ready device did not time out");
Require(Clock::now() - start >= std::chrono::microseconds(limit.microseconds),
"select with no ready device returned before its deadline");
Require(read[0] == (std::uint64_t{1} << 63),
"select did not preserve bits outside the descriptor limit");
std::array<std::uint64_t, 16> write{};
write[0] = 2;
const GuestTimeval longLimit{1, 0};
Require(select_nid_postfix(2, nullptr, write.data(), nullptr, &longLimit) == 1 && write[0] == 2,
"select did not report a ready device");
std::puts("20 select wait scenarios passed");
}
Loading