kernel: File cleanup pt1

This commit is contained in:
IndecisiveTurtle 2024-10-23 23:02:20 +03:00
parent d0d8b5eee5
commit 77ff4290d6
27 changed files with 445 additions and 535 deletions

View file

@ -208,10 +208,9 @@ set(GNM_LIB src/core/libraries/gnmdriver/gnmdriver.cpp
src/core/libraries/gnmdriver/gnm_error.h
)
set(KERNEL_LIB src/core/libraries/kernel/event_flag/event_flag.cpp
src/core/libraries/kernel/event_flag/event_flag.h
src/core/libraries/kernel/event_flag/event_flag_obj.cpp
src/core/libraries/kernel/event_flag/event_flag_obj.h
set(KERNEL_LIB
src/core/libraries/kernel/threads/event_flag.cpp
src/core/libraries/kernel/threads/event_flag.h
src/core/libraries/kernel/threads/thr_attr.cpp
src/core/libraries/kernel/threads/thr_cond.cpp
src/core/libraries/kernel/threads/thr_create.cpp
@ -220,16 +219,19 @@ set(KERNEL_LIB src/core/libraries/kernel/event_flag/event_flag.cpp
src/core/libraries/kernel/threads/thr_rwlock.cpp
src/core/libraries/kernel/threads/thr_sem.cpp
src/core/libraries/kernel/threads/thr_spec.cpp
src/core/libraries/kernel/threads/thr_stack.cpp
src/core/libraries/kernel/threads/thr_clean.cpp
src/core/libraries/kernel/threads/thread_state.cpp
src/core/libraries/kernel/threads/thread_state.h
src/core/libraries/kernel/threads/thr_ctrdtr.cpp
src/core/libraries/kernel/cpu_management.cpp
src/core/libraries/kernel/cpu_management.h
src/core/libraries/kernel/event_queue.cpp
src/core/libraries/kernel/event_queue.h
src/core/libraries/kernel/event_queues.cpp
src/core/libraries/kernel/event_queues.h
src/core/libraries/kernel/file_system.cpp
src/core/libraries/kernel/file_system.h
src/core/libraries/kernel/libkernel.cpp
src/core/libraries/kernel/libkernel.h
src/core/libraries/kernel/kernel.cpp
src/core/libraries/kernel/kernel.h
src/core/libraries/kernel/memory_management.cpp
src/core/libraries/kernel/memory_management.h
src/core/libraries/kernel/thread_management.cpp
@ -457,7 +459,10 @@ set(COMMON src/common/logging/backend.cpp
src/common/signal_context.h
src/common/signal_context.cpp
src/common/singleton.h
src/common/slab_heap.h
src/common/slot_vector.h
src/common/spin_lock.cpp
src/common/spin_lock.h
src/common/string_util.cpp
src/common/string_util.h
src/common/thread.cpp
@ -816,14 +821,6 @@ else()
src/emulator.h
src/sdl_window.h
src/sdl_window.cpp
src/core/libraries/kernel/threads/thr_stack.cpp
src/core/libraries/kernel/threads/thr_exit.cpp
src/core/libraries/kernel/threads/thr_clean.cpp
src/core/libraries/kernel/threads/thread_state.h src/core/libraries/kernel/threads/thread_state.cpp
src/core/libraries/kernel/threads/thr_ctrdtr.cpp
src/common/slab_heap.h
src/common/spin_lock.cpp
src/common/spin_lock.h
)
endif()

View file

@ -41,7 +41,7 @@ enum MarkersPalette : int {
#define RENDERER_TRACE ZoneScopedC(RendererMarkerColor)
#define HLE_TRACE ZoneScopedC(HleMarkerColor)
#define TRACE_HINT(str) ZoneText(str.c_str(), str.size())
#define TRACE_HINT(str) ZoneText(str.data(), str.size())
#define TRACE_WARN(msg) \
[](const auto& msg) { TracyMessageC(msg.c_str(), msg.size(), tracy::Color::DarkOrange); }(msg);

View file

@ -6,7 +6,7 @@
#include "common/logging/log.h"
#include "core/libraries/error_codes.h"
#include "core/libraries/kernel/libkernel.h"
#include "core/libraries/kernel/kernel.h"
using namespace Libraries::Kernel;

View file

@ -1,6 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma clang optimize off
#include "gnm_error.h"
#include "gnmdriver.h"
@ -8,7 +8,6 @@
#include "common/config.h"
#include "common/debug.h"
#include "common/logging/log.h"
#include "common/path_util.h"
#include "common/slot_vector.h"
#include "core/address_space.h"
#include "core/debug_state.h"

View file

@ -1,40 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/types.h"
#include "event_flag_codes.h"
#include "event_flag_obj.h"
namespace Core::Loader {
class SymbolsResolver;
}
namespace Libraries::Kernel {
using OrbisKernelUseconds = u32;
using OrbisKernelEventFlag = EventFlagInternal*;
struct OrbisKernelEventFlagOptParam {
size_t size;
};
int PS4_SYSV_ABI sceKernelCreateEventFlag(OrbisKernelEventFlag* ef, const char* pName, u32 attr,
u64 initPattern,
const OrbisKernelEventFlagOptParam* pOptParam);
int PS4_SYSV_ABI sceKernelDeleteEventFlag(OrbisKernelEventFlag ef);
int PS4_SYSV_ABI sceKernelOpenEventFlag();
int PS4_SYSV_ABI sceKernelCloseEventFlag();
int PS4_SYSV_ABI sceKernelClearEventFlag(OrbisKernelEventFlag ef, u64 bitPattern);
int PS4_SYSV_ABI sceKernelCancelEventFlag(OrbisKernelEventFlag ef, u64 setPattern,
int* pNumWaitThreads);
int PS4_SYSV_ABI sceKernelSetEventFlag(OrbisKernelEventFlag ef, u64 bitPattern);
int PS4_SYSV_ABI sceKernelPollEventFlag(OrbisKernelEventFlag ef, u64 bitPattern, u32 waitMode,
u64* pResultPat);
int PS4_SYSV_ABI sceKernelWaitEventFlag(OrbisKernelEventFlag ef, u64 bitPattern, u32 waitMode,
u64* pResultPat, OrbisKernelUseconds* pTimeout);
void RegisterKernelEventFlag(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::Kernel

View file

@ -1,14 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
constexpr int ORBIS_KERNEL_EVF_ATTR_TH_FIFO = 0x01;
constexpr int ORBIS_KERNEL_EVF_ATTR_TH_PRIO = 0x02;
constexpr int ORBIS_KERNEL_EVF_ATTR_SINGLE = 0x10;
constexpr int ORBIS_KERNEL_EVF_ATTR_MULTI = 0x20;
constexpr int ORBIS_KERNEL_EVF_WAITMODE_AND = 0x01;
constexpr int ORBIS_KERNEL_EVF_WAITMODE_OR = 0x02;
constexpr int ORBIS_KERNEL_EVF_WAITMODE_CLEAR_ALL = 0x10;
constexpr int ORBIS_KERNEL_EVF_WAITMODE_CLEAR_PAT = 0x20;

View file

@ -1,111 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <thread>
#include "core/libraries/error_codes.h"
#include "event_flag_obj.h"
namespace Libraries::Kernel {
int EventFlagInternal::Wait(u64 bits, WaitMode wait_mode, ClearMode clear_mode, u64* result,
u32* ptr_micros) {
std::unique_lock lock{m_mutex};
uint32_t micros = 0;
bool infinitely = true;
if (ptr_micros != nullptr) {
micros = *ptr_micros;
infinitely = false;
}
if (m_thread_mode == ThreadMode::Single && m_waiting_threads > 0) {
return ORBIS_KERNEL_ERROR_EPERM;
}
auto const start = std::chrono::system_clock::now();
m_waiting_threads++;
auto waitFunc = [this, wait_mode, bits] {
return (m_status == Status::Canceled || m_status == Status::Deleted ||
(wait_mode == WaitMode::And && (m_bits & bits) == bits) ||
(wait_mode == WaitMode::Or && (m_bits & bits) != 0));
};
if (infinitely) {
m_cond_var.wait(lock, waitFunc);
} else {
if (!m_cond_var.wait_for(lock, std::chrono::microseconds(micros), waitFunc)) {
if (result != nullptr) {
*result = m_bits;
}
*ptr_micros = 0;
--m_waiting_threads;
return ORBIS_KERNEL_ERROR_ETIMEDOUT;
}
}
--m_waiting_threads;
if (result != nullptr) {
*result = m_bits;
}
auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::system_clock::now() - start)
.count();
if (result != nullptr) {
*result = m_bits;
}
if (ptr_micros != nullptr) {
*ptr_micros = (elapsed >= micros ? 0 : micros - elapsed);
}
if (m_status == Status::Canceled) {
return ORBIS_KERNEL_ERROR_ECANCELED;
} else if (m_status == Status::Deleted) {
return ORBIS_KERNEL_ERROR_EACCES;
}
if (clear_mode == ClearMode::All) {
m_bits = 0;
} else if (clear_mode == ClearMode::Bits) {
m_bits &= ~bits;
}
return ORBIS_OK;
}
int EventFlagInternal::Poll(u64 bits, WaitMode wait_mode, ClearMode clear_mode, u64* result) {
u32 micros = 0;
auto ret = Wait(bits, wait_mode, clear_mode, result, &micros);
if (ret == ORBIS_KERNEL_ERROR_ETIMEDOUT) {
// Poll returns EBUSY instead.
ret = ORBIS_KERNEL_ERROR_EBUSY;
}
return ret;
}
void EventFlagInternal::Set(u64 bits) {
std::unique_lock lock{m_mutex};
while (m_status != Status::Set) {
m_mutex.unlock();
std::this_thread::sleep_for(std::chrono::microseconds(10));
m_mutex.lock();
}
m_bits |= bits;
m_cond_var.notify_all();
}
void EventFlagInternal::Clear(u64 bits) {
std::unique_lock lock{m_mutex};
while (m_status != Status::Set) {
m_mutex.unlock();
std::this_thread::sleep_for(std::chrono::microseconds(10));
m_mutex.lock();
}
m_bits &= bits;
}
} // namespace Libraries::Kernel

View file

@ -1,44 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <condition_variable>
#include <mutex>
#include "common/types.h"
namespace Libraries::Kernel {
class EventFlagInternal {
public:
enum class ClearMode { None, All, Bits };
enum class WaitMode { And, Or };
enum class ThreadMode { Single, Multi };
enum class QueueMode { Fifo, ThreadPrio };
EventFlagInternal(const std::string& name, ThreadMode thread_mode, QueueMode queue_mode,
uint64_t bits)
: m_name(name), m_thread_mode(thread_mode), m_queue_mode(queue_mode), m_bits(bits){};
int Wait(u64 bits, WaitMode wait_mode, ClearMode clear_mode, u64* result, u32* ptr_micros);
int Poll(u64 bits, WaitMode wait_mode, ClearMode clear_mode, u64* result);
void Set(u64 bits);
void Clear(u64 bits);
private:
enum class Status { Set, Canceled, Deleted };
std::mutex m_mutex;
std::condition_variable m_cond_var;
Status m_status = Status::Set;
int m_waiting_threads = 0;
std::string m_name;
ThreadMode m_thread_mode = ThreadMode::Single;
QueueMode m_queue_mode = QueueMode::Fifo;
u64 m_bits = 0;
};
} // namespace Libraries::Kernel

View file

@ -1,145 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <thread>
#include "common/assert.h"
#include "core/libraries/kernel/event_queue.h"
namespace Libraries::Kernel {
EqueueInternal::~EqueueInternal() = default;
bool EqueueInternal::AddEvent(EqueueEvent& event) {
std::scoped_lock lock{m_mutex};
event.time_added = std::chrono::steady_clock::now();
const auto& it = std::ranges::find(m_events, event);
if (it != m_events.cend()) {
*it = std::move(event);
} else {
m_events.emplace_back(std::move(event));
}
return true;
}
bool EqueueInternal::RemoveEvent(u64 id) {
bool has_found = false;
std::scoped_lock lock{m_mutex};
const auto& it =
std::ranges::find_if(m_events, [id](auto& ev) { return ev.event.ident == id; });
if (it != m_events.cend()) {
m_events.erase(it);
has_found = true;
}
return has_found;
}
int EqueueInternal::WaitForEvents(SceKernelEvent* ev, int num, u32 micros) {
int count = 0;
const auto predicate = [&] {
count = GetTriggeredEvents(ev, num);
return count > 0;
};
if (micros == 0) {
std::unique_lock lock{m_mutex};
m_cond.wait(lock, predicate);
} else {
std::unique_lock lock{m_mutex};
m_cond.wait_for(lock, std::chrono::microseconds(micros), predicate);
}
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;
}
if (ev->flags & SceKernelEvent::Flags::OneShot) {
for (auto ev_id = 0u; ev_id < count; ++ev_id) {
RemoveEvent(ev->ident);
}
}
return count;
}
bool EqueueInternal::TriggerEvent(u64 ident, s16 filter, void* trigger_data) {
bool has_found = false;
{
std::scoped_lock lock{m_mutex};
for (auto& event : m_events) {
if ((event.event.ident == ident) && (event.event.filter == filter)) {
event.Trigger(trigger_data);
has_found = true;
}
}
}
m_cond.notify_one();
return has_found;
}
int EqueueInternal::GetTriggeredEvents(SceKernelEvent* ev, int num) {
int count = 0;
for (auto& event : m_events) {
if (event.IsTriggered()) {
if (event.event.flags & SceKernelEvent::Flags::Clear) {
event.Reset();
}
ev[count++] = event.event;
if (count == num) {
break;
}
}
}
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);
ev.time_added = std::chrono::steady_clock::now();
small_timer_event = std::move(ev);
return true;
}
int EqueueInternal::WaitForSmallTimer(SceKernelEvent* ev, int num, u32 micros) {
int count{};
ASSERT(num == 1);
auto curr_clock = std::chrono::steady_clock::now();
const auto wait_end_us = curr_clock + std::chrono::microseconds{micros};
do {
curr_clock = std::chrono::steady_clock::now();
{
std::scoped_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;
}
} // namespace Libraries::Kernel

View file

@ -1,122 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <condition_variable>
#include <mutex>
#include <string>
#include <vector>
#include <boost/asio/steady_timer.hpp>
#include "common/types.h"
namespace Core::Loader {
class SymbolsResolver;
}
namespace Libraries::Kernel {
class EqueueInternal;
struct EqueueEvent;
struct SceKernelEvent {
enum Filter : s16 {
None = 0,
Read = -1,
Write = -2,
Aio = -3,
Vnode = -4,
Proc = -5,
Signal = -6,
Timer = -7,
Fs = -9,
Lio = -10,
User = -11,
Polling = -12,
VideoOut = -13,
GraphicsCore = -14,
HrTimer = -15,
};
enum Flags : u16 {
Add = 1u,
Delete = 2u,
Enable = 4u,
Disable = 8u,
OneShot = 0x10u,
Clear = 0x20u,
Receipt = 0x40u,
Dispatch = 0x80u,
Flag1 = 0x2000u,
System = 0xf000u,
};
u64 ident = 0; /* identifier for this event */
Filter filter = Filter::None; /* filter for event */
u16 flags = 0;
u32 fflags = 0;
u64 data = 0;
void* udata = nullptr; /* opaque user data identifier */
};
struct EqueueEvent {
SceKernelEvent event;
void* data = nullptr;
std::chrono::steady_clock::time_point time_added;
std::unique_ptr<boost::asio::steady_timer> timer;
void Reset() {
is_triggered = false;
event.fflags = 0;
event.data = 0;
}
void Trigger(void* data) {
is_triggered = true;
event.fflags++;
event.data = reinterpret_cast<uintptr_t>(data);
}
bool IsTriggered() const {
return is_triggered;
}
bool operator==(const EqueueEvent& ev) const {
return ev.event.ident == event.ident;
}
private:
bool is_triggered = false;
};
class EqueueInternal {
public:
EqueueInternal() = default;
virtual ~EqueueInternal();
void setName(const std::string& m_name) {
this->m_name = m_name;
}
const auto& GetName() const {
return m_name;
}
bool AddEvent(EqueueEvent& event);
bool RemoveEvent(u64 id);
int WaitForEvents(SceKernelEvent* ev, int num, u32 micros);
bool TriggerEvent(u64 ident, s16 filter, void* trigger_data);
int GetTriggeredEvents(SceKernelEvent* ev, int num);
bool AddSmallTimer(EqueueEvent& event);
bool HasSmallTimer() const {
return small_timer_event.event.data != 0;
}
int WaitForSmallTimer(SceKernelEvent* ev, int num, u32 micros);
private:
std::string m_name;
std::mutex m_mutex;
std::vector<EqueueEvent> m_events;
EqueueEvent small_timer_event{};
std::condition_variable m_cond;
};
} // namespace Libraries::Kernel

View file

@ -10,6 +10,138 @@
namespace Libraries::Kernel {
bool EqueueInternal::AddEvent(EqueueEvent& event) {
std::scoped_lock lock{m_mutex};
event.time_added = std::chrono::steady_clock::now();
const auto& it = std::ranges::find(m_events, event);
if (it != m_events.cend()) {
*it = std::move(event);
} else {
m_events.emplace_back(std::move(event));
}
return true;
}
bool EqueueInternal::RemoveEvent(u64 id) {
bool has_found = false;
std::scoped_lock lock{m_mutex};
const auto& it =
std::ranges::find_if(m_events, [id](auto& ev) { return ev.event.ident == id; });
if (it != m_events.cend()) {
m_events.erase(it);
has_found = true;
}
return has_found;
}
int EqueueInternal::WaitForEvents(SceKernelEvent* ev, int num, u32 micros) {
int count = 0;
const auto predicate = [&] {
count = GetTriggeredEvents(ev, num);
return count > 0;
};
if (micros == 0) {
std::unique_lock lock{m_mutex};
m_cond.wait(lock, predicate);
} else {
std::unique_lock lock{m_mutex};
m_cond.wait_for(lock, std::chrono::microseconds(micros), predicate);
}
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;
}
if (ev->flags & SceKernelEvent::Flags::OneShot) {
for (auto ev_id = 0u; ev_id < count; ++ev_id) {
RemoveEvent(ev->ident);
}
}
return count;
}
bool EqueueInternal::TriggerEvent(u64 ident, s16 filter, void* trigger_data) {
bool has_found = false;
{
std::scoped_lock lock{m_mutex};
for (auto& event : m_events) {
if ((event.event.ident == ident) && (event.event.filter == filter)) {
event.Trigger(trigger_data);
has_found = true;
}
}
}
m_cond.notify_one();
return has_found;
}
int EqueueInternal::GetTriggeredEvents(SceKernelEvent* ev, int num) {
int count = 0;
for (auto& event : m_events) {
if (event.IsTriggered()) {
if (event.event.flags & SceKernelEvent::Flags::Clear) {
event.Reset();
}
ev[count++] = event.event;
if (count == num) {
break;
}
}
}
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);
ev.time_added = std::chrono::steady_clock::now();
small_timer_event = std::move(ev);
return true;
}
int EqueueInternal::WaitForSmallTimer(SceKernelEvent* ev, int num, u32 micros) {
int count{};
ASSERT(num == 1);
auto curr_clock = std::chrono::steady_clock::now();
const auto wait_end_us = curr_clock + std::chrono::microseconds{micros};
do {
curr_clock = std::chrono::steady_clock::now();
{
std::scoped_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;
}
extern boost::asio::io_context io_context;
extern void KernelSignalRequest();
@ -43,8 +175,7 @@ int PS4_SYSV_ABI sceKernelCreateEqueue(SceKernelEqueue* eq, const char* name) {
LOG_INFO(Kernel_Event, "name = {}", name);
*eq = new EqueueInternal;
(*eq)->setName(std::string(name));
*eq = new EqueueInternal(name);
return ORBIS_OK;
}

View file

@ -3,7 +3,13 @@
#pragma once
#include "core/libraries/kernel/event_queue.h"
#include <condition_variable>
#include <mutex>
#include <string>
#include <vector>
#include <boost/asio/steady_timer.hpp>
#include "common/types.h"
namespace Core::Loader {
class SymbolsResolver;
@ -11,22 +17,111 @@ class SymbolsResolver;
namespace Libraries::Kernel {
class EqueueInternal;
struct EqueueEvent;
struct SceKernelEvent {
enum Filter : s16 {
None = 0,
Read = -1,
Write = -2,
Aio = -3,
Vnode = -4,
Proc = -5,
Signal = -6,
Timer = -7,
Fs = -9,
Lio = -10,
User = -11,
Polling = -12,
VideoOut = -13,
GraphicsCore = -14,
HrTimer = -15,
};
enum Flags : u16 {
Add = 1u,
Delete = 2u,
Enable = 4u,
Disable = 8u,
OneShot = 0x10u,
Clear = 0x20u,
Receipt = 0x40u,
Dispatch = 0x80u,
Flag1 = 0x2000u,
System = 0xf000u,
};
u64 ident = 0; /* identifier for this event */
Filter filter = Filter::None; /* filter for event */
u16 flags = 0;
u32 fflags = 0;
u64 data = 0;
void* udata = nullptr; /* opaque user data identifier */
};
struct EqueueEvent {
SceKernelEvent event;
void* data = nullptr;
std::chrono::steady_clock::time_point time_added;
std::unique_ptr<boost::asio::steady_timer> timer;
void Reset() {
is_triggered = false;
event.fflags = 0;
event.data = 0;
}
void Trigger(void* data) {
is_triggered = true;
event.fflags++;
event.data = reinterpret_cast<uintptr_t>(data);
}
bool IsTriggered() const {
return is_triggered;
}
bool operator==(const EqueueEvent& ev) const {
return ev.event.ident == event.ident;
}
private:
bool is_triggered = false;
};
class EqueueInternal {
public:
explicit EqueueInternal(std::string_view name) : m_name(name) {}
std::string_view GetName() const {
return m_name;
}
bool AddEvent(EqueueEvent& event);
bool RemoveEvent(u64 id);
int WaitForEvents(SceKernelEvent* ev, int num, u32 micros);
bool TriggerEvent(u64 ident, s16 filter, void* trigger_data);
int GetTriggeredEvents(SceKernelEvent* ev, int num);
bool AddSmallTimer(EqueueEvent& event);
bool HasSmallTimer() const {
return small_timer_event.event.data != 0;
}
int WaitForSmallTimer(SceKernelEvent* ev, int num, u32 micros);
private:
std::string m_name;
std::mutex m_mutex;
std::vector<EqueueEvent> m_events;
EqueueEvent small_timer_event{};
std::condition_variable m_cond;
};
using SceKernelUseconds = u32;
using SceKernelEqueue = EqueueInternal*;
int PS4_SYSV_ABI sceKernelCreateEqueue(SceKernelEqueue* eq, const char* name);
int PS4_SYSV_ABI sceKernelDeleteEqueue(SceKernelEqueue eq);
int PS4_SYSV_ABI sceKernelWaitEqueue(SceKernelEqueue eq, SceKernelEvent* ev, int num, int* out,
SceKernelUseconds* timo);
void* PS4_SYSV_ABI sceKernelGetEventUserData(const SceKernelEvent* ev);
u64 PS4_SYSV_ABI sceKernelGetEventId(const SceKernelEvent* ev);
int PS4_SYSV_ABI sceKernelTriggerUserEvent(SceKernelEqueue eq, int id, void* udata);
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);
s16 PS4_SYSV_ABI sceKernelGetEventFilter(const SceKernelEvent* ev);
void RegisterEventQueue(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::Kernel

View file

@ -9,7 +9,7 @@
#include "core/libraries/error_codes.h"
#include "core/libraries/kernel/file_system.h"
#include "core/libraries/libs.h"
#include "libkernel.h"
#include "kernel.h"
namespace Libraries::Kernel {

View file

@ -14,10 +14,10 @@
#include "core/file_sys/fs.h"
#include "core/libraries/error_codes.h"
#include "core/libraries/kernel/cpu_management.h"
#include "core/libraries/kernel/event_flag/event_flag.h"
#include "core/libraries/kernel/threads/event_flag.h"
#include "core/libraries/kernel/event_queues.h"
#include "core/libraries/kernel/file_system.h"
#include "core/libraries/kernel/libkernel.h"
#include "core/libraries/kernel/kernel.h"
#include "core/libraries/kernel/memory_management.h"
#include "core/libraries/kernel/thread_management.h"
#include "core/libraries/kernel/time_management.h"

View file

@ -1,7 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/libraries/kernel/libkernel.h"
#include "core/libraries/kernel/kernel.h"
#include "core/libraries/kernel/thread_management.h"
#include "core/libraries/kernel/threads/threads.h"

View file

@ -1,13 +1,157 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <condition_variable>
#include <mutex>
#include "common/assert.h"
#include "common/logging/log.h"
#include "core/libraries/error_codes.h"
#include "core/libraries/libs.h"
#include "event_flag.h"
namespace Libraries::Kernel {
constexpr int ORBIS_KERNEL_EVF_ATTR_TH_FIFO = 0x01;
constexpr int ORBIS_KERNEL_EVF_ATTR_TH_PRIO = 0x02;
constexpr int ORBIS_KERNEL_EVF_ATTR_SINGLE = 0x10;
constexpr int ORBIS_KERNEL_EVF_ATTR_MULTI = 0x20;
constexpr int ORBIS_KERNEL_EVF_WAITMODE_AND = 0x01;
constexpr int ORBIS_KERNEL_EVF_WAITMODE_OR = 0x02;
constexpr int ORBIS_KERNEL_EVF_WAITMODE_CLEAR_ALL = 0x10;
constexpr int ORBIS_KERNEL_EVF_WAITMODE_CLEAR_PAT = 0x20;
class EventFlagInternal {
public:
enum class ClearMode { None, All, Bits };
enum class WaitMode { And, Or };
enum class ThreadMode { Single, Multi };
enum class QueueMode { Fifo, ThreadPrio };
EventFlagInternal(const std::string& name, ThreadMode thread_mode, QueueMode queue_mode,
uint64_t bits)
: m_name(name), m_thread_mode(thread_mode), m_queue_mode(queue_mode), m_bits(bits){};
int Wait(u64 bits, WaitMode wait_mode, ClearMode clear_mode, u64* result, u32* ptr_micros) {
std::unique_lock lock{m_mutex};
uint32_t micros = 0;
bool infinitely = true;
if (ptr_micros != nullptr) {
micros = *ptr_micros;
infinitely = false;
}
if (m_thread_mode == ThreadMode::Single && m_waiting_threads > 0) {
return ORBIS_KERNEL_ERROR_EPERM;
}
auto const start = std::chrono::system_clock::now();
m_waiting_threads++;
auto waitFunc = [this, wait_mode, bits] {
return (m_status == Status::Canceled || m_status == Status::Deleted ||
(wait_mode == WaitMode::And && (m_bits & bits) == bits) ||
(wait_mode == WaitMode::Or && (m_bits & bits) != 0));
};
if (infinitely) {
m_cond_var.wait(lock, waitFunc);
} else {
if (!m_cond_var.wait_for(lock, std::chrono::microseconds(micros), waitFunc)) {
if (result != nullptr) {
*result = m_bits;
}
*ptr_micros = 0;
--m_waiting_threads;
return ORBIS_KERNEL_ERROR_ETIMEDOUT;
}
}
--m_waiting_threads;
if (result != nullptr) {
*result = m_bits;
}
auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::system_clock::now() - start)
.count();
if (result != nullptr) {
*result = m_bits;
}
if (ptr_micros != nullptr) {
*ptr_micros = (elapsed >= micros ? 0 : micros - elapsed);
}
if (m_status == Status::Canceled) {
return ORBIS_KERNEL_ERROR_ECANCELED;
} else if (m_status == Status::Deleted) {
return ORBIS_KERNEL_ERROR_EACCES;
}
if (clear_mode == ClearMode::All) {
m_bits = 0;
} else if (clear_mode == ClearMode::Bits) {
m_bits &= ~bits;
}
return ORBIS_OK;
}
int Poll(u64 bits, WaitMode wait_mode, ClearMode clear_mode, u64* result) {
u32 micros = 0;
auto ret = Wait(bits, wait_mode, clear_mode, result, &micros);
if (ret == ORBIS_KERNEL_ERROR_ETIMEDOUT) {
// Poll returns EBUSY instead.
ret = ORBIS_KERNEL_ERROR_EBUSY;
}
return ret;
}
void Set(u64 bits) {
std::unique_lock lock{m_mutex};
while (m_status != Status::Set) {
m_mutex.unlock();
std::this_thread::sleep_for(std::chrono::microseconds(10));
m_mutex.lock();
}
m_bits |= bits;
m_cond_var.notify_all();
}
void Clear(u64 bits) {
std::unique_lock lock{m_mutex};
while (m_status != Status::Set) {
m_mutex.unlock();
std::this_thread::sleep_for(std::chrono::microseconds(10));
m_mutex.lock();
}
m_bits &= bits;
}
private:
enum class Status { Set, Canceled, Deleted };
std::mutex m_mutex;
std::condition_variable m_cond_var;
Status m_status = Status::Set;
int m_waiting_threads = 0;
std::string m_name;
ThreadMode m_thread_mode = ThreadMode::Single;
QueueMode m_queue_mode = QueueMode::Fifo;
u64 m_bits = 0;
};
using OrbisKernelUseconds = u32;
using OrbisKernelEventFlag = EventFlagInternal*;
struct OrbisKernelEventFlagOptParam {
size_t size;
};
int PS4_SYSV_ABI sceKernelCreateEventFlag(OrbisKernelEventFlag* ef, const char* pName, u32 attr,
u64 initPattern,
const OrbisKernelEventFlagOptParam* pOptParam) {
@ -25,9 +169,8 @@ int PS4_SYSV_ABI sceKernelCreateEventFlag(OrbisKernelEventFlag* ef, const char*
return ORBIS_KERNEL_ERROR_ENAMETOOLONG;
}
EventFlagInternal::ThreadMode thread_mode = EventFlagInternal::ThreadMode::Single;
EventFlagInternal::QueueMode queue_mode = EventFlagInternal::QueueMode::Fifo;
auto thread_mode = EventFlagInternal::ThreadMode::Single;
auto queue_mode = EventFlagInternal::QueueMode::Fifo;
switch (attr & 0xfu) {
case 0x01:
queue_mode = EventFlagInternal::QueueMode::Fifo;
@ -61,6 +204,7 @@ int PS4_SYSV_ABI sceKernelCreateEventFlag(OrbisKernelEventFlag* ef, const char*
*ef = new EventFlagInternal(std::string(pName), thread_mode, queue_mode, initPattern);
return ORBIS_OK;
}
int PS4_SYSV_ABI sceKernelDeleteEventFlag(OrbisKernelEventFlag ef) {
if (ef == nullptr) {
return ORBIS_KERNEL_ERROR_ESRCH;
@ -69,24 +213,29 @@ int PS4_SYSV_ABI sceKernelDeleteEventFlag(OrbisKernelEventFlag ef) {
delete ef;
return ORBIS_OK;
}
int PS4_SYSV_ABI sceKernelOpenEventFlag() {
LOG_ERROR(Kernel_Event, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceKernelCloseEventFlag() {
LOG_ERROR(Kernel_Event, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceKernelClearEventFlag(OrbisKernelEventFlag ef, u64 bitPattern) {
LOG_DEBUG(Kernel_Event, "called");
ef->Clear(bitPattern);
return ORBIS_OK;
}
int PS4_SYSV_ABI sceKernelCancelEventFlag(OrbisKernelEventFlag ef, u64 setPattern,
int* pNumWaitThreads) {
LOG_ERROR(Kernel_Event, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceKernelSetEventFlag(OrbisKernelEventFlag ef, u64 bitPattern) {
LOG_TRACE(Kernel_Event, "called");
if (ef == nullptr) {
@ -95,6 +244,7 @@ int PS4_SYSV_ABI sceKernelSetEventFlag(OrbisKernelEventFlag ef, u64 bitPattern)
ef->Set(bitPattern);
return ORBIS_OK;
}
int PS4_SYSV_ABI sceKernelPollEventFlag(OrbisKernelEventFlag ef, u64 bitPattern, u32 waitMode,
u64* pResultPat) {
LOG_DEBUG(Kernel_Event, "called bitPattern = {:#x} waitMode = {:#x}", bitPattern, waitMode);
@ -107,9 +257,8 @@ int PS4_SYSV_ABI sceKernelPollEventFlag(OrbisKernelEventFlag ef, u64 bitPattern,
return ORBIS_KERNEL_ERROR_EINVAL;
}
EventFlagInternal::WaitMode wait = EventFlagInternal::WaitMode::And;
EventFlagInternal::ClearMode clear = EventFlagInternal::ClearMode::None;
auto wait = EventFlagInternal::WaitMode::And;
auto clear = EventFlagInternal::ClearMode::None;
switch (waitMode & 0xf) {
case 0x01:
wait = EventFlagInternal::WaitMode::And;
@ -154,9 +303,8 @@ int PS4_SYSV_ABI sceKernelWaitEventFlag(OrbisKernelEventFlag ef, u64 bitPattern,
return ORBIS_KERNEL_ERROR_EINVAL;
}
EventFlagInternal::WaitMode wait = EventFlagInternal::WaitMode::And;
EventFlagInternal::ClearMode clear = EventFlagInternal::ClearMode::None;
auto wait = EventFlagInternal::WaitMode::And;
auto clear = EventFlagInternal::ClearMode::None;
switch (waitMode & 0xf) {
case 0x01:
wait = EventFlagInternal::WaitMode::And;
@ -190,6 +338,7 @@ int PS4_SYSV_ABI sceKernelWaitEventFlag(OrbisKernelEventFlag ef, u64 bitPattern,
return result;
}
void RegisterKernelEventFlag(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("PZku4ZrXJqg", "libkernel", 1, "libkernel", 1, 1, sceKernelCancelEventFlag);
LIB_FUNCTION("7uhBFWRAS60", "libkernel", 1, "libkernel", 1, 1, sceKernelClearEventFlag);
@ -201,4 +350,5 @@ void RegisterKernelEventFlag(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("IOnSvHzqu6A", "libkernel", 1, "libkernel", 1, 1, sceKernelSetEventFlag);
LIB_FUNCTION("JTvBflhYazQ", "libkernel", 1, "libkernel", 1, 1, sceKernelWaitEventFlag);
}
} // namespace Libraries::Kernel

View file

@ -0,0 +1,14 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
namespace Core::Loader {
class SymbolsResolver;
}
namespace Libraries::Kernel {
void RegisterKernelEventFlag(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::Kernel

View file

@ -2,7 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma clang optimize off
#include "core/libraries/error_codes.h"
#include "core/libraries/kernel/libkernel.h"
#include "core/libraries/kernel/kernel.h"
#include "core/libraries/kernel/threads/thread_state.h"
#include "core/libraries/kernel/threads/threads.h"
#include "core/libraries/libs.h"

View file

@ -4,7 +4,7 @@
#include <cstring>
#include "common/assert.h"
#include "core/libraries/error_codes.h"
#include "core/libraries/kernel/libkernel.h"
#include "core/libraries/kernel/kernel.h"
#include "core/libraries/kernel/threads/threads.h"
#include "core/libraries/libs.h"

View file

@ -5,7 +5,7 @@
#include "common/thread.h"
#include "core/debug_state.h"
#include "core/libraries/error_codes.h"
#include "core/libraries/kernel/libkernel.h"
#include "core/libraries/kernel/kernel.h"
#include "core/libraries/kernel/threads/thread_state.h"
#include "core/libraries/kernel/threads/threads.h"
#include "core/libraries/libs.h"

View file

@ -5,7 +5,7 @@
#include "common/scope_exit.h"
#include "common/types.h"
#include "core/libraries/error_codes.h"
#include "core/libraries/kernel/libkernel.h"
#include "core/libraries/kernel/kernel.h"
#include "core/libraries/kernel/threads/threads.h"
#include "core/libraries/libs.h"

View file

@ -2,7 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/libraries/error_codes.h"
#include "core/libraries/kernel/libkernel.h"
#include "core/libraries/kernel/kernel.h"
#include "core/libraries/kernel/threads/threads.h"
#include "core/libraries/libs.h"

View file

@ -7,7 +7,7 @@
#include "common/assert.h"
#include "common/logging/log.h"
#include "core/libraries/error_codes.h"
#include "core/libraries/kernel/libkernel.h"
#include "core/libraries/kernel/kernel.h"
#include "core/libraries/kernel/time_management.h"
#include "core/libraries/libs.h"

View file

@ -3,7 +3,7 @@
#include "common/assert.h"
#include "core/libraries/error_codes.h"
#include "core/libraries/kernel/libkernel.h"
#include "core/libraries/kernel/kernel.h"
#include "core/libraries/kernel/threads/threads.h"
#include "core/libraries/libs.h"

View file

@ -14,7 +14,7 @@
#include "core/libraries/ime/error_dialog.h"
#include "core/libraries/ime/ime.h"
#include "core/libraries/ime/ime_dialog.h"
#include "core/libraries/kernel/libkernel.h"
#include "core/libraries/kernel/kernel.h"
#include "core/libraries/libc_internal/libc_internal.h"
#include "core/libraries/libpng/pngdec.h"
#include "core/libraries/libs.h"

View file

@ -6,7 +6,7 @@
#include "common/logging/log.h"
#include "core/libraries/error_codes.h"
#include "core/libraries/kernel/libkernel.h"
#include "core/libraries/kernel/kernel.h"
using namespace Libraries::Kernel;