mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-11-05 13:20:11 +00:00
test(libkernel): restore synchronized SCE sleep cancellation coverage
This commit is contained in:
1 parent
7b7ff0bbae
commit
4d8f05891b
3 files changed
+39
-10
No files matched your search
@@ -2052,4 +2052,15 @@ if(BUILD_TESTING)
|
||||
endif()
|
||||
endforeach()
|
||||
endforeach()
|
||||
foreach(sleepApi IN ITEMS sce_usleep sce_nanosleep sce_sleep)
|
||||
set(sleepTest guest_sleep_cancel_${sleepApi}_deferred)
|
||||
add_test(NAME ${sleepTest} COMMAND guest_sleep_cancel_tests deferred ${sleepApi})
|
||||
add_test(NAME ${sleepTest}_coarse COMMAND guest_sleep_cancel_tests deferred ${sleepApi})
|
||||
set_tests_properties(${sleepTest} ${sleepTest}_coarse PROPERTIES TIMEOUT 20)
|
||||
set_tests_properties(${sleepTest}_coarse PROPERTIES ENVIRONMENT "APS5_COARSE_TIMED_WAITS=1")
|
||||
if(WIN32)
|
||||
set_tests_properties(${sleepTest} ${sleepTest}_coarse PROPERTIES
|
||||
ENVIRONMENT_MODIFICATION "PATH=path_list_prepend:$<TARGET_FILE_DIR:libkernel>")
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
@@ -619,6 +619,11 @@ void SleepNanos(std::uint64_t nanos) {
|
||||
}
|
||||
SleepUntil(NowNanos() + nanos);
|
||||
#else
|
||||
struct SleepRegistration {
|
||||
std::atomic<int>* state = WaitState().bound;
|
||||
SleepRegistration() { state->fetch_add(1, std::memory_order_seq_cst); }
|
||||
~SleepRegistration() { state->fetch_sub(1, std::memory_order_seq_cst); }
|
||||
} registration;
|
||||
struct timespec req{};
|
||||
req.tv_sec = static_cast<time_t>(nanos / 1000000000ULL);
|
||||
req.tv_nsec = static_cast<long>(nanos % 1000000000ULL);
|
||||
|
||||
@@ -39,9 +39,11 @@ static bool pending = false;
|
||||
static unsigned seconds = LongSleep;
|
||||
static std::string_view api = "sleep";
|
||||
static unsigned cleanupCalls = 0;
|
||||
static std::chrono::steady_clock::time_point sleepStart{};
|
||||
static std::chrono::steady_clock::duration elapsed{};
|
||||
|
||||
static void APS5_VABI Cleanup(void*) {
|
||||
elapsed = std::chrono::steady_clock::now() - sleepStart;
|
||||
++cleanupCalls;
|
||||
}
|
||||
|
||||
@@ -64,9 +66,9 @@ static void* APS5_VABI Sleeper(void*) {
|
||||
ready.store(true);
|
||||
ready.notify_all();
|
||||
if (pending) release.wait(false);
|
||||
const auto start = std::chrono::steady_clock::now();
|
||||
sleepStart = std::chrono::steady_clock::now();
|
||||
Require(Sleep() == 0);
|
||||
elapsed = std::chrono::steady_clock::now() - start;
|
||||
elapsed = std::chrono::steady_clock::now() - sleepStart;
|
||||
returned.store(true);
|
||||
if (disabled) {
|
||||
Require(scePthreadSetcancelstate(0, nullptr) == 0);
|
||||
@@ -86,13 +88,15 @@ static bool WaitForCompletion(Pthread thread) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool WaitForSleep(Pthread thread) {
|
||||
static bool WaitForSleep(Pthread thread, bool hostSleep) {
|
||||
const auto limit = std::chrono::steady_clock::now() + ObservationLimit;
|
||||
for (;;) {
|
||||
{
|
||||
std::lock_guard lock(thread->cancelLock);
|
||||
if (thread->cancelWait != nullptr) return true;
|
||||
}
|
||||
if (hostSleep && thread->waitCount.load(std::memory_order_seq_cst) > 0) return true;
|
||||
if (thread->_finished.load(std::memory_order_acquire)) return false;
|
||||
if (std::chrono::steady_clock::now() >= limit) return false;
|
||||
std::this_thread::yield();
|
||||
}
|
||||
@@ -106,24 +110,33 @@ int main(int count, char** arguments) {
|
||||
const bool zero = mode == "pending";
|
||||
pending = zero || disabled || mode == "pending_long";
|
||||
const bool normal = mode == "normal";
|
||||
Require(mode == "blocked" || disabled || pending || normal);
|
||||
if (disabled || normal) seconds = 1;
|
||||
const bool deferred = mode == "deferred";
|
||||
Require(mode == "blocked" || disabled || pending || normal || deferred);
|
||||
Require(!deferred || api == "sce_usleep" || api == "sce_nanosleep" || api == "sce_sleep");
|
||||
if (disabled || normal || deferred) seconds = 1;
|
||||
if (zero) seconds = 0;
|
||||
Pthread thread = nullptr;
|
||||
Require(scePthreadCreate(&thread, nullptr, Sleeper, nullptr, nullptr) == 0);
|
||||
ready.wait(false);
|
||||
const auto readyLimit = std::chrono::steady_clock::now() + ObservationLimit;
|
||||
while (!ready.load()) {
|
||||
Require(std::chrono::steady_clock::now() < readyLimit);
|
||||
std::this_thread::yield();
|
||||
}
|
||||
bool wasSleeping = false;
|
||||
if (!normal) {
|
||||
if (!pending) wasSleeping = WaitForSleep(thread);
|
||||
if (!pending) {
|
||||
wasSleeping = WaitForSleep(thread, deferred);
|
||||
Require(wasSleeping);
|
||||
}
|
||||
Require(scePthreadCancel(thread) == 0);
|
||||
release.store(true);
|
||||
release.notify_all();
|
||||
}
|
||||
const bool completed = WaitForCompletion(thread);
|
||||
void* result = nullptr;
|
||||
Require(scePthreadJoin(thread, &result) == 0);
|
||||
if (!completed) std::fputs("sleep stayed blocked after cancellation\n", stderr);
|
||||
Require(completed);
|
||||
void* result = nullptr;
|
||||
Require(scePthreadJoin(thread, &result) == 0);
|
||||
if (normal) {
|
||||
Require(result == nullptr && returned.load());
|
||||
Require(cleanupCalls == 0);
|
||||
@@ -133,5 +146,5 @@ int main(int count, char** arguments) {
|
||||
Require(returned.load() == disabled);
|
||||
if (!pending) Require(wasSleeping);
|
||||
}
|
||||
if (normal || disabled) Require(elapsed >= std::chrono::seconds(1));
|
||||
if (normal || disabled || deferred) Require(elapsed >= std::chrono::seconds(1));
|
||||
}
|
||||
Reference in new issue
Block a user