kernel: event_queue: `sceKernelAddHRTimerEvent` implementation
This commit is contained in:
parent
cb6b21de1f
commit
ab36a238bf
|
@ -41,6 +41,8 @@ enum MarkersPallete : int {
|
|||
#define RENDERER_TRACE ZoneScopedC(RendererMarkerColor)
|
||||
#define HLE_TRACE ZoneScopedC(HleMarkerColor)
|
||||
|
||||
#define TRACE_HINT(str) ZoneText(str.c_str(), str.size())
|
||||
|
||||
#define TRACE_WARN(msg) \
|
||||
[](const auto& msg) { TracyMessageC(msg.c_str(), msg.size(), tracy::Color::DarkOrange); }(msg);
|
||||
#define TRACE_ERROR(msg) \
|
||||
|
|
|
@ -8,13 +8,19 @@ namespace Libraries::Kernel {
|
|||
|
||||
EqueueInternal::~EqueueInternal() = default;
|
||||
|
||||
int EqueueInternal::addEvent(const EqueueEvent& event) {
|
||||
int EqueueInternal::addEvent(EqueueEvent& event) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
|
||||
ASSERT(!event.isTriggered);
|
||||
const auto start_clock = std::chrono::high_resolution_clock::now();
|
||||
event.filter.added_time_us =
|
||||
std::chrono::time_point_cast<std::chrono::microseconds>(start_clock);
|
||||
|
||||
// TODO check if event is already exists and return it. Currently we just add in m_events array
|
||||
m_events.push_back(event);
|
||||
const auto& it = std::ranges::find(m_events, event);
|
||||
if (it != m_events.cend()) {
|
||||
*it = event;
|
||||
} else {
|
||||
m_events.push_back(event);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -50,8 +56,8 @@ bool EqueueInternal::triggerEvent(u64 ident, s16 filter, void* trigger_data) {
|
|||
std::scoped_lock lock{m_mutex};
|
||||
|
||||
for (auto& event : m_events) {
|
||||
if (event.event.ident == ident) { // event filter?
|
||||
event.trigger(trigger_data);
|
||||
if (event.event.ident == ident && event.event.filter == filter) {
|
||||
event.Trigger(trigger_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -64,9 +70,9 @@ int EqueueInternal::getTriggeredEvents(SceKernelEvent* ev, int num) {
|
|||
int ret = 0;
|
||||
|
||||
for (auto& event : m_events) {
|
||||
if (event.isTriggered) {
|
||||
if (event.IsTriggered()) {
|
||||
ev[ret++] = event.event;
|
||||
event.reset();
|
||||
event.Reset();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -70,24 +70,44 @@ struct SceKernelEvent {
|
|||
|
||||
struct Filter {
|
||||
void* data = nullptr;
|
||||
std::chrono::time_point<std::chrono::steady_clock, std::chrono::microseconds> added_time_us;
|
||||
};
|
||||
|
||||
struct EqueueEvent {
|
||||
bool isTriggered = false;
|
||||
SceKernelEvent event;
|
||||
Filter filter;
|
||||
|
||||
void reset() {
|
||||
isTriggered = false;
|
||||
void Reset() {
|
||||
is_triggered = false;
|
||||
event.fflags = 0;
|
||||
event.data = 0;
|
||||
}
|
||||
|
||||
void trigger(void* data) {
|
||||
isTriggered = true;
|
||||
void Trigger(void* data) {
|
||||
is_triggered = true;
|
||||
event.fflags++;
|
||||
event.data = reinterpret_cast<uintptr_t>(data);
|
||||
}
|
||||
|
||||
bool IsTriggered() const {
|
||||
if (event.filter == Kernel::EVFILT_HRTIMER) {
|
||||
// For HR timers we don't want to waste time on spawning waiters. Instead, we will check
|
||||
// for time out condition every time caller fetches the event status.
|
||||
const auto now_clock = std::chrono::high_resolution_clock::now();
|
||||
const auto now_time_us =
|
||||
std::chrono::time_point_cast<std::chrono::microseconds>(now_clock);
|
||||
const auto delta = (now_time_us - filter.added_time_us).count();
|
||||
return (s64(event.data) - delta) <= 0;
|
||||
}
|
||||
return is_triggered;
|
||||
}
|
||||
|
||||
bool operator==(const EqueueEvent& ev) const {
|
||||
return ev.event.ident == event.ident;
|
||||
}
|
||||
|
||||
private:
|
||||
bool is_triggered = false;
|
||||
};
|
||||
|
||||
class EqueueInternal {
|
||||
|
@ -97,7 +117,10 @@ public:
|
|||
void setName(const std::string& m_name) {
|
||||
this->m_name = m_name;
|
||||
}
|
||||
int addEvent(const EqueueEvent& event);
|
||||
const auto& GetName() const {
|
||||
return m_name;
|
||||
}
|
||||
int addEvent(EqueueEvent& event);
|
||||
int removeEvent(u64 id);
|
||||
int waitForEvents(SceKernelEvent* ev, int num, u32 micros);
|
||||
bool triggerEvent(u64 ident, s16 filter, void* trigger_data);
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/libraries/error_codes.h"
|
||||
#include "core/libraries/kernel/event_queues.h"
|
||||
|
@ -43,7 +44,9 @@ int PS4_SYSV_ABI sceKernelDeleteEqueue(SceKernelEqueue eq) {
|
|||
|
||||
int PS4_SYSV_ABI sceKernelWaitEqueue(SceKernelEqueue eq, SceKernelEvent* ev, int num, int* out,
|
||||
SceKernelUseconds* timo) {
|
||||
LOG_INFO(Kernel_Event, "num = {}", num);
|
||||
HLE_TRACE;
|
||||
TRACE_HINT(eq->GetName());
|
||||
LOG_INFO(Kernel_Event, "equeue = {} num = {}", eq->GetName(), num);
|
||||
|
||||
if (eq == nullptr) {
|
||||
return ORBIS_KERNEL_ERROR_EBADF;
|
||||
|
@ -84,7 +87,6 @@ int PS4_SYSV_ABI sceKernelAddUserEvent(SceKernelEqueue eq, int id) {
|
|||
}
|
||||
|
||||
Kernel::EqueueEvent event{};
|
||||
event.isTriggered = false;
|
||||
event.event.ident = id;
|
||||
event.event.filter = Kernel::EVFILT_USER;
|
||||
event.event.udata = 0;
|
||||
|
@ -101,7 +103,6 @@ int PS4_SYSV_ABI sceKernelAddUserEventEdge(SceKernelEqueue eq, int id) {
|
|||
}
|
||||
|
||||
Kernel::EqueueEvent event{};
|
||||
event.isTriggered = false;
|
||||
event.event.ident = id;
|
||||
event.event.filter = Kernel::EVFILT_USER;
|
||||
event.event.udata = 0;
|
||||
|
@ -112,6 +113,28 @@ int PS4_SYSV_ABI sceKernelAddUserEventEdge(SceKernelEqueue eq, int id) {
|
|||
return eq->addEvent(event);
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelAddHRTimerEvent(SceKernelEqueue eq, int id, timespec* ts, void* udata) {
|
||||
if (eq == nullptr) {
|
||||
return ORBIS_KERNEL_ERROR_EBADF;
|
||||
}
|
||||
|
||||
if (ts->tv_sec > 100 || ts->tv_nsec < 100'000) {
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
ASSERT(ts->tv_nsec > 1000); // assume 1us granularity
|
||||
const auto total_us = ts->tv_sec * 1000'000 + ts->tv_nsec / 1000;
|
||||
|
||||
Kernel::EqueueEvent event{};
|
||||
event.event.ident = id;
|
||||
event.event.filter = Kernel::EVFILT_HRTIMER;
|
||||
event.event.flags = 0x11;
|
||||
event.event.fflags = 0;
|
||||
event.event.data = total_us;
|
||||
event.event.udata = udata;
|
||||
|
||||
return eq->addEvent(event);
|
||||
}
|
||||
|
||||
void* PS4_SYSV_ABI sceKernelGetEventUserData(const SceKernelEvent* ev) {
|
||||
if (!ev) {
|
||||
return nullptr;
|
||||
|
|
|
@ -19,5 +19,6 @@ int PS4_SYSV_ABI sceKernelTriggerUserEvent(SceKernelEqueue eq, int id, void* uda
|
|||
int PS4_SYSV_ABI sceKernelDeleteUserEvent(SceKernelEqueue eq, int id);
|
||||
int PS4_SYSV_ABI sceKernelAddUserEvent(SceKernelEqueue eq, int id);
|
||||
int PS4_SYSV_ABI sceKernelAddUserEventEdge(SceKernelEqueue eq, int id);
|
||||
s32 PS4_SYSV_ABI sceKernelAddHRTimerEvent(SceKernelEqueue eq, int id, timespec* ts, void* udata);
|
||||
|
||||
} // namespace Libraries::Kernel
|
||||
|
|
|
@ -328,6 +328,7 @@ void LibKernel_Register(Core::Loader::SymbolsResolver* sym) {
|
|||
LIB_FUNCTION("vz+pg2zdopI", "libkernel", 1, "libkernel", 1, 1, sceKernelGetEventUserData);
|
||||
LIB_FUNCTION("4R6-OvI2cEA", "libkernel", 1, "libkernel", 1, 1, sceKernelAddUserEvent);
|
||||
LIB_FUNCTION("WDszmSbWuDk", "libkernel", 1, "libkernel", 1, 1, sceKernelAddUserEventEdge);
|
||||
LIB_FUNCTION("R74tt43xP6k", "libkernel", 1, "libkernel", 1, 1, sceKernelAddHRTimerEvent);
|
||||
LIB_FUNCTION("F6e0kwo4cnk", "libkernel", 1, "libkernel", 1, 1, sceKernelTriggerUserEvent);
|
||||
LIB_FUNCTION("LJDwdSNTnDg", "libkernel", 1, "libkernel", 1, 1, sceKernelDeleteUserEvent);
|
||||
|
||||
|
|
|
@ -48,7 +48,6 @@ s32 PS4_SYSV_ABI sceVideoOutAddFlipEvent(Kernel::SceKernelEqueue eq, s32 handle,
|
|||
}
|
||||
|
||||
Kernel::EqueueEvent event{};
|
||||
event.isTriggered = false;
|
||||
event.event.ident = SCE_VIDEO_OUT_EVENT_FLIP;
|
||||
event.event.filter = Kernel::EVFILT_VIDEO_OUT;
|
||||
event.event.udata = udata;
|
||||
|
@ -73,7 +72,6 @@ s32 PS4_SYSV_ABI sceVideoOutAddVblankEvent(Kernel::SceKernelEqueue eq, s32 handl
|
|||
}
|
||||
|
||||
Kernel::EqueueEvent event{};
|
||||
event.isTriggered = false;
|
||||
event.event.ident = SCE_VIDEO_OUT_EVENT_VBLANK;
|
||||
event.event.filter = Kernel::EVFILT_VIDEO_OUT;
|
||||
event.event.udata = udata;
|
||||
|
|
Loading…
Reference in New Issue