2024-02-23 22:32:32 +01:00
|
|
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
|
2024-04-14 16:09:51 +02:00
|
|
|
#include "common/assert.h"
|
2024-04-13 23:35:48 +02:00
|
|
|
#include "core/libraries/kernel/event_queue.h"
|
2023-11-06 00:11:54 +01:00
|
|
|
|
2024-04-13 23:35:48 +02:00
|
|
|
namespace Libraries::Kernel {
|
2023-10-22 16:17:43 +02:00
|
|
|
|
2023-11-06 00:11:54 +01:00
|
|
|
EqueueInternal::~EqueueInternal() = default;
|
2023-09-05 13:28:52 +02:00
|
|
|
|
2024-07-09 12:12:15 +02:00
|
|
|
bool EqueueInternal::AddEvent(EqueueEvent& event) {
|
2023-10-22 16:10:25 +02:00
|
|
|
std::scoped_lock lock{m_mutex};
|
2023-09-05 13:28:52 +02:00
|
|
|
|
2024-07-11 09:09:37 +02:00
|
|
|
event.time_added = std::chrono::steady_clock::now();
|
2024-04-14 16:09:51 +02:00
|
|
|
|
2024-07-09 12:12:15 +02:00
|
|
|
const auto& it = std::ranges::find(m_events, event);
|
|
|
|
if (it != m_events.cend()) {
|
2024-07-10 20:02:56 +02:00
|
|
|
*it = std::move(event);
|
2024-07-09 12:12:15 +02:00
|
|
|
} else {
|
2024-07-10 20:02:56 +02:00
|
|
|
m_events.emplace_back(std::move(event));
|
2024-07-09 12:12:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2023-09-05 13:28:52 +02:00
|
|
|
}
|
|
|
|
|
2024-07-09 12:12:15 +02:00
|
|
|
bool EqueueInternal::RemoveEvent(u64 id) {
|
|
|
|
bool has_found = false;
|
2024-05-17 23:32:15 +02:00
|
|
|
std::scoped_lock lock{m_mutex};
|
|
|
|
|
2024-07-09 12:12:15 +02:00
|
|
|
const auto& it =
|
2024-05-10 23:51:24 +02:00
|
|
|
std::ranges::find_if(m_events, [id](auto& ev) { return ev.event.ident == id; });
|
2024-07-09 12:12:15 +02:00
|
|
|
if (it != m_events.cend()) {
|
|
|
|
m_events.erase(it);
|
|
|
|
has_found = true;
|
|
|
|
}
|
|
|
|
return has_found;
|
2024-05-07 22:46:54 +02:00
|
|
|
}
|
|
|
|
|
2024-07-09 12:12:15 +02:00
|
|
|
int EqueueInternal::WaitForEvents(SceKernelEvent* ev, int num, u32 micros) {
|
2024-07-10 20:02:56 +02:00
|
|
|
int count = 0;
|
2023-09-10 00:06:14 +02:00
|
|
|
|
2024-02-14 23:52:57 +01:00
|
|
|
const auto predicate = [&] {
|
2024-07-10 20:02:56 +02:00
|
|
|
count = GetTriggeredEvents(ev, num);
|
|
|
|
return count > 0;
|
2024-02-14 23:52:57 +01:00
|
|
|
};
|
2024-05-29 00:28:34 +02:00
|
|
|
|
2024-02-14 23:52:57 +01:00
|
|
|
if (micros == 0) {
|
2024-07-10 20:02:56 +02:00
|
|
|
std::unique_lock lock{m_mutex};
|
2024-02-14 23:52:57 +01:00
|
|
|
m_cond.wait(lock, predicate);
|
|
|
|
} else {
|
2024-07-10 20:02:56 +02:00
|
|
|
std::unique_lock lock{m_mutex};
|
2024-02-14 23:52:57 +01:00
|
|
|
m_cond.wait_for(lock, std::chrono::microseconds(micros), predicate);
|
2023-09-10 00:06:14 +02:00
|
|
|
}
|
2024-07-10 20:02:56 +02:00
|
|
|
|
2024-07-11 09:09:37 +02:00
|
|
|
if (HasSmallTimer()) {
|
|
|
|
if (count > 0) {
|
|
|
|
const auto time_waited = std::chrono::duration_cast<std::chrono::microseconds>(
|
|
|
|
std::chrono::steady_clock::now() - m_events[0].time_added)
|
|
|
|
.count();
|
|
|
|
count = WaitForSmallTimer(ev, num, std::max(0l, long(micros - time_waited)));
|
|
|
|
}
|
|
|
|
small_timer_event.event.data = 0;
|
|
|
|
}
|
|
|
|
|
2024-07-10 20:02:56 +02:00
|
|
|
if (ev->flags & SceKernelEvent::Flags::OneShot) {
|
|
|
|
for (auto ev_id = 0u; ev_id < count; ++ev_id) {
|
|
|
|
RemoveEvent(ev->ident);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return count;
|
2023-09-10 00:06:14 +02:00
|
|
|
}
|
|
|
|
|
2024-07-09 12:12:15 +02:00
|
|
|
bool EqueueInternal::TriggerEvent(u64 ident, s16 filter, void* trigger_data) {
|
|
|
|
bool has_found = false;
|
2024-05-17 23:32:15 +02:00
|
|
|
{
|
|
|
|
std::scoped_lock lock{m_mutex};
|
|
|
|
|
|
|
|
for (auto& event : m_events) {
|
2024-07-09 12:12:15 +02:00
|
|
|
ASSERT_MSG(event.event.filter == filter,
|
|
|
|
"Event to trigger doesn't match to queue events");
|
|
|
|
if (event.event.ident == ident) {
|
|
|
|
event.Trigger(trigger_data);
|
|
|
|
has_found = true;
|
2024-05-17 23:32:15 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-10-22 16:10:25 +02:00
|
|
|
m_cond.notify_one();
|
2024-07-09 12:12:15 +02:00
|
|
|
return has_found;
|
2023-09-11 12:14:13 +02:00
|
|
|
}
|
|
|
|
|
2024-07-09 12:12:15 +02:00
|
|
|
int EqueueInternal::GetTriggeredEvents(SceKernelEvent* ev, int num) {
|
2024-07-10 20:02:56 +02:00
|
|
|
int count = 0;
|
2023-09-10 00:06:14 +02:00
|
|
|
|
2024-05-17 23:32:15 +02:00
|
|
|
for (auto& event : m_events) {
|
2024-07-09 12:12:15 +02:00
|
|
|
if (event.IsTriggered()) {
|
|
|
|
if (ev->flags & SceKernelEvent::Flags::Clear) {
|
|
|
|
event.Reset();
|
|
|
|
}
|
|
|
|
|
2024-07-10 20:02:56 +02:00
|
|
|
ev[count++] = event.event;
|
2024-07-09 12:12:15 +02:00
|
|
|
|
2024-07-10 20:02:56 +02:00
|
|
|
if (count == num) {
|
2024-07-09 12:12:15 +02:00
|
|
|
break;
|
|
|
|
}
|
2024-05-17 23:32:15 +02:00
|
|
|
}
|
2023-09-10 00:06:14 +02:00
|
|
|
}
|
|
|
|
|
2024-07-10 20:02:56 +02:00
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool EqueueInternal::AddSmallTimer(EqueueEvent& ev) {
|
|
|
|
// We assume that only one timer event (with the same ident across calls)
|
|
|
|
// can be posted to the queue, based on observations so far. In the opposite case,
|
|
|
|
// the small timer storage and wait logic should be reworked.
|
|
|
|
ASSERT(!HasSmallTimer() || small_timer_event.event.ident == ev.event.ident);
|
2024-07-11 09:09:37 +02:00
|
|
|
ev.time_added = std::chrono::steady_clock::now();
|
2024-07-10 20:02:56 +02:00
|
|
|
small_timer_event = std::move(ev);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
int EqueueInternal::WaitForSmallTimer(SceKernelEvent* ev, int num, u32 micros) {
|
|
|
|
int count{};
|
|
|
|
|
|
|
|
ASSERT(num == 1);
|
|
|
|
|
2024-07-11 09:09:37 +02:00
|
|
|
auto curr_clock = std::chrono::steady_clock::now();
|
2024-07-10 20:02:56 +02:00
|
|
|
const auto wait_end_us = curr_clock + std::chrono::microseconds{micros};
|
|
|
|
|
|
|
|
do {
|
2024-07-11 09:09:37 +02:00
|
|
|
curr_clock = std::chrono::steady_clock::now();
|
2024-07-10 20:02:56 +02:00
|
|
|
|
|
|
|
{
|
|
|
|
std::unique_lock lock{m_mutex};
|
|
|
|
if ((curr_clock - small_timer_event.time_added) >
|
|
|
|
std::chrono::microseconds{small_timer_event.event.data}) {
|
|
|
|
ev[count++] = small_timer_event.event;
|
|
|
|
small_timer_event.event.data = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::this_thread::yield();
|
|
|
|
|
|
|
|
} while (curr_clock < wait_end_us);
|
|
|
|
|
|
|
|
return count;
|
2023-09-10 00:06:14 +02:00
|
|
|
}
|
|
|
|
|
2024-04-13 23:35:48 +02:00
|
|
|
} // namespace Libraries::Kernel
|