diff --git a/src/core/libraries/kernel/threads/semaphore.cpp b/src/core/libraries/kernel/threads/semaphore.cpp index b8537d86..9c9c1117 100644 --- a/src/core/libraries/kernel/threads/semaphore.cpp +++ b/src/core/libraries/kernel/threads/semaphore.cpp @@ -49,7 +49,9 @@ public: const auto it = AddWaiter(&waiter); // Perform the wait. - const s32 result = waiter.Wait(lk, timeout); + lk.unlock(); + const s32 result = waiter.Wait(timeout); + lk.lock(); if (result == SCE_KERNEL_ERROR_ETIMEDOUT) { wait_list.erase(it); } @@ -72,7 +74,7 @@ public: } it = wait_list.erase(it); token_count -= waiter->need_count; - waiter->cv.notify_one(); + waiter->sema.release(); } return true; @@ -85,7 +87,7 @@ public: } for (auto* waiter : wait_list) { waiter->was_cancled = true; - waiter->cv.notify_one(); + waiter->sema.release(); } wait_list.clear(); token_count = set_count < 0 ? init_count : set_count; @@ -96,20 +98,20 @@ public: std::scoped_lock lk{mutex}; for (auto* waiter : wait_list) { waiter->was_deleted = true; - waiter->cv.notify_one(); + waiter->sema.release(); } wait_list.clear(); } public: struct WaitingThread { - std::condition_variable cv; + std::binary_semaphore sema; u32 priority; s32 need_count; bool was_deleted{}; bool was_cancled{}; - explicit WaitingThread(s32 need_count, bool is_fifo) : need_count{need_count} { + explicit WaitingThread(s32 need_count, bool is_fifo) : sema{0}, need_count{need_count} { // Retrieve calling thread priority for sorting into waiting threads list. if (!is_fifo) { priority = g_curthread->attr.prio; @@ -129,24 +131,24 @@ public: return SCE_OK; } - int Wait(std::unique_lock& lk, u32* timeout) { + int Wait(u32* timeout) { if (!timeout) { // Wait indefinitely until we are woken up. - cv.wait(lk); + sema.acquire(); return GetResult(false); } // Wait until timeout runs out, recording how much remaining time there was. const auto start = std::chrono::high_resolution_clock::now(); - const auto status = cv.wait_for(lk, std::chrono::microseconds(*timeout)); + const auto sema_timeout = !sema.try_acquire_for(std::chrono::microseconds(*timeout)); const auto end = std::chrono::high_resolution_clock::now(); const auto time = std::chrono::duration_cast(end - start).count(); - if (status == std::cv_status::timeout) { + if (sema_timeout) { *timeout = 0; } else { *timeout -= time; } - return GetResult(status == std::cv_status::timeout); + return GetResult(sema_timeout); } };