equeue: Few fixes for sceKernelWaitEqueue (#3548)

This commit is contained in:
squidbus
2025-09-08 19:47:12 -07:00
committed by GitHub
parent f4531fd927
commit ac318b56ac
2 changed files with 29 additions and 25 deletions

View File

@@ -97,7 +97,14 @@ bool EqueueInternal::RemoveEvent(u64 id, s16 filter) {
return has_found;
}
int EqueueInternal::WaitForEvents(SceKernelEvent* ev, int num, u32 micros) {
int EqueueInternal::WaitForEvents(SceKernelEvent* ev, int num, const SceKernelUseconds* timo) {
if (timo != nullptr && *timo == 0) {
// Effectively acts as a poll; only events that have already
// arrived at the time of this function call can be received
return GetTriggeredEvents(ev, num);
}
const auto micros = timo ? *timo : 0u;
if (HasSmallTimer()) {
// If a small timer is set, just wait for it to expire.
return WaitForSmallTimer(ev, num, micros);
@@ -111,9 +118,11 @@ int EqueueInternal::WaitForEvents(SceKernelEvent* ev, int num, u32 micros) {
};
if (micros == 0) {
// Wait indefinitely for events
std::unique_lock lock{m_mutex};
m_cond.wait(lock, predicate);
} else {
// Wait up until the timeout value
std::unique_lock lock{m_mutex};
m_cond.wait_for(lock, std::chrono::microseconds(micros), predicate);
}
@@ -127,12 +136,6 @@ int EqueueInternal::WaitForEvents(SceKernelEvent* ev, int num, u32 micros) {
}
}
if (ev->flags & SceKernelEvent::Flags::OneShot) {
for (auto ev_id = 0u; ev_id < count; ++ev_id) {
RemoveEvent(ev->ident, ev->filter);
}
}
return count;
}
@@ -159,18 +162,27 @@ bool EqueueInternal::TriggerEvent(u64 ident, s16 filter, void* trigger_data) {
int EqueueInternal::GetTriggeredEvents(SceKernelEvent* ev, int num) {
int count = 0;
for (auto& event : m_events) {
if (event.IsTriggered()) {
// Event should not trigger again
event.ResetTriggerState();
for (auto it = m_events.begin(); it != m_events.end();) {
if (it->IsTriggered()) {
ev[count++] = it->event;
if (event.event.flags & SceKernelEvent::Flags::Clear) {
event.Clear();
// Event should not trigger again
it->ResetTriggerState();
if (it->event.flags & SceKernelEvent::Flags::Clear) {
it->Clear();
}
ev[count++] = event.event;
if (it->event.flags & SceKernelEvent::Flags::OneShot) {
it = m_events.erase(it);
} else {
++it;
}
if (count == num) {
break;
}
} else {
++it;
}
}
@@ -277,19 +289,11 @@ int PS4_SYSV_ABI sceKernelWaitEqueue(SceKernelEqueue eq, SceKernelEvent* ev, int
}
if (num < 1) {
*out = 0;
return ORBIS_KERNEL_ERROR_EINVAL;
}
if (timo == nullptr) {
// When the timeout is nullptr, we wait indefinitely
*out = eq->WaitForEvents(ev, num, 0);
} else if (*timo == 0) {
// Only events that have already arrived at the time of this function call can be received
*out = eq->GetTriggeredEvents(ev, num);
} else {
// Wait for up to the specified timeout value
*out = eq->WaitForEvents(ev, num, *timo);
}
*out = eq->WaitForEvents(ev, num, timo);
if (*out == 0) {
return ORBIS_KERNEL_ERROR_ETIMEDOUT;

View File

@@ -153,7 +153,7 @@ public:
bool ScheduleEvent(u64 id, s16 filter,
void (*callback)(SceKernelEqueue, const SceKernelEvent&));
bool RemoveEvent(u64 id, s16 filter);
int WaitForEvents(SceKernelEvent* ev, int num, u32 micros);
int WaitForEvents(SceKernelEvent* ev, int num, const SceKernelUseconds* timo);
bool TriggerEvent(u64 ident, s16 filter, void* trigger_data);
int GetTriggeredEvents(SceKernelEvent* ev, int num);