semaphore: Use binary_semaphore instead of condvar
Some checks failed
Build and Release / reuse (push) Has been cancelled
Build and Release / clang-format (push) Has been cancelled
Build and Release / get-info (push) Has been cancelled
Build and Release / windows-sdl (push) Has been cancelled
Build and Release / windows-qt (push) Has been cancelled
Build and Release / macos-sdl (push) Has been cancelled
Build and Release / macos-qt (push) Has been cancelled
Build and Release / linux-sdl (push) Has been cancelled
Build and Release / linux-qt (push) Has been cancelled
Build and Release / pre-release (push) Has been cancelled

* Seems more reliable
This commit is contained in:
IndecisiveTurtle 2024-11-19 23:52:59 +02:00
parent a4ea20c273
commit 85dc57b868

View file

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