kernel: event_queue: initial `sceKernelAddHRTimerEvent` added

This commit is contained in:
psucien 2024-06-18 10:10:27 +02:00
parent a5d22b8151
commit 53dd407ae3
5 changed files with 43 additions and 5 deletions

View File

@ -8,15 +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);
const auto& it = std::ranges::find(m_events, event);
ASSERT(it == m_events.cend()); // TODO: update event if found
m_events.push_back(event);
if (it != m_events.cend()) {
*it = event;
} else {
m_events.push_back(event);
}
return 0;
}

View File

@ -70,6 +70,7 @@ struct SceKernelEvent {
struct Filter {
void* data = nullptr;
std::chrono::time_point<std::chrono::steady_clock, std::chrono::microseconds> added_time_us;
};
struct EqueueEvent {
@ -89,6 +90,15 @@ struct EqueueEvent {
}
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;
}

View File

@ -113,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;

View File

@ -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

View File

@ -324,6 +324,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);