mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-07-03 07:36:20 +00:00
kernel: File cleanup pt1
This commit is contained in:
parent
d0d8b5eee5
commit
77ff4290d6
27 changed files with 445 additions and 535 deletions
|
@ -208,10 +208,9 @@ set(GNM_LIB src/core/libraries/gnmdriver/gnmdriver.cpp
|
||||||
src/core/libraries/gnmdriver/gnm_error.h
|
src/core/libraries/gnmdriver/gnm_error.h
|
||||||
)
|
)
|
||||||
|
|
||||||
set(KERNEL_LIB src/core/libraries/kernel/event_flag/event_flag.cpp
|
set(KERNEL_LIB
|
||||||
src/core/libraries/kernel/event_flag/event_flag.h
|
src/core/libraries/kernel/threads/event_flag.cpp
|
||||||
src/core/libraries/kernel/event_flag/event_flag_obj.cpp
|
src/core/libraries/kernel/threads/event_flag.h
|
||||||
src/core/libraries/kernel/event_flag/event_flag_obj.h
|
|
||||||
src/core/libraries/kernel/threads/thr_attr.cpp
|
src/core/libraries/kernel/threads/thr_attr.cpp
|
||||||
src/core/libraries/kernel/threads/thr_cond.cpp
|
src/core/libraries/kernel/threads/thr_cond.cpp
|
||||||
src/core/libraries/kernel/threads/thr_create.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_rwlock.cpp
|
||||||
src/core/libraries/kernel/threads/thr_sem.cpp
|
src/core/libraries/kernel/threads/thr_sem.cpp
|
||||||
src/core/libraries/kernel/threads/thr_spec.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.cpp
|
||||||
src/core/libraries/kernel/cpu_management.h
|
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.cpp
|
||||||
src/core/libraries/kernel/event_queues.h
|
src/core/libraries/kernel/event_queues.h
|
||||||
src/core/libraries/kernel/file_system.cpp
|
src/core/libraries/kernel/file_system.cpp
|
||||||
src/core/libraries/kernel/file_system.h
|
src/core/libraries/kernel/file_system.h
|
||||||
src/core/libraries/kernel/libkernel.cpp
|
src/core/libraries/kernel/kernel.cpp
|
||||||
src/core/libraries/kernel/libkernel.h
|
src/core/libraries/kernel/kernel.h
|
||||||
src/core/libraries/kernel/memory_management.cpp
|
src/core/libraries/kernel/memory_management.cpp
|
||||||
src/core/libraries/kernel/memory_management.h
|
src/core/libraries/kernel/memory_management.h
|
||||||
src/core/libraries/kernel/thread_management.cpp
|
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.h
|
||||||
src/common/signal_context.cpp
|
src/common/signal_context.cpp
|
||||||
src/common/singleton.h
|
src/common/singleton.h
|
||||||
|
src/common/slab_heap.h
|
||||||
src/common/slot_vector.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.cpp
|
||||||
src/common/string_util.h
|
src/common/string_util.h
|
||||||
src/common/thread.cpp
|
src/common/thread.cpp
|
||||||
|
@ -816,14 +821,6 @@ else()
|
||||||
src/emulator.h
|
src/emulator.h
|
||||||
src/sdl_window.h
|
src/sdl_window.h
|
||||||
src/sdl_window.cpp
|
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()
|
endif()
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,7 @@ enum MarkersPalette : int {
|
||||||
#define RENDERER_TRACE ZoneScopedC(RendererMarkerColor)
|
#define RENDERER_TRACE ZoneScopedC(RendererMarkerColor)
|
||||||
#define HLE_TRACE ZoneScopedC(HleMarkerColor)
|
#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) \
|
#define TRACE_WARN(msg) \
|
||||||
[](const auto& msg) { TracyMessageC(msg.c_str(), msg.size(), tracy::Color::DarkOrange); }(msg);
|
[](const auto& msg) { TracyMessageC(msg.c_str(), msg.size(), tracy::Color::DarkOrange); }(msg);
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "core/libraries/error_codes.h"
|
#include "core/libraries/error_codes.h"
|
||||||
#include "core/libraries/kernel/libkernel.h"
|
#include "core/libraries/kernel/kernel.h"
|
||||||
|
|
||||||
using namespace Libraries::Kernel;
|
using namespace Libraries::Kernel;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
#pragma clang optimize off
|
|
||||||
#include "gnm_error.h"
|
#include "gnm_error.h"
|
||||||
#include "gnmdriver.h"
|
#include "gnmdriver.h"
|
||||||
|
|
||||||
|
@ -8,7 +8,6 @@
|
||||||
#include "common/config.h"
|
#include "common/config.h"
|
||||||
#include "common/debug.h"
|
#include "common/debug.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/path_util.h"
|
|
||||||
#include "common/slot_vector.h"
|
#include "common/slot_vector.h"
|
||||||
#include "core/address_space.h"
|
#include "core/address_space.h"
|
||||||
#include "core/debug_state.h"
|
#include "core/debug_state.h"
|
||||||
|
|
|
@ -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
|
|
|
@ -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;
|
|
|
@ -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, µs);
|
|
||||||
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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -10,6 +10,138 @@
|
||||||
|
|
||||||
namespace Libraries::Kernel {
|
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 boost::asio::io_context io_context;
|
||||||
extern void KernelSignalRequest();
|
extern void KernelSignalRequest();
|
||||||
|
|
||||||
|
@ -43,8 +175,7 @@ int PS4_SYSV_ABI sceKernelCreateEqueue(SceKernelEqueue* eq, const char* name) {
|
||||||
|
|
||||||
LOG_INFO(Kernel_Event, "name = {}", name);
|
LOG_INFO(Kernel_Event, "name = {}", name);
|
||||||
|
|
||||||
*eq = new EqueueInternal;
|
*eq = new EqueueInternal(name);
|
||||||
(*eq)->setName(std::string(name));
|
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,13 @@
|
||||||
|
|
||||||
#pragma once
|
#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 {
|
namespace Core::Loader {
|
||||||
class SymbolsResolver;
|
class SymbolsResolver;
|
||||||
|
@ -11,22 +17,111 @@ class SymbolsResolver;
|
||||||
|
|
||||||
namespace Libraries::Kernel {
|
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 SceKernelUseconds = u32;
|
||||||
using SceKernelEqueue = EqueueInternal*;
|
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);
|
void RegisterEventQueue(Core::Loader::SymbolsResolver* sym);
|
||||||
|
|
||||||
} // namespace Libraries::Kernel
|
} // namespace Libraries::Kernel
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
#include "core/libraries/error_codes.h"
|
#include "core/libraries/error_codes.h"
|
||||||
#include "core/libraries/kernel/file_system.h"
|
#include "core/libraries/kernel/file_system.h"
|
||||||
#include "core/libraries/libs.h"
|
#include "core/libraries/libs.h"
|
||||||
#include "libkernel.h"
|
#include "kernel.h"
|
||||||
|
|
||||||
namespace Libraries::Kernel {
|
namespace Libraries::Kernel {
|
||||||
|
|
||||||
|
|
|
@ -14,10 +14,10 @@
|
||||||
#include "core/file_sys/fs.h"
|
#include "core/file_sys/fs.h"
|
||||||
#include "core/libraries/error_codes.h"
|
#include "core/libraries/error_codes.h"
|
||||||
#include "core/libraries/kernel/cpu_management.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/event_queues.h"
|
||||||
#include "core/libraries/kernel/file_system.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/memory_management.h"
|
||||||
#include "core/libraries/kernel/thread_management.h"
|
#include "core/libraries/kernel/thread_management.h"
|
||||||
#include "core/libraries/kernel/time_management.h"
|
#include "core/libraries/kernel/time_management.h"
|
|
@ -1,7 +1,7 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// 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/thread_management.h"
|
||||||
#include "core/libraries/kernel/threads/threads.h"
|
#include "core/libraries/kernel/threads/threads.h"
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,157 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "core/libraries/error_codes.h"
|
#include "core/libraries/error_codes.h"
|
||||||
#include "core/libraries/libs.h"
|
#include "core/libraries/libs.h"
|
||||||
#include "event_flag.h"
|
|
||||||
|
|
||||||
namespace Libraries::Kernel {
|
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, µs);
|
||||||
|
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,
|
int PS4_SYSV_ABI sceKernelCreateEventFlag(OrbisKernelEventFlag* ef, const char* pName, u32 attr,
|
||||||
u64 initPattern,
|
u64 initPattern,
|
||||||
const OrbisKernelEventFlagOptParam* pOptParam) {
|
const OrbisKernelEventFlagOptParam* pOptParam) {
|
||||||
|
@ -25,9 +169,8 @@ int PS4_SYSV_ABI sceKernelCreateEventFlag(OrbisKernelEventFlag* ef, const char*
|
||||||
return ORBIS_KERNEL_ERROR_ENAMETOOLONG;
|
return ORBIS_KERNEL_ERROR_ENAMETOOLONG;
|
||||||
}
|
}
|
||||||
|
|
||||||
EventFlagInternal::ThreadMode thread_mode = EventFlagInternal::ThreadMode::Single;
|
auto thread_mode = EventFlagInternal::ThreadMode::Single;
|
||||||
EventFlagInternal::QueueMode queue_mode = EventFlagInternal::QueueMode::Fifo;
|
auto queue_mode = EventFlagInternal::QueueMode::Fifo;
|
||||||
|
|
||||||
switch (attr & 0xfu) {
|
switch (attr & 0xfu) {
|
||||||
case 0x01:
|
case 0x01:
|
||||||
queue_mode = EventFlagInternal::QueueMode::Fifo;
|
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);
|
*ef = new EventFlagInternal(std::string(pName), thread_mode, queue_mode, initPattern);
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceKernelDeleteEventFlag(OrbisKernelEventFlag ef) {
|
int PS4_SYSV_ABI sceKernelDeleteEventFlag(OrbisKernelEventFlag ef) {
|
||||||
if (ef == nullptr) {
|
if (ef == nullptr) {
|
||||||
return ORBIS_KERNEL_ERROR_ESRCH;
|
return ORBIS_KERNEL_ERROR_ESRCH;
|
||||||
|
@ -69,24 +213,29 @@ int PS4_SYSV_ABI sceKernelDeleteEventFlag(OrbisKernelEventFlag ef) {
|
||||||
delete ef;
|
delete ef;
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceKernelOpenEventFlag() {
|
int PS4_SYSV_ABI sceKernelOpenEventFlag() {
|
||||||
LOG_ERROR(Kernel_Event, "(STUBBED) called");
|
LOG_ERROR(Kernel_Event, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceKernelCloseEventFlag() {
|
int PS4_SYSV_ABI sceKernelCloseEventFlag() {
|
||||||
LOG_ERROR(Kernel_Event, "(STUBBED) called");
|
LOG_ERROR(Kernel_Event, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceKernelClearEventFlag(OrbisKernelEventFlag ef, u64 bitPattern) {
|
int PS4_SYSV_ABI sceKernelClearEventFlag(OrbisKernelEventFlag ef, u64 bitPattern) {
|
||||||
LOG_DEBUG(Kernel_Event, "called");
|
LOG_DEBUG(Kernel_Event, "called");
|
||||||
ef->Clear(bitPattern);
|
ef->Clear(bitPattern);
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceKernelCancelEventFlag(OrbisKernelEventFlag ef, u64 setPattern,
|
int PS4_SYSV_ABI sceKernelCancelEventFlag(OrbisKernelEventFlag ef, u64 setPattern,
|
||||||
int* pNumWaitThreads) {
|
int* pNumWaitThreads) {
|
||||||
LOG_ERROR(Kernel_Event, "(STUBBED) called");
|
LOG_ERROR(Kernel_Event, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceKernelSetEventFlag(OrbisKernelEventFlag ef, u64 bitPattern) {
|
int PS4_SYSV_ABI sceKernelSetEventFlag(OrbisKernelEventFlag ef, u64 bitPattern) {
|
||||||
LOG_TRACE(Kernel_Event, "called");
|
LOG_TRACE(Kernel_Event, "called");
|
||||||
if (ef == nullptr) {
|
if (ef == nullptr) {
|
||||||
|
@ -95,6 +244,7 @@ int PS4_SYSV_ABI sceKernelSetEventFlag(OrbisKernelEventFlag ef, u64 bitPattern)
|
||||||
ef->Set(bitPattern);
|
ef->Set(bitPattern);
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceKernelPollEventFlag(OrbisKernelEventFlag ef, u64 bitPattern, u32 waitMode,
|
int PS4_SYSV_ABI sceKernelPollEventFlag(OrbisKernelEventFlag ef, u64 bitPattern, u32 waitMode,
|
||||||
u64* pResultPat) {
|
u64* pResultPat) {
|
||||||
LOG_DEBUG(Kernel_Event, "called bitPattern = {:#x} waitMode = {:#x}", bitPattern, waitMode);
|
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;
|
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
EventFlagInternal::WaitMode wait = EventFlagInternal::WaitMode::And;
|
auto wait = EventFlagInternal::WaitMode::And;
|
||||||
EventFlagInternal::ClearMode clear = EventFlagInternal::ClearMode::None;
|
auto clear = EventFlagInternal::ClearMode::None;
|
||||||
|
|
||||||
switch (waitMode & 0xf) {
|
switch (waitMode & 0xf) {
|
||||||
case 0x01:
|
case 0x01:
|
||||||
wait = EventFlagInternal::WaitMode::And;
|
wait = EventFlagInternal::WaitMode::And;
|
||||||
|
@ -154,9 +303,8 @@ int PS4_SYSV_ABI sceKernelWaitEventFlag(OrbisKernelEventFlag ef, u64 bitPattern,
|
||||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
EventFlagInternal::WaitMode wait = EventFlagInternal::WaitMode::And;
|
auto wait = EventFlagInternal::WaitMode::And;
|
||||||
EventFlagInternal::ClearMode clear = EventFlagInternal::ClearMode::None;
|
auto clear = EventFlagInternal::ClearMode::None;
|
||||||
|
|
||||||
switch (waitMode & 0xf) {
|
switch (waitMode & 0xf) {
|
||||||
case 0x01:
|
case 0x01:
|
||||||
wait = EventFlagInternal::WaitMode::And;
|
wait = EventFlagInternal::WaitMode::And;
|
||||||
|
@ -190,6 +338,7 @@ int PS4_SYSV_ABI sceKernelWaitEventFlag(OrbisKernelEventFlag ef, u64 bitPattern,
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegisterKernelEventFlag(Core::Loader::SymbolsResolver* sym) {
|
void RegisterKernelEventFlag(Core::Loader::SymbolsResolver* sym) {
|
||||||
LIB_FUNCTION("PZku4ZrXJqg", "libkernel", 1, "libkernel", 1, 1, sceKernelCancelEventFlag);
|
LIB_FUNCTION("PZku4ZrXJqg", "libkernel", 1, "libkernel", 1, 1, sceKernelCancelEventFlag);
|
||||||
LIB_FUNCTION("7uhBFWRAS60", "libkernel", 1, "libkernel", 1, 1, sceKernelClearEventFlag);
|
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("IOnSvHzqu6A", "libkernel", 1, "libkernel", 1, 1, sceKernelSetEventFlag);
|
||||||
LIB_FUNCTION("JTvBflhYazQ", "libkernel", 1, "libkernel", 1, 1, sceKernelWaitEventFlag);
|
LIB_FUNCTION("JTvBflhYazQ", "libkernel", 1, "libkernel", 1, 1, sceKernelWaitEventFlag);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Libraries::Kernel
|
} // namespace Libraries::Kernel
|
14
src/core/libraries/kernel/threads/event_flag.h
Normal file
14
src/core/libraries/kernel/threads/event_flag.h
Normal 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
|
|
@ -2,7 +2,7 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
#pragma clang optimize off
|
#pragma clang optimize off
|
||||||
#include "core/libraries/error_codes.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/thread_state.h"
|
||||||
#include "core/libraries/kernel/threads/threads.h"
|
#include "core/libraries/kernel/threads/threads.h"
|
||||||
#include "core/libraries/libs.h"
|
#include "core/libraries/libs.h"
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "core/libraries/error_codes.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/kernel/threads/threads.h"
|
||||||
#include "core/libraries/libs.h"
|
#include "core/libraries/libs.h"
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#include "common/thread.h"
|
#include "common/thread.h"
|
||||||
#include "core/debug_state.h"
|
#include "core/debug_state.h"
|
||||||
#include "core/libraries/error_codes.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/thread_state.h"
|
||||||
#include "core/libraries/kernel/threads/threads.h"
|
#include "core/libraries/kernel/threads/threads.h"
|
||||||
#include "core/libraries/libs.h"
|
#include "core/libraries/libs.h"
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#include "common/scope_exit.h"
|
#include "common/scope_exit.h"
|
||||||
#include "common/types.h"
|
#include "common/types.h"
|
||||||
#include "core/libraries/error_codes.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/kernel/threads/threads.h"
|
||||||
#include "core/libraries/libs.h"
|
#include "core/libraries/libs.h"
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include "core/libraries/error_codes.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/kernel/threads/threads.h"
|
||||||
#include "core/libraries/libs.h"
|
#include "core/libraries/libs.h"
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "core/libraries/error_codes.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/kernel/time_management.h"
|
||||||
#include "core/libraries/libs.h"
|
#include "core/libraries/libs.h"
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "core/libraries/error_codes.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/kernel/threads/threads.h"
|
||||||
#include "core/libraries/libs.h"
|
#include "core/libraries/libs.h"
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
#include "core/libraries/ime/error_dialog.h"
|
#include "core/libraries/ime/error_dialog.h"
|
||||||
#include "core/libraries/ime/ime.h"
|
#include "core/libraries/ime/ime.h"
|
||||||
#include "core/libraries/ime/ime_dialog.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/libc_internal/libc_internal.h"
|
||||||
#include "core/libraries/libpng/pngdec.h"
|
#include "core/libraries/libpng/pngdec.h"
|
||||||
#include "core/libraries/libs.h"
|
#include "core/libraries/libs.h"
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "core/libraries/error_codes.h"
|
#include "core/libraries/error_codes.h"
|
||||||
#include "core/libraries/kernel/libkernel.h"
|
#include "core/libraries/kernel/kernel.h"
|
||||||
|
|
||||||
using namespace Libraries::Kernel;
|
using namespace Libraries::Kernel;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue