kernel: It builds

This commit is contained in:
IndecisiveTurtle 2024-10-19 19:23:03 +03:00
parent c878e69270
commit 00b84b2c7f
43 changed files with 420 additions and 739 deletions

View file

@ -1,18 +1,14 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "avplayer.h"
#include "avplayer_impl.h"
#include "common/logging/log.h"
#include "core/libraries/avplayer/avplayer.h"
#include "core/libraries/avplayer/avplayer_impl.h"
#include "core/libraries/error_codes.h"
#include "core/libraries/kernel/thread_management.h"
#include "core/libraries/libs.h"
namespace Libraries::AvPlayer {
using namespace Kernel;
s32 PS4_SYSV_ABI sceAvPlayerAddSource(SceAvPlayerHandle handle, const char* filename) {
LOG_TRACE(Lib_AvPlayer, "filename = {}", filename);
if (handle == nullptr) {

View file

@ -5,8 +5,8 @@
#include "common/types.h"
#include <stdarg.h> // va_list
#include <stddef.h> // size_t
#include <cstdarg> // va_list
#include <cstddef> // size_t
namespace Core::Loader {
class SymbolsResolver;

View file

@ -1,24 +1,16 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "avplayer.h"
#include "avplayer_common.h"
#include <algorithm> // std::equal
#include <cctype> // std::tolower
#include <algorithm> // std::equal
#include <cctype> // std::tolower
#include <string_view> // std::string_view
#include "core/libraries/avplayer/avplayer.h"
#include "core/libraries/avplayer/avplayer_common.h"
namespace Libraries::AvPlayer {
using namespace Kernel;
static bool ichar_equals(char a, char b) {
return std::tolower(static_cast<unsigned char>(a)) ==
std::tolower(static_cast<unsigned char>(b));
}
static bool iequals(std::string_view l, std::string_view r) {
return std::ranges::equal(l, r, ichar_equals);
return std::ranges::equal(l, r, [](u8 a, u8 b) { return std::tolower(a) == std::tolower(b); });
}
SceAvPlayerSourceType GetSourceType(std::string_view path) {

View file

@ -3,16 +3,14 @@
#pragma once
#include "avplayer.h"
#include "common/assert.h"
#include "common/logging/log.h"
#include "core/libraries/kernel/thread_management.h"
#include <mutex>
#include <optional>
#include <string_view>
#include <utility>
#include <queue>
#include "core/libraries/avplayer/avplayer.h"
#define AVPLAYER_IS_ERROR(x) ((x) < 0)
namespace Libraries::AvPlayer {

View file

@ -1,20 +1,16 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "avplayer_file_streamer.h"
#include "avplayer_common.h"
#include <algorithm> // std::max, std::min
#include <magic_enum.hpp>
#include "core/libraries/avplayer/avplayer_file_streamer.h"
extern "C" {
#include <libavformat/avformat.h>
#include <libavformat/avio.h>
}
#include <algorithm> // std::max, std::min
#define AVPLAYER_AVIO_BUFFER_SIZE 4096
constexpr u32 AVPLAYER_AVIO_BUFFER_SIZE = 4096;
namespace Libraries::AvPlayer {

View file

@ -3,11 +3,9 @@
#pragma once
#include "avplayer.h"
#include "avplayer_data_streamer.h"
#include <string_view>
#include <vector>
#include "core/libraries/avplayer/avplayer.h"
#include "core/libraries/avplayer/avplayer_data_streamer.h"
struct AVIOContext;

View file

@ -1,17 +1,10 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "avplayer_common.h"
#include "avplayer_file_streamer.h"
#include "avplayer_impl.h"
#include "common/logging/log.h"
#include "common/singleton.h"
#include "core/libraries/avplayer/avplayer_common.h"
#include "core/libraries/avplayer/avplayer_impl.h"
#include "core/libraries/error_codes.h"
#include "core/libraries/kernel/libkernel.h"
#include "core/linker.h"
using namespace Libraries::Kernel;
#include "core/tls.h"
namespace Libraries::AvPlayer {
@ -19,32 +12,28 @@ void* PS4_SYSV_ABI AvPlayer::Allocate(void* handle, u32 alignment, u32 size) {
const auto* const self = reinterpret_cast<AvPlayer*>(handle);
const auto allocate = self->m_init_data_original.memory_replacement.allocate;
const auto ptr = self->m_init_data_original.memory_replacement.object_ptr;
const auto* linker = Common::Singleton<Core::Linker>::Instance();
return linker->ExecuteGuest(allocate, ptr, alignment, size);
return Core::ExecuteGuest(allocate, ptr, alignment, size);
}
void PS4_SYSV_ABI AvPlayer::Deallocate(void* handle, void* memory) {
const auto* const self = reinterpret_cast<AvPlayer*>(handle);
const auto deallocate = self->m_init_data_original.memory_replacement.deallocate;
const auto ptr = self->m_init_data_original.memory_replacement.object_ptr;
const auto* linker = Common::Singleton<Core::Linker>::Instance();
return linker->ExecuteGuest(deallocate, ptr, memory);
return Core::ExecuteGuest(deallocate, ptr, memory);
}
void* PS4_SYSV_ABI AvPlayer::AllocateTexture(void* handle, u32 alignment, u32 size) {
const auto* const self = reinterpret_cast<AvPlayer*>(handle);
const auto allocate = self->m_init_data_original.memory_replacement.allocate_texture;
const auto ptr = self->m_init_data_original.memory_replacement.object_ptr;
const auto* linker = Common::Singleton<Core::Linker>::Instance();
return linker->ExecuteGuest(allocate, ptr, alignment, size);
return Core::ExecuteGuest(allocate, ptr, alignment, size);
}
void PS4_SYSV_ABI AvPlayer::DeallocateTexture(void* handle, void* memory) {
const auto* const self = reinterpret_cast<AvPlayer*>(handle);
const auto deallocate = self->m_init_data_original.memory_replacement.deallocate_texture;
const auto ptr = self->m_init_data_original.memory_replacement.object_ptr;
const auto* linker = Common::Singleton<Core::Linker>::Instance();
return linker->ExecuteGuest(deallocate, ptr, memory);
return Core::ExecuteGuest(deallocate, ptr, memory);
}
int PS4_SYSV_ABI AvPlayer::OpenFile(void* handle, const char* filename) {
@ -53,8 +42,7 @@ int PS4_SYSV_ABI AvPlayer::OpenFile(void* handle, const char* filename) {
const auto open = self->m_init_data_original.file_replacement.open;
const auto ptr = self->m_init_data_original.file_replacement.object_ptr;
const auto* linker = Common::Singleton<Core::Linker>::Instance();
return linker->ExecuteGuest(open, ptr, filename);
return Core::ExecuteGuest(open, ptr, filename);
}
int PS4_SYSV_ABI AvPlayer::CloseFile(void* handle) {
@ -63,8 +51,7 @@ int PS4_SYSV_ABI AvPlayer::CloseFile(void* handle) {
const auto close = self->m_init_data_original.file_replacement.close;
const auto ptr = self->m_init_data_original.file_replacement.object_ptr;
const auto* linker = Common::Singleton<Core::Linker>::Instance();
return linker->ExecuteGuest(close, ptr);
return Core::ExecuteGuest(close, ptr);
}
int PS4_SYSV_ABI AvPlayer::ReadOffsetFile(void* handle, u8* buffer, u64 position, u32 length) {
@ -73,8 +60,7 @@ int PS4_SYSV_ABI AvPlayer::ReadOffsetFile(void* handle, u8* buffer, u64 position
const auto read_offset = self->m_init_data_original.file_replacement.readOffset;
const auto ptr = self->m_init_data_original.file_replacement.object_ptr;
const auto* linker = Common::Singleton<Core::Linker>::Instance();
return linker->ExecuteGuest(read_offset, ptr, buffer, position, length);
return Core::ExecuteGuest(read_offset, ptr, buffer, position, length);
}
u64 PS4_SYSV_ABI AvPlayer::SizeFile(void* handle) {
@ -83,8 +69,7 @@ u64 PS4_SYSV_ABI AvPlayer::SizeFile(void* handle) {
const auto size = self->m_init_data_original.file_replacement.size;
const auto ptr = self->m_init_data_original.file_replacement.object_ptr;
const auto* linker = Common::Singleton<Core::Linker>::Instance();
return linker->ExecuteGuest(size, ptr);
return Core::ExecuteGuest(size, ptr);
}
SceAvPlayerInitData AvPlayer::StubInitData(const SceAvPlayerInitData& data) {

View file

@ -3,11 +3,8 @@
#pragma once
#include "avplayer.h"
#include "avplayer_data_streamer.h"
#include "avplayer_state.h"
#include "core/libraries/kernel/thread_management.h"
#include "core/libraries/avplayer/avplayer.h"
#include "core/libraries/avplayer/avplayer_state.h"
#include <mutex>
@ -17,7 +14,6 @@ extern "C" {
}
#include <memory>
#include <vector>
namespace Libraries::AvPlayer {

View file

@ -1,16 +1,12 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "avplayer_source.h"
#include "avplayer_file_streamer.h"
#include "common/alignment.h"
#include "common/singleton.h"
#include "common/thread.h"
#include "core/file_sys/fs.h"
#include "core/libraries/kernel/time_management.h"
#include "core/libraries/avplayer/avplayer_file_streamer.h"
#include "core/libraries/avplayer/avplayer_source.h"
#include <magic_enum.hpp>
@ -35,8 +31,6 @@ av_always_inline std::string av_err2string(int errnum) {
namespace Libraries::AvPlayer {
using namespace Kernel;
AvPlayerSource::AvPlayerSource(AvPlayerStateCallback& state, bool use_vdec2)
: m_state(state), m_use_vdec2(use_vdec2) {}

View file

@ -3,20 +3,18 @@
#pragma once
#include "avplayer.h"
#include "avplayer_common.h"
#include "avplayer_data_streamer.h"
#include "common/polyfill_thread.h"
#include "common/types.h"
#include "core/libraries/kernel/thread_management.h"
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <mutex>
#include <optional>
#include <string>
#include <string_view>
#include "common/assert.h"
#include "common/polyfill_thread.h"
#include "core/libraries/avplayer/avplayer.h"
#include "core/libraries/avplayer/avplayer_common.h"
#include "core/libraries/avplayer/avplayer_data_streamer.h"
struct AVCodecContext;
struct AVFormatContext;
@ -139,8 +137,6 @@ public:
bool IsActive();
private:
using ScePthread = Kernel::ScePthread;
static void ReleaseAVPacket(AVPacket* packet);
static void ReleaseAVFrame(AVFrame* frame);
static void ReleaseAVCodecContext(AVCodecContext* context);

View file

@ -1,22 +1,17 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "avplayer_file_streamer.h"
#include "avplayer_source.h"
#include "avplayer_state.h"
#include "common/singleton.h"
#include "common/logging/log.h"
#include "common/thread.h"
#include "core/libraries/avplayer/avplayer_source.h"
#include "core/libraries/avplayer/avplayer_state.h"
#include "core/libraries/error_codes.h"
#include "core/libraries/kernel/time_management.h"
#include "core/linker.h"
#include "core/tls.h"
#include <magic_enum.hpp>
namespace Libraries::AvPlayer {
using namespace Kernel;
void PS4_SYSV_ABI AvPlayerState::AutoPlayEventCallback(void* opaque, SceAvPlayerEvents event_id,
s32 source_id, void* event_data) {
auto const self = reinterpret_cast<AvPlayerState*>(opaque);
@ -96,8 +91,7 @@ void AvPlayerState::DefaultEventCallback(void* opaque, SceAvPlayerEvents event_i
const auto callback = self->m_event_replacement.event_callback;
const auto ptr = self->m_event_replacement.object_ptr;
if (callback != nullptr) {
const auto* linker = Common::Singleton<Core::Linker>::Instance();
linker->ExecuteGuest(callback, ptr, event_id, 0, event_data);
Core::ExecuteGuest(callback, ptr, event_id, 0, event_data);
}
}

View file

@ -3,17 +3,14 @@
#pragma once
#include "avplayer.h"
#include "avplayer_data_streamer.h"
#include "avplayer_source.h"
#include "common/polyfill_thread.h"
#include "core/libraries/kernel/thread_management.h"
#include <memory>
#include <mutex>
#include <shared_mutex>
#include "common/polyfill_thread.h"
#include "core/libraries/avplayer/avplayer.h"
#include "core/libraries/avplayer/avplayer_source.h"
namespace Libraries::AvPlayer {
class Stream;

View file

@ -4,10 +4,9 @@
#include "fiber.h"
#include "common/logging/log.h"
#include "common/singleton.h"
#include "core/libraries/error_codes.h"
#include "core/libraries/libs.h"
#include "core/linker.h"
#include "core/tls.h"
#ifdef _WIN64
#include <windows.h>
@ -31,9 +30,7 @@ void FiberEntry(void* param) {
argRun = *fiber->pArgRun;
}
const auto* linker = Common::Singleton<Core::Linker>::Instance();
linker->ExecuteGuest(fiber->entry, fiber->argOnInitialize, argRun);
Core::ExecuteGuest(fiber->entry, fiber->argOnInitialize, argRun);
UNREACHABLE();
}
@ -281,4 +278,4 @@ void RegisterlibSceFiber(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("JzyT91ucGDc", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberRename);
}
} // namespace Libraries::Fiber
} // namespace Libraries::Fiber

View file

@ -11,7 +11,7 @@
#include "common/singleton.h"
#include "core/libraries/ime/ime_dialog.h"
#include "core/libraries/ime/ime_dialog_ui.h"
#include "core/linker.h"
#include "core/tls.h"
#include "imgui/imgui_std.h"
using namespace ImGui;
@ -124,9 +124,8 @@ bool ImeDialogState::CallTextFilter() {
return false;
}
auto* linker = Common::Singleton<Core::Linker>::Instance();
int ret =
linker->ExecuteGuest(text_filter, out_text, &out_text_length, src_text, src_text_length);
Core::ExecuteGuest(text_filter, out_text, &out_text_length, src_text, src_text_length);
if (ret != 0) {
return false;
@ -147,15 +146,12 @@ bool ImeDialogState::CallKeyboardFilter(const OrbisImeKeycode* src_keycode, u16*
return true;
}
auto* linker = Common::Singleton<Core::Linker>::Instance();
int ret = linker->ExecuteGuest(keyboard_filter, src_keycode, out_keycode, out_status, nullptr);
int ret = Core::ExecuteGuest(keyboard_filter, src_keycode, out_keycode, out_status, nullptr);
return ret == 0;
}
bool ImeDialogState::ConvertOrbisToUTF8(const char16_t* orbis_text, std::size_t orbis_text_len,
char* utf8_text, std::size_t utf8_text_len) {
std::fill(utf8_text, utf8_text + utf8_text_len, '\0');
const ImWchar* orbis_text_ptr = reinterpret_cast<const ImWchar*>(orbis_text);
ImTextStrToUtf8(utf8_text, utf8_text_len, orbis_text_ptr, orbis_text_ptr + orbis_text_len);
@ -165,7 +161,6 @@ bool ImeDialogState::ConvertOrbisToUTF8(const char16_t* orbis_text, std::size_t
bool ImeDialogState::ConvertUTF8ToOrbis(const char* utf8_text, std::size_t utf8_text_len,
char16_t* orbis_text, std::size_t orbis_text_len) {
std::fill(orbis_text, orbis_text + orbis_text_len, u'\0');
ImTextStrFromUtf8(reinterpret_cast<ImWchar*>(orbis_text), orbis_text_len, utf8_text, nullptr);
@ -387,4 +382,4 @@ int ImeDialogUi::InputTextCallback(ImGuiInputTextCallbackData* data) {
return 0;
}
} // namespace Libraries::ImeDialog
} // namespace Libraries::ImeDialog

View file

@ -13,7 +13,7 @@
namespace Libraries::Kernel {
std::vector<Core::FileSys::DirEntry> GetDirectoryEntries(const std::filesystem::path& path) {
auto GetDirectoryEntries(const std::filesystem::path& path) {
std::vector<Core::FileSys::DirEntry> files;
for (const auto& entry : std::filesystem::directory_iterator(path)) {
auto& dir_entry = files.emplace_back();

View file

@ -65,11 +65,6 @@ constexpr int ORBIS_KERNEL_O_DSYNC = 0x1000;
constexpr int ORBIS_KERNEL_O_DIRECT = 0x00010000;
constexpr int ORBIS_KERNEL_O_DIRECTORY = 0x00020000;
int PS4_SYSV_ABI sceKernelOpen(const char* path, int flags, /* SceKernelMode*/ u16 mode);
int PS4_SYSV_ABI posix_open(const char* path, int flags, /* SceKernelMode*/ u16 mode);
s64 PS4_SYSV_ABI lseek(int d, s64 offset, int whence);
void RegisterFileSystem(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::Kernel

View file

@ -29,7 +29,6 @@
#include <objbase.h>
#include <windows.h>
#else
#include <sys/mman.h>
#ifdef __APPLE__
#include <date/tz.h>
#endif

View file

@ -7,6 +7,20 @@
namespace Libraries::Kernel {
int PS4_SYSV_ABI posix_pthread_attr_init(PthreadAttrT* attr);
int PS4_SYSV_ABI posix_pthread_create_name_np(PthreadT* thread, const PthreadAttrT* attr,
PthreadEntryFunc start_routine, void* arg,
const char* name);
PthreadT LaunchThread(PthreadEntryFunc start_routine, void* arg, const char* name) {
PthreadT thread{};
PthreadAttrT attr{};
posix_pthread_attr_init(&attr);
posix_pthread_create_name_np(&thread, &attr, start_routine, arg, name);
return thread;
}
void RegisterThreads(Core::Loader::SymbolsResolver* sym) {
RegisterMutex(sym);
RegisterCond(sym);
@ -14,6 +28,8 @@ void RegisterThreads(Core::Loader::SymbolsResolver* sym) {
RegisterSemaphore(sym);
RegisterSpec(sym);
RegisterThreadAttr(sym);
RegisterThread(sym);
RegisterRtld(sym);
}
} // namespace Libraries::Kernel

View file

@ -3,223 +3,15 @@
#pragma once
#include <atomic>
#include <mutex>
#include <semaphore>
#include <string>
#include <vector>
#include <pthread.h>
#include <sched.h>
#include "common/types.h"
#define ORBIS_PTHREAD_MUTEX_ADAPTIVE_INITIALIZER (reinterpret_cast<ScePthreadMutex>(1))
#include "core/libraries/kernel/threads/threads.h"
namespace Core::Loader {
class SymbolsResolver;
}
namespace Libraries::Kernel {
constexpr int ORBIS_KERNEL_PRIO_FIFO_DEFAULT = 700;
constexpr int ORBIS_KERNEL_PRIO_FIFO_HIGHEST = 256;
constexpr int ORBIS_KERNEL_PRIO_FIFO_LOWEST = 767;
constexpr int ORBIS_KERNEL_SEM_VALUE_MAX = 0x7FFFFFFF;
constexpr int ORBIS_PTHREAD_MUTEX_ERRORCHECK = 1;
constexpr int ORBIS_PTHREAD_MUTEX_RECURSIVE = 2;
constexpr int ORBIS_PTHREAD_MUTEX_NORMAL = 3;
constexpr int ORBIS_PTHREAD_MUTEX_ADAPTIVE = 4;
struct PthreadInternal;
struct PthreadAttrInternal;
struct PthreadMutexInternal;
struct PthreadMutexattrInternal;
struct PthreadCondInternal;
struct PthreadCondAttrInternal;
struct PthreadRwInternal;
struct PthreadRwLockAttrInternal;
class PthreadKeys;
using SceKernelSchedParam = ::sched_param;
using ScePthread = PthreadInternal*;
using ScePthreadAttr = PthreadAttrInternal*;
using ScePthreadMutex = PthreadMutexInternal*;
using ScePthreadMutexattr = PthreadMutexattrInternal*;
using ScePthreadCond = PthreadCondInternal*;
using ScePthreadCondattr = PthreadCondAttrInternal*;
using OrbisPthreadRwlock = PthreadRwInternal*;
using OrbisPthreadRwlockattr = PthreadRwLockAttrInternal*;
using OrbisPthreadKey = u32;
using PthreadKeyDestructor = PS4_SYSV_ABI void (*)(void*);
using PthreadEntryFunc = PS4_SYSV_ABI void* (*)(void*);
struct PthreadInternal {
u8 reserved[4096];
std::string name;
pthread_t pth;
ScePthreadAttr attr;
PthreadEntryFunc entry;
void* arg;
std::atomic_bool is_started;
std::atomic_bool is_detached;
std::atomic_bool is_almost_done;
std::atomic_bool is_free;
using Destructor = std::pair<OrbisPthreadKey, PthreadKeyDestructor>;
std::vector<Destructor> key_destructors;
int prio;
};
struct PthreadAttrInternal {
u8 reserved[64];
u64 affinity;
size_t guard_size;
int policy;
bool detached;
pthread_attr_t pth_attr;
};
struct PthreadMutexInternal {
u8 reserved[256];
std::string name;
pthread_mutex_t pth_mutex;
};
struct PthreadMutexattrInternal {
u8 reserved[64];
pthread_mutexattr_t pth_mutex_attr;
int pprotocol;
};
struct PthreadCondInternal {
u8 reserved[256];
std::string name;
pthread_cond_t cond;
};
struct PthreadCondAttrInternal {
u8 reserved[64];
pthread_condattr_t cond_attr;
clockid_t clock;
};
struct PthreadRwLockAttrInternal {
u8 reserved[64];
pthread_rwlockattr_t attr_rwlock;
int type;
};
struct PthreadRwInternal {
pthread_rwlock_t pth_rwlock;
std::string name;
};
struct PthreadSemInternal {
std::counting_semaphore<ORBIS_KERNEL_SEM_VALUE_MAX> semaphore;
std::atomic<s32> value;
};
class PThreadPool {
public:
ScePthread Create(const char* name);
private:
std::vector<ScePthread> m_threads;
std::mutex m_mutex;
};
class PThreadCxt {
public:
ScePthreadMutexattr* getDefaultMutexattr() {
return &m_default_mutexattr;
}
void setDefaultMutexattr(ScePthreadMutexattr attr) {
m_default_mutexattr = attr;
}
ScePthreadMutexattr* getAdaptiveMutexattr() {
return &m_adaptive_mutexattr;
}
void setAdaptiveMutexattr(ScePthreadMutexattr attr) {
m_adaptive_mutexattr = attr;
}
ScePthreadCondattr* getDefaultCondattr() {
return &m_default_condattr;
}
void setDefaultCondattr(ScePthreadCondattr attr) {
m_default_condattr = attr;
}
ScePthreadAttr* GetDefaultAttr() {
return &m_default_attr;
}
void SetDefaultAttr(ScePthreadAttr attr) {
m_default_attr = attr;
}
PThreadPool* GetPthreadPool() {
return m_pthread_pool;
}
void SetPthreadPool(PThreadPool* pool) {
m_pthread_pool = pool;
}
OrbisPthreadRwlockattr* getDefaultRwattr() {
return &m_default_Rwattr;
}
void setDefaultRwattr(OrbisPthreadRwlockattr attr) {
m_default_Rwattr = attr;
}
private:
ScePthreadMutexattr m_default_mutexattr = nullptr;
ScePthreadMutexattr m_adaptive_mutexattr = nullptr;
ScePthreadCondattr m_default_condattr = nullptr;
ScePthreadAttr m_default_attr = nullptr;
PThreadPool* m_pthread_pool = nullptr;
OrbisPthreadRwlockattr m_default_Rwattr = nullptr;
};
void init_pthreads();
void pthreadInitSelfMainThread();
int PS4_SYSV_ABI scePthreadAttrInit(ScePthreadAttr* attr);
int PS4_SYSV_ABI scePthreadAttrSetdetachstate(ScePthreadAttr* attr, int detachstate);
int PS4_SYSV_ABI scePthreadAttrSetinheritsched(ScePthreadAttr* attr, int inheritSched);
int PS4_SYSV_ABI scePthreadAttrSetschedparam(ScePthreadAttr* attr,
const SceKernelSchedParam* param);
int PS4_SYSV_ABI scePthreadAttrSetschedpolicy(ScePthreadAttr* attr, int policy);
ScePthread PS4_SYSV_ABI scePthreadSelf();
int PS4_SYSV_ABI scePthreadAttrSetaffinity(ScePthreadAttr* pattr,
const /*SceKernelCpumask*/ u64 mask);
int PS4_SYSV_ABI scePthreadSetaffinity(ScePthread thread, const /*SceKernelCpumask*/ u64 mask);
int PS4_SYSV_ABI scePthreadGetaffinity(ScePthread thread, /*SceKernelCpumask*/ u64* mask);
int PS4_SYSV_ABI scePthreadCreate(ScePthread* thread, const ScePthreadAttr* attr,
PthreadEntryFunc start_routine, void* arg, const char* name);
int PS4_SYSV_ABI scePthreadSetprio(ScePthread thread, int prio);
/***
* Mutex calls
*/
int PS4_SYSV_ABI scePthreadMutexInit(ScePthreadMutex* mutex, const ScePthreadMutexattr* attr,
const char* name);
int PS4_SYSV_ABI scePthreadMutexattrInit(ScePthreadMutexattr* attr);
int PS4_SYSV_ABI scePthreadMutexattrSettype(ScePthreadMutexattr* attr, int type);
int PS4_SYSV_ABI scePthreadMutexattrSetprotocol(ScePthreadMutexattr* attr, int protocol);
int PS4_SYSV_ABI scePthreadMutexLock(ScePthreadMutex* mutex);
int PS4_SYSV_ABI scePthreadMutexUnlock(ScePthreadMutex* mutex);
/****
* Cond calls
*/
int PS4_SYSV_ABI scePthreadCondInit(ScePthreadCond* cond, const ScePthreadCondattr* attr,
const char* name);
int PS4_SYSV_ABI scePthreadCondattrInit(ScePthreadCondattr* attr);
int PS4_SYSV_ABI scePthreadCondBroadcast(ScePthreadCond* cond);
int PS4_SYSV_ABI scePthreadCondWait(ScePthreadCond* cond, ScePthreadMutex* mutex);
/****
* Posix calls
*/
int PS4_SYSV_ABI posix_pthread_mutex_init(ScePthreadMutex* mutex, const ScePthreadMutexattr* attr);
int PS4_SYSV_ABI posix_pthread_mutex_lock(ScePthreadMutex* mutex);
int PS4_SYSV_ABI posix_pthread_mutex_unlock(ScePthreadMutex* mutex);
int PS4_SYSV_ABI posix_pthread_cond_broadcast(ScePthreadCond* cond);
PthreadT LaunchThread(PthreadEntryFunc start_routine, void* arg, const char* name);
void RegisterThreads(Core::Loader::SymbolsResolver* sym);

View file

@ -224,6 +224,7 @@ int PS4_SYSV_ABI posix_pthread_attr_get_np(PthreadT pthread, PthreadAttrT* dstat
if (True(pthread->flags & ThreadFlags::Detached)) {
attr.flags |= PthreadAttrFlags::Detached;
}
pthread->lock->unlock();
if (ret == 0) {
memcpy(dst, &attr, sizeof(PthreadAttr));
}

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 <cstring>
#include "core/libraries/error_codes.h"
#include "core/libraries/kernel/libkernel.h"
@ -68,6 +68,7 @@ static int InitStatic(Pthread* thread, PthreadCondT* cond) {
} else if (cvp == THR_COND_DESTROYED) { \
return POSIX_EINVAL; \
} \
cvp = *cond; \
}
int PS4_SYSV_ABI posix_pthread_cond_init(PthreadCondT* cond, const PthreadCondAttrT* cond_attr) {

View file

@ -9,22 +9,188 @@
#include "core/libraries/kernel/threads/thread_state.h"
#include "core/libraries/kernel/threads/threads.h"
#include "core/libraries/libs.h"
#include "core/linker.h"
#include "core/memory.h"
#include <pthread.h>
namespace Libraries::Kernel {
constexpr int PthreadInheritSched = 4;
constexpr int ORBIS_KERNEL_PRIO_FIFO_DEFAULT = 700;
constexpr int ORBIS_KERNEL_PRIO_FIFO_HIGHEST = 256;
constexpr int ORBIS_KERNEL_PRIO_FIFO_LOWEST = 767;
extern PthreadAttr PthreadAttrDefault;
using PthreadEntryFunc = void* (*)(void*);
void _thread_cleanupspecific();
void PS4_SYSV_ABI posix_pthread_exit(void* status);
static void ExitThread() {
Pthread* curthread = g_curthread;
/* Check if there is thread specific data: */
if (curthread->specific != nullptr) {
/* Run the thread-specific data destructors: */
_thread_cleanupspecific();
}
auto* thread_state = ThrState::Instance();
ASSERT(thread_state->active_threads.fetch_sub(1) != 1);
curthread->lock->lock();
curthread->state = PthreadState::Dead;
ASSERT(False(curthread->flags & ThreadFlags::NeedSuspend));
/*
* Thread was created with initial refcount 1, we drop the
* reference count to allow it to be garbage collected.
*/
curthread->refcount--;
thread_state->TryCollect(curthread, curthread); /* thread lock released */
/*
* Kernel will do wakeup at the address, so joiner thread
* will be resumed if it is sleeping at the address.
*/
curthread->tid.store(TidTerminated);
curthread->tid.notify_all();
pthread_exit(nullptr);
UNREACHABLE();
/* Never reach! */
}
void PS4_SYSV_ABI posix_pthread_exit(void* status) {
Pthread* curthread = g_curthread;
/* Check if this thread is already in the process of exiting: */
ASSERT_MSG(!curthread->cancelling, "Thread {} has called pthread_exit from a destructor",
fmt::ptr(curthread));
/* Flag this thread as exiting. */
curthread->cancelling = 1;
curthread->no_cancel = 1;
curthread->cancel_async = 0;
curthread->cancel_point = 0;
/* Save the return value: */
curthread->ret = status;
while (!curthread->cleanup.empty()) {
PthreadCleanup* old = curthread->cleanup.front();
curthread->cleanup.pop_front();
old->routine(old->routine_arg);
if (old->onheap) {
free(old);
}
}
ExitThread();
}
static int JoinThread(PthreadT pthread, void** thread_return, const OrbisKernelTimespec* abstime) {
Pthread* curthread = g_curthread;
if (pthread == nullptr) {
return POSIX_EINVAL;
}
if (pthread == curthread) {
return POSIX_EDEADLK;
}
auto* thread_state = ThrState::Instance();
if (int ret = thread_state->FindThread(pthread, 1); ret != 0) {
return POSIX_ESRCH;
}
int ret = 0;
if (True(pthread->flags & ThreadFlags::Detached)) {
ret = POSIX_EINVAL;
} else if (pthread->joiner != nullptr) {
/* Multiple joiners are not supported. */
ret = POSIX_ENOTSUP;
}
if (ret) {
pthread->lock->unlock();
return ret;
}
/* Set the running thread to be the joiner: */
pthread->joiner = curthread;
pthread->lock->unlock();
const auto backout_join = [](void* arg) {
Pthread* pthread = (Pthread*)arg;
std::scoped_lock lk{*pthread->lock};
pthread->joiner = nullptr;
};
PthreadCleanup cup{backout_join, pthread, 0};
curthread->cleanup.push_front(&cup);
//_thr_cancel_enter(curthread);
const int tid = pthread->tid;
while (pthread->tid.load() != TidTerminated) {
//_thr_testcancel(curthread);
ASSERT(abstime == nullptr);
pthread->tid.wait(tid);
}
//_thr_cancel_leave(curthread, 0);
curthread->cleanup.pop_front();
if (ret == POSIX_ETIMEDOUT) {
backout_join(pthread);
return ret;
}
void* tmp = pthread->ret;
pthread->lock->lock();
pthread->flags |= ThreadFlags::Detached;
pthread->joiner = nullptr;
thread_state->TryCollect(curthread, pthread); /* thread lock released */
if (thread_return != nullptr) {
*thread_return = tmp;
}
return 0;
}
int PS4_SYSV_ABI posix_pthread_join(PthreadT pthread, void** thread_return) {
return JoinThread(pthread, thread_return, NULL);
}
int PS4_SYSV_ABI posix_pthread_timedjoin_np(PthreadT pthread, void** thread_return,
const OrbisKernelTimespec* abstime) {
if (abstime == nullptr || abstime->tv_sec < 0 || abstime->tv_nsec < 0 ||
abstime->tv_nsec >= 1000000000) {
return POSIX_EINVAL;
}
return JoinThread(pthread, thread_return, abstime);
}
int PS4_SYSV_ABI posix_pthread_detach(PthreadT pthread) {
if (pthread == nullptr) {
return POSIX_EINVAL;
}
auto* thread_state = ThrState::Instance();
if (int ret = thread_state->FindThread(pthread, 1); ret != 0) {
return ret;
}
/* Check if the thread is already detached or has a joiner. */
if (True(pthread->flags & ThreadFlags::Detached) || (pthread->joiner != NULL)) {
pthread->lock->unlock();
return POSIX_EINVAL;
}
/* Flag the thread as detached. */
pthread->flags |= ThreadFlags::Detached;
thread_state->TryCollect(g_curthread, pthread); /* thread lock released */
return 0;
}
static void RunThread(Pthread* curthread) {
g_curthread = curthread;
@ -32,8 +198,7 @@ static void RunThread(Pthread* curthread) {
DebugState.AddCurrentThreadToGuestList();
/* Run the current thread's start routine with argument: */
const auto* linker = Common::Singleton<Core::Linker>::Instance();
void* ret = linker->ExecuteGuest(curthread->start_routine, curthread->arg);
void* ret = Core::ExecuteGuest(curthread->start_routine, curthread->arg);
/* Remove thread from tracking */
DebugState.RemoveCurrentThreadFromGuestList();
@ -56,7 +221,7 @@ int PS4_SYSV_ABI posix_pthread_create_name_np(PthreadT* thread, const PthreadAtt
new_thread->attr = *(*attr);
new_thread->attr.cpusetsize = 0;
}
if (new_thread->attr.sched_inherit == PTHREAD_INHERIT_SCHED) {
if (new_thread->attr.sched_inherit == PthreadInheritSched) {
if (True(curthread->attr.flags & PthreadAttrFlags::ScopeSystem)) {
new_thread->attr.flags |= PthreadAttrFlags::ScopeSystem;
} else {
@ -85,7 +250,7 @@ int PS4_SYSV_ABI posix_pthread_create_name_np(PthreadT* thread, const PthreadAtt
new_thread->cancel_async = 0;
auto* memory = Core::Memory::Instance();
if (memory->IsValidAddress(name)) {
if (name && (std::string_view{name} == "GAME_MainThread" || memory->IsValidAddress(name))) {
new_thread->name = name;
}
@ -109,6 +274,7 @@ int PS4_SYSV_ABI posix_pthread_create_name_np(PthreadT* thread, const PthreadAtt
pthread_attr_setstack(&pattr, new_thread->attr.stackaddr_attr, new_thread->attr.stacksize_attr);
pthread_t pthr;
int ret = pthread_create(&pthr, &pattr, (PthreadEntryFunc)RunThread, new_thread);
ASSERT_MSG(ret == 0, "Failed to create thread with error {}", ret);
if (ret) {
*thread = nullptr;
}
@ -203,6 +369,7 @@ void RegisterThread(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("m0iS6jNsXds", "libScePosix", 1, "libkernel", 1, 1, posix_sched_get_priority_min);
LIB_FUNCTION("EotR8a3ASf4", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_self);
LIB_FUNCTION("B5GmVDKwpn0", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_yield);
LIB_FUNCTION("+U1R4WtXvoc", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_detach);
// Posix-Kernel
LIB_FUNCTION("EotR8a3ASf4", "libkernel", 1, "libkernel", 1, 1, posix_pthread_self);
@ -212,6 +379,7 @@ void RegisterThread(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("GBUY7ywdULE", "libkernel", 1, "libkernel", 1, 1, ORBIS(posix_pthread_rename_np));
LIB_FUNCTION("6UgtwV+0zb4", "libkernel", 1, "libkernel", 1, 1,
ORBIS(posix_pthread_create_name_np));
LIB_FUNCTION("4qGrR6eoP9Y", "libkernel", 1, "libkernel", 1, 1, ORBIS(posix_pthread_detach));
LIB_FUNCTION("aI+OeCz8xrQ", "libkernel", 1, "libkernel", 1, 1, posix_pthread_self);
LIB_FUNCTION("3PtV6p3QNX4", "libkernel", 1, "libkernel", 1, 1, posix_pthread_equal);
LIB_FUNCTION("T72hz6ffq08", "libkernel", 1, "libkernel", 1, 1, posix_pthread_yield);

View file

@ -1,10 +1,10 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/alignment.h"
#include "common/assert.h"
#include "common/singleton.h"
#include "core/libraries/kernel/threads/threads.h"
#include "core/libraries/libs.h"
#include "core/linker.h"
#include "core/tls.h"
@ -16,11 +16,10 @@ static constexpr size_t TlsTcbAlign = 0x20;
static std::shared_mutex RtldLock;
Core::Tcb* TcbCtor(Pthread* thread, int initial) {
ASSERT(initial == 0);
std::scoped_lock lk{RtldLock};
auto* linker = Common::Singleton<Core::Linker>::Instance();
auto* addr_out = linker->AllocateTlsForThread(false);
auto* addr_out = linker->AllocateTlsForThread(initial);
ASSERT_MSG(addr_out, "Unable to allocate guest TCB");
// Initialize allocated memory and allocate DTV table.
@ -43,15 +42,15 @@ Core::Tcb* TcbCtor(Pthread* thread, int initial) {
auto* module = linker->GetModule(0);
u8* dest = reinterpret_cast<u8*>(addr + static_tls_size - module->tls.offset);
if (module->tls.image_virtual_addr != 0) {
const u8* src = reinterpret_cast<const u8*>(module->tls.image_virtual_addr);
memcpy(dest, src, module->tls.init_image_size);
if (module->tls.image_size != 0) {
if (module->tls.image_virtual_addr != 0) {
const u8* src = reinterpret_cast<const u8*>(module->tls.image_virtual_addr);
memcpy(dest, src, module->tls.init_image_size);
}
ASSERT_MSG(module->tls.modid > 0 && module->tls.modid <= num_dtvs);
tcb->tcb_dtv[module->tls.modid + 1].pointer = dest;
}
// Initialize DTV entry of main module
ASSERT_MSG(module->tls.modid > 0 && module->tls.modid <= num_dtvs);
tcb->tcb_dtv[module->tls.modid + 1].pointer = dest;
if (tcb) {
tcb->tcb_thread = thread;
}
@ -68,21 +67,12 @@ void TcbDtor(Core::Tcb* oldtls) {
ASSERT_MSG(num_dtvs <= max_tls_index, "Out of bounds DTV access");
const u32 static_tls_size = linker->StaticTlsSize();
const u8* tls_base = (const u8*)oldtls - Common::AlignUp(static_tls_size, tcbalign);
const u8* tls_base = (const u8*)oldtls - static_tls_size;
for (int i = 1; i < num_dtvs; i++) {
u8* dtv_ptr = dtv_table[i + 1].pointer;
if (dtv_ptr && (dtv_ptr < tls_base || (const u8*)oldtls < dtv_ptr)) {
bool is_occupied;
_is_occupied = IsDtvIndexOccupied ? ((ulong)tcb, next);
if (_is_occupied != 0) {
FreeMem(dtv_ptr);
return;
}
(**(code**)(LibcHeapApiPtr + 8))(dtv_ptr);
FreeIfOccupied(tcb, dtv_addr & 0xffffffffffff, mod_index);
dtv[modid + 1] = (ulong) * (ushort*)((long)dtv + modid * 8 + 0xe) << 0x30;
linker->FreeTlsForNonPrimaryThread(dtv_ptr);
}
}
@ -99,4 +89,8 @@ void* PS4_SYSV_ABI __tls_get_addr(TlsIndex* index) {
return linker->TlsGetAddr(index->ti_module, index->ti_offset);
}
void RegisterRtld(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("vNe1w4diLCs", "libkernel", 1, "libkernel", 1, 1, __tls_get_addr);
}
} // namespace Libraries::Kernel

View file

@ -7,175 +7,4 @@
#include "core/libraries/kernel/threads/thread_state.h"
#include "core/libraries/kernel/threads/threads.h"
namespace Libraries::Kernel {
void _thread_cleanupspecific();
static void ExitThread() {
Pthread* curthread = g_curthread;
/* Check if there is thread specific data: */
if (curthread->specific != nullptr) {
/* Run the thread-specific data destructors: */
_thread_cleanupspecific();
}
auto* thread_state = ThrState::Instance();
ASSERT(thread_state->active_threads.fetch_sub(1) != 1);
curthread->lock->lock();
curthread->state = PthreadState::Dead;
ASSERT(False(curthread->flags & ThreadFlags::NeedSuspend));
/*
* Thread was created with initial refcount 1, we drop the
* reference count to allow it to be garbage collected.
*/
curthread->refcount--;
thread_state->TryCollect(curthread, curthread); /* thread lock released */
/*
* Kernel will do wakeup at the address, so joiner thread
* will be resumed if it is sleeping at the address.
*/
curthread->tid.store(TidTerminated);
curthread->tid.notify_all();
pthread_exit(nullptr);
UNREACHABLE();
/* Never reach! */
}
void PS4_SYSV_ABI posix_pthread_exit(void* status) {
Pthread* curthread = g_curthread;
/* Check if this thread is already in the process of exiting: */
ASSERT_MSG(!curthread->cancelling, "Thread {} has called pthread_exit from a destructor",
fmt::ptr(curthread));
/* Flag this thread as exiting. */
curthread->cancelling = 1;
curthread->no_cancel = 1;
curthread->cancel_async = 0;
curthread->cancel_point = 0;
/* Save the return value: */
curthread->ret = status;
while (!curthread->cleanup.empty()) {
PthreadCleanup* old = curthread->cleanup.front();
curthread->cleanup.pop_front();
old->routine(old->routine_arg);
if (old->onheap) {
free(old);
}
}
ExitThread();
}
static int JoinThread(PthreadT pthread, void** thread_return, const OrbisKernelTimespec* abstime) {
Pthread* curthread = g_curthread;
if (pthread == nullptr) {
return POSIX_EINVAL;
}
if (pthread == curthread) {
return POSIX_EDEADLK;
}
auto* thread_state = ThrState::Instance();
if (int ret = thread_state->FindThread(pthread, 1); ret != 0) {
return POSIX_ESRCH;
}
int ret = 0;
if (True(pthread->flags & ThreadFlags::Detached)) {
ret = POSIX_EINVAL;
} else if (pthread->joiner != nullptr) {
/* Multiple joiners are not supported. */
ret = POSIX_ENOTSUP;
}
if (ret) {
pthread->lock->unlock();
return ret;
}
/* Set the running thread to be the joiner: */
pthread->joiner = curthread;
pthread->lock->unlock();
const auto backout_join = [](void* arg) {
Pthread* pthread = (Pthread*)arg;
std::scoped_lock lk{*pthread->lock};
pthread->joiner = nullptr;
};
PthreadCleanup cup{backout_join, pthread, 0};
curthread->cleanup.push_front(&cup);
//_thr_cancel_enter(curthread);
const int tid = pthread->tid;
while (pthread->tid.load() != TidTerminated) {
//_thr_testcancel(curthread);
ASSERT(abstime == nullptr);
pthread->tid.wait(tid);
}
//_thr_cancel_leave(curthread, 0);
curthread->cleanup.pop_front();
if (ret == POSIX_ETIMEDOUT) {
backout_join(pthread);
return ret;
}
void* tmp = pthread->ret;
pthread->lock->lock();
pthread->flags |= ThreadFlags::Detached;
pthread->joiner = nullptr;
thread_state->TryCollect(curthread, pthread); /* thread lock released */
if (thread_return != nullptr) {
*thread_return = tmp;
}
return 0;
}
int PS4_SYSV_ABI posix_pthread_join(PthreadT pthread, void** thread_return) {
return JoinThread(pthread, thread_return, NULL);
}
int PS4_SYSV_ABI posix_pthread_timedjoin_np(PthreadT pthread, void** thread_return,
const OrbisKernelTimespec* abstime) {
if (abstime == nullptr || abstime->tv_sec < 0 || abstime->tv_nsec < 0 ||
abstime->tv_nsec >= 1000000000) {
return POSIX_EINVAL;
}
return JoinThread(pthread, thread_return, abstime);
}
int PS4_SYSV_ABI posix_pthread_detach(PthreadT pthread) {
if (pthread == nullptr) {
return POSIX_EINVAL;
}
auto* thread_state = ThrState::Instance();
if (int ret = thread_state->FindThread(pthread, 1); ret != 0) {
return ret;
}
/* Check if the thread is already detached or has a joiner. */
if (True(pthread->flags & ThreadFlags::Detached) || (pthread->joiner != NULL)) {
pthread->lock->unlock();
return POSIX_EINVAL;
}
/* Flag the thread as detached. */
pthread->flags |= ThreadFlags::Detached;
thread_state->TryCollect(g_curthread, pthread); /* thread lock released */
return 0;
}
} // namespace Libraries::Kernel
namespace Libraries::Kernel {} // namespace Libraries::Kernel

View file

@ -99,7 +99,7 @@ int PS4_SYSV_ABI posix_pthread_mutex_destroy(PthreadMutexT* mutex) {
return POSIX_EINVAL;
}
if (m->m_owner != nullptr) {
return EBUSY;
return POSIX_EBUSY;
}
*mutex = THR_MUTEX_DESTROYED;
std::destroy_at(m);

View file

@ -178,7 +178,17 @@ int PS4_SYSV_ABI posix_pthread_rwlock_unlock(PthreadRwlockT* rwlock) {
return POSIX_EINVAL;
}
s32 state = prwlock->lock.rw_state;
if (prwlock->owner == curthread) {
prwlock->lock.unlock();
prwlock->owner = nullptr;
} else {
prwlock->lock.unlock_shared();
if (prwlock->owner == nullptr) {
curthread->rdlock_count--;
}
}
/*s32 state = prwlock->lock.rw_state;
if (state & URWLOCK_WRITE_OWNER) {
if (prwlock->owner != curthread) [[unlikely]] {
return POSIX_EPERM;
@ -189,7 +199,7 @@ int PS4_SYSV_ABI posix_pthread_rwlock_unlock(PthreadRwlockT* rwlock) {
prwlock->lock.unlock();
if ((state & URWLOCK_WRITE_OWNER) == 0) {
curthread->rdlock_count--;
}
}*/
return 0;
}

View file

@ -140,20 +140,6 @@ const void* PS4_SYSV_ABI posix_pthread_getspecific(PthreadKeyT key) {
return nullptr;
}
void _thr_tsd_unload(struct dl_phdr_info* phdr_info) {
std::scoped_lock lk{KeytableLock};
for (int key = 0; key < PTHREAD_KEYS_MAX; key++) {
if (!ThreadKeytable[key].allocated) {
continue;
}
const auto destructor = ThreadKeytable[key].destructor;
if (destructor != nullptr) {
if (__elf_phdr_match_addr(phdr_info, destructor))
ThreadKeytable[key].destructor = nullptr;
}
}
}
void RegisterSpec(Core::Loader::SymbolsResolver* sym) {
// Posix
LIB_FUNCTION("mqULNdimTn0", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_key_create);
@ -162,8 +148,7 @@ void RegisterSpec(Core::Loader::SymbolsResolver* sym) {
// Orbis
LIB_FUNCTION("geDaqgH9lTg", "libkernel", 1, "libkernel", 1, 1, ORBIS(posix_pthread_key_create));
LIB_FUNCTION("eoht7mQOCmo", "libkernel", 1, "libkernel", 1, 1,
ORBIS(posix_pthread_getspecific));
LIB_FUNCTION("eoht7mQOCmo", "libkernel", 1, "libkernel", 1, 1, posix_pthread_getspecific);
LIB_FUNCTION("+BzXYkqYeLE", "libkernel", 1, "libkernel", 1, 1,
ORBIS(posix_pthread_setspecific));
}

View file

@ -78,7 +78,8 @@ int ThreadState::CreateStack(PthreadAttr* attr) {
/* Allocate a stack from usrstack. */
if (last_stack == 0) {
last_stack = _usrstack - ThrStackInitial - ThrGuardDefault;
static constexpr VAddr UsrStack = 0x7EFFF8000ULL;
last_stack = UsrStack - ThrStackInitial - ThrGuardDefault;
}
/* Allocate a new stack. */

View file

@ -10,6 +10,8 @@
namespace Libraries::Kernel {
Pthread* g_curthread{};
Core::Tcb* TcbCtor(Pthread* thread, int initial);
void TcbDtor(Core::Tcb* oldtls);
@ -85,11 +87,11 @@ Pthread* ThreadState::Alloc(Pthread* curthread) {
tcb = TcbCtor(thread, 1 /* initial tls */);
}
if (tcb != nullptr) {
memset(thread, 0, sizeof(*thread));
thread->tcb = tcb;
// thread->sleepqueue = _sleepq_alloc();
// thread->wake_addr = _thr_alloc_wake_addr();
} else {
std::destroy_at(thread);
free(thread);
total_threads.fetch_sub(1);
thread = nullptr;
@ -108,6 +110,7 @@ void ThreadState::Free(Pthread* curthread, Pthread* thread) {
if (free_threads.size() >= MaxCachedThreads) {
//_sleepq_free(thread->sleepqueue);
//_thr_release_wake_addr(thread->wake_addr);
std::destroy_at(thread);
free(thread);
total_threads.fetch_sub(1);
} else {

View file

@ -194,6 +194,8 @@ enum class ThreadListFlags : u32 {
InGcList = 4,
};
using PthreadEntryFunc = void* (*)(void*);
constexpr u32 TidTerminated = 1;
struct Pthread {
@ -272,15 +274,6 @@ void RegisterSemaphore(Core::Loader::SymbolsResolver* sym);
void RegisterSpec(Core::Loader::SymbolsResolver* sym);
void RegisterThreadAttr(Core::Loader::SymbolsResolver* sym);
void RegisterThread(Core::Loader::SymbolsResolver* sym);
inline void RegisterThreads(Core::Loader::SymbolsResolver* sym) {
RegisterMutex(sym);
RegisterCond(sym);
RegisterRwlock(sym);
RegisterSemaphore(sym);
RegisterSpec(sym);
RegisterThreadAttr(sym);
RegisterThread(sym);
}
void RegisterRtld(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::Kernel

View file

@ -49,11 +49,9 @@ namespace Libraries {
void InitHLELibs(Core::Loader::SymbolsResolver* sym) {
LOG_INFO(Lib_Kernel, "Initializing HLE libraries");
Libraries::Kernel::LibKernel_Register(sym);
Libraries::Kernel::RegisterKernel(sym);
Libraries::GnmDriver::RegisterlibSceGnmDriver(sym);
Libraries::VideoOut::RegisterLib(sym);
// New libraries folder from autogen
Libraries::UserService::RegisterlibSceUserService(sym);
Libraries::SystemService::RegisterlibSceSystemService(sym);
Libraries::CommonDialog::RegisterlibSceCommonDialog(sym);

View file

@ -1,80 +1,62 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/singleton.h"
#include "core/linker.h"
#include "net_ctl_codes.h"
#include "net_ctl_obj.h"
#include "core/libraries/network/net_ctl_codes.h"
#include "core/libraries/network/net_ctl_obj.h"
#include "core/tls.h"
Libraries::NetCtl::NetCtlInternal::NetCtlInternal() {
callbacks.fill({nullptr, nullptr});
nptoolCallbacks.fill({nullptr, nullptr});
}
namespace Libraries::NetCtl {
Libraries::NetCtl::NetCtlInternal::~NetCtlInternal() {}
NetCtlInternal::NetCtlInternal() = default;
s32 Libraries::NetCtl::NetCtlInternal::registerCallback(OrbisNetCtlCallback func, void* arg) {
std::unique_lock lock{m_mutex};
NetCtlInternal::~NetCtlInternal() = default;
s32 NetCtlInternal::RegisterCallback(OrbisNetCtlCallback func, void* arg) {
std::scoped_lock lock{m_mutex};
// Find the next available slot
int next_id = 0;
for (const auto& callback : callbacks) {
if (callback.func == nullptr) {
break;
}
next_id++;
}
if (next_id == 8) {
const auto it = std::ranges::find(callbacks, nullptr, &NetCtlCallback::func);
if (it == callbacks.end()) {
return ORBIS_NET_CTL_ERROR_CALLBACK_MAX;
}
const int next_id = std::distance(callbacks.begin(), it);
callbacks[next_id].func = func;
callbacks[next_id].arg = arg;
return next_id;
}
s32 Libraries::NetCtl::NetCtlInternal::registerNpToolkitCallback(
OrbisNetCtlCallbackForNpToolkit func, void* arg) {
std::unique_lock lock{m_mutex};
s32 NetCtlInternal::RegisterNpToolkitCallback(OrbisNetCtlCallbackForNpToolkit func, void* arg) {
std::scoped_lock lock{m_mutex};
// Find the next available slot
int next_id = 0;
for (const auto& callback : nptoolCallbacks) {
if (callback.func == nullptr) {
break;
}
next_id++;
}
if (next_id == 8) {
const auto it = std::ranges::find(nptool_callbacks, nullptr, &NetCtlCallbackForNpToolkit::func);
if (it == nptool_callbacks.end()) {
return ORBIS_NET_CTL_ERROR_CALLBACK_MAX;
}
nptoolCallbacks[next_id].func = func;
nptoolCallbacks[next_id].arg = arg;
const int next_id = std::distance(nptool_callbacks.begin(), it);
nptool_callbacks[next_id].func = func;
nptool_callbacks[next_id].arg = arg;
return next_id;
}
void Libraries::NetCtl::NetCtlInternal::checkCallback() {
std::unique_lock lock{m_mutex};
const auto* linker = Common::Singleton<Core::Linker>::Instance();
for (auto& callback : callbacks) {
if (callback.func != nullptr) {
linker->ExecuteGuest(callback.func, ORBIS_NET_CTL_EVENT_TYPE_DISCONNECTED,
callback.arg);
void NetCtlInternal::CheckCallback() {
std::scoped_lock lock{m_mutex};
for (const auto [func, arg] : callbacks) {
if (func != nullptr) {
Core::ExecuteGuest(func, ORBIS_NET_CTL_EVENT_TYPE_DISCONNECTED, arg);
}
}
}
void Libraries::NetCtl::NetCtlInternal::checkNpToolkitCallback() {
std::unique_lock lock{m_mutex};
const auto* linker = Common::Singleton<Core::Linker>::Instance();
for (auto& callback : nptoolCallbacks) {
if (callback.func != nullptr) {
linker->ExecuteGuest(callback.func, ORBIS_NET_CTL_EVENT_TYPE_DISCONNECTED,
callback.arg);
void NetCtlInternal::CheckNpToolkitCallback() {
std::scoped_lock lock{m_mutex};
for (const auto [func, arg] : nptool_callbacks) {
if (func != nullptr) {
Core::ExecuteGuest(func, ORBIS_NET_CTL_EVENT_TYPE_DISCONNECTED, arg);
}
}
}
} // namespace Libraries::NetCtl

View file

@ -3,9 +3,7 @@
#pragma once
#include <condition_variable>
#include <mutex>
#include "common/types.h"
namespace Libraries::NetCtl {
@ -25,16 +23,17 @@ struct NetCtlCallbackForNpToolkit {
class NetCtlInternal {
public:
NetCtlInternal();
explicit NetCtlInternal();
~NetCtlInternal();
s32 registerCallback(OrbisNetCtlCallback func, void* arg);
s32 registerNpToolkitCallback(OrbisNetCtlCallbackForNpToolkit func, void* arg);
void checkCallback();
void checkNpToolkitCallback();
s32 RegisterCallback(OrbisNetCtlCallback func, void* arg);
s32 RegisterNpToolkitCallback(OrbisNetCtlCallbackForNpToolkit func, void* arg);
void CheckCallback();
void CheckNpToolkitCallback();
public:
std::array<NetCtlCallback, 8> nptoolCallbacks;
std::array<NetCtlCallbackForNpToolkit, 8> callbacks;
std::array<NetCtlCallbackForNpToolkit, 8> nptool_callbacks{};
std::array<NetCtlCallback, 8> callbacks{};
std::mutex m_mutex;
};
} // namespace Libraries::NetCtl

View file

@ -13,7 +13,6 @@
#endif
#include "common/logging/log.h"
#include "common/singleton.h"
#include "core/libraries/error_codes.h"
#include "core/libraries/libs.h"
#include "core/libraries/network/net_ctl_codes.h"
@ -21,6 +20,8 @@
namespace Libraries::NetCtl {
static NetCtlInternal netctl;
int PS4_SYSV_ABI sceNetBweCheckCallbackIpcInt() {
LOG_ERROR(Lib_NetCtl, "(STUBBED) called");
return ORBIS_OK;
@ -92,8 +93,7 @@ int PS4_SYSV_ABI sceNetCtlUnregisterCallbackV6() {
}
int PS4_SYSV_ABI sceNetCtlCheckCallback() {
auto* netctl = Common::Singleton<Libraries::NetCtl::NetCtlInternal>::Instance();
netctl->checkCallback();
netctl.CheckCallback();
return ORBIS_OK;
}
@ -298,8 +298,7 @@ int PS4_SYSV_ABI sceNetCtlRegisterCallback(OrbisNetCtlCallback func, void* arg,
if (!func || !cid) {
return ORBIS_NET_CTL_ERROR_INVALID_ADDR;
}
auto* netctl = Common::Singleton<Libraries::NetCtl::NetCtlInternal>::Instance();
s32 result = netctl->registerCallback(func, arg);
s32 result = netctl.RegisterCallback(func, arg);
if (result < 0) {
return result;
} else {
@ -374,8 +373,7 @@ int PS4_SYSV_ABI Func_D8DCB6973537A3DC() {
}
int PS4_SYSV_ABI sceNetCtlCheckCallbackForNpToolkit() {
auto* netctl = Common::Singleton<Libraries::NetCtl::NetCtlInternal>::Instance();
netctl->checkNpToolkitCallback();
netctl.CheckNpToolkitCallback();
return ORBIS_OK;
}
@ -389,8 +387,7 @@ int PS4_SYSV_ABI sceNetCtlRegisterCallbackForNpToolkit(OrbisNetCtlCallbackForNpT
if (!func || !cid) {
return ORBIS_NET_CTL_ERROR_INVALID_ADDR;
}
auto* netctl = Common::Singleton<Libraries::NetCtl::NetCtlInternal>::Instance();
s32 result = netctl->registerNpToolkitCallback(func, arg);
s32 result = netctl.RegisterNpToolkitCallback(func, arg);
if (result < 0) {
return result;
} else {

View file

@ -4,7 +4,7 @@
#pragma once
#include "common/types.h"
#include "net_ctl_obj.h"
#include "core/libraries/network/net_ctl_obj.h"
namespace Core::Loader {
class SymbolsResolver;

View file

@ -1,13 +1,12 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <common/singleton.h>
#include <core/linker.h>
#include "common/config.h"
#include "common/logging/log.h"
#include "core/libraries/error_codes.h"
#include "core/libraries/libs.h"
#include "np_manager.h"
#include "core/libraries/np_manager/np_manager.h"
#include "core/tls.h"
namespace Libraries::NpManager {
@ -2519,10 +2518,7 @@ struct NpStateCallbackForNpToolkit {
NpStateCallbackForNpToolkit NpStateCbForNp;
int PS4_SYSV_ABI sceNpCheckCallbackForLib() {
// LOG_ERROR(Lib_NpManager, "(STUBBED) called");
const auto* linker = Common::Singleton<Core::Linker>::Instance();
linker->ExecuteGuest(NpStateCbForNp.func, 1, ORBIS_NP_STATE_SIGNED_OUT,
NpStateCbForNp.userdata);
Core::ExecuteGuest(NpStateCbForNp.func, 1, ORBIS_NP_STATE_SIGNED_OUT, NpStateCbForNp.userdata);
return ORBIS_OK;
}

View file

@ -8,30 +8,26 @@
#include "common/logging/log.h"
#include "common/path_util.h"
#include "common/string_util.h"
#include "common/thread.h"
#include "core/aerolib/aerolib.h"
#include "core/aerolib/stubs.h"
#include "core/cpu_patches.h"
#include "core/libraries/kernel/memory_management.h"
#include "core/libraries/kernel/thread_management.h"
#include "core/linker.h"
#include "core/memory.h"
#include "core/tls.h"
#include "core/virtual_memory.h"
#include "debug_state.h"
namespace Core {
using ExitFunc = PS4_SYSV_ABI void (*)();
static PS4_SYSV_ABI void ProgramExitFunc() {
fmt::print("exit function called\n");
LOG_ERROR(Core_Linker, "Exit function called");
}
#ifdef ARCH_X86_64
static PS4_SYSV_ABI void RunMainEntry(VAddr addr, EntryParams* params, ExitFunc exit_func) {
// reinterpret_cast<entry_func_t>(addr)(params, exit_func); // can't be used, stack has to have
// a specific layout
static PS4_SYSV_ABI void* RunMainEntry [[noreturn]] (void* arg) {
EntryParams* params = (EntryParams*)arg;
// Start shared library modules
params->linker->LoadSharedLibraries();
asm volatile("andq $-16, %%rsp\n" // Align to 16 bytes
"subq $8, %%rsp\n" // videoout_basic expects the stack to be misaligned
@ -47,8 +43,9 @@ static PS4_SYSV_ABI void RunMainEntry(VAddr addr, EntryParams* params, ExitFunc
"jmp *%0\n" // can't use call here, as that would mangle the prepared stack.
// there's no coming back
:
: "r"(addr), "r"(params), "r"(exit_func)
: "r"(params->entry_addr), "r"(params), "r"(params->exit_func)
: "rax", "rsi", "rdi");
UNREACHABLE();
}
#endif
@ -62,10 +59,8 @@ void Linker::Execute() {
}
// Calculate static TLS size.
for (const auto& module : m_modules) {
static_tls_size += module->tls.image_size;
module->tls.offset = static_tls_size;
}
Module* module = m_modules[0].get();
static_tls_size = module->tls.offset = module->tls.image_size;
// Relocate all modules
for (const auto& m : m_modules) {
@ -87,36 +82,14 @@ void Linker::Execute() {
}
}
// Init primary thread.
Common::SetCurrentThreadName("GAME_MainThread");
DebugState.AddCurrentThreadToGuestList();
Libraries::Kernel::pthreadInitSelfMainThread();
EnsureThreadInitialized(true);
// Start shared library modules
for (auto& m : m_modules) {
if (m->IsSharedLib()) {
m->Start(0, nullptr, nullptr);
}
}
// Start main module.
EntryParams p{};
p.argc = 1;
p.argv[0] = "eboot.bin";
for (auto& m : m_modules) {
if (!m->IsSharedLib()) {
#ifdef ARCH_X86_64
ExecuteGuest(RunMainEntry, m->GetEntryAddress(), &p, ProgramExitFunc);
#else
UNIMPLEMENTED_MSG(
"Missing guest entrypoint implementation for target CPU architecture.");
#endif
}
}
SetTcbBase(nullptr);
EntryParams* params = new EntryParams;
params->argc = 1;
params->argv[0] = "eboot.bin";
params->entry_addr = module->GetEntryAddress();
params->exit_func = ProgramExitFunc;
params->linker = this;
Libraries::Kernel::LaunchThread(RunMainEntry, params, "GAME_MainThread");
}
s32 Linker::LoadModule(const std::filesystem::path& elf_name, bool is_dynamic) {
@ -337,17 +310,6 @@ void* Linker::TlsGetAddr(u64 module_index, u64 offset) {
return addr + offset;
}
thread_local std::once_flag init_tls_flag;
void Linker::EnsureThreadInitialized(bool is_primary) const {
std::call_once(init_tls_flag, [this, is_primary] {
#ifdef ARCH_X86_64
InitializeThreadPatchStack();
#endif
InitTlsForThread(is_primary);
});
}
void* Linker::AllocateTlsForThread(bool is_primary) {
static constexpr size_t TcbSize = 0x40;
static constexpr size_t TlsAllocAlign = 0x20;
@ -369,7 +331,7 @@ void* Linker::AllocateTlsForThread(bool is_primary) {
ASSERT_MSG(ret == 0, "Unable to allocate TLS+TCB for the primary thread");
} else {
if (heap_api) {
addr_out = heap_api->heap_malloc(total_tls_size);
addr_out = Core::ExecuteGuest(heap_api->heap_malloc, total_tls_size);
} else {
addr_out = std::malloc(total_tls_size);
}
@ -377,22 +339,31 @@ void* Linker::AllocateTlsForThread(bool is_primary) {
return addr_out;
}
void Linker::FreeTlsForNonPrimaryThread(void* pointer) {
if (heap_api) {
Core::ExecuteGuest(heap_api->heap_free, pointer);
} else {
std::free(pointer);
}
}
void Linker::DebugDump() {
const auto& log_dir = Common::FS::GetUserPath(Common::FS::PathType::LogDir);
const std::filesystem::path debug(log_dir / "debugdump");
std::filesystem::create_directory(debug);
for (const auto& m : m_modules) {
// TODO make a folder with game id for being more unique?
const std::filesystem::path filepath(debug / m.get()->file.stem());
Module* module = m.get();
auto& elf = module->elf;
const std::filesystem::path filepath(debug / module->file.stem());
std::filesystem::create_directory(filepath);
m.get()->import_sym.DebugDump(filepath / "imports.txt");
m.get()->export_sym.DebugDump(filepath / "exports.txt");
if (m.get()->elf.IsSelfFile()) {
m.get()->elf.SelfHeaderDebugDump(filepath / "selfHeader.txt");
m.get()->elf.SelfSegHeaderDebugDump(filepath / "selfSegHeaders.txt");
module->import_sym.DebugDump(filepath / "imports.txt");
module->export_sym.DebugDump(filepath / "exports.txt");
if (elf.IsSelfFile()) {
elf.SelfHeaderDebugDump(filepath / "selfHeader.txt");
elf.SelfSegHeaderDebugDump(filepath / "selfSegHeaders.txt");
}
m.get()->elf.ElfHeaderDebugDump(filepath / "elfHeader.txt");
m.get()->elf.PHeaderDebugDump(filepath / "elfPHeaders.txt");
elf.ElfHeaderDebugDump(filepath / "elfHeader.txt");
elf.PHeaderDebugDump(filepath / "elfPHeaders.txt");
}
}

View file

@ -40,10 +40,17 @@ struct OrbisProcParam {
u64 unknown1;
};
using ExitFunc = PS4_SYSV_ABI void (*)();
class Linker;
struct EntryParams {
int argc;
u32 padding;
const char* argv[3];
VAddr entry_addr;
ExitFunc exit_func;
Linker* linker;
};
struct HeapAPI {
@ -101,6 +108,14 @@ public:
}
}
void LoadSharedLibraries() {
for (auto& module : m_modules) {
if (module->IsSharedLib()) {
module->Start(0, nullptr, nullptr);
}
}
}
void SetHeapAPI(void* func[]) {
heap_api = reinterpret_cast<AppHeapAPI>(func);
}
@ -111,6 +126,7 @@ public:
void* TlsGetAddr(u64 module_index, u64 offset);
void* AllocateTlsForThread(bool is_primary);
void FreeTlsForNonPrimaryThread(void* pointer);
s32 LoadModule(const std::filesystem::path& elf_name, bool is_dynamic = false);
Module* FindByAddress(VAddr address);
@ -121,24 +137,8 @@ public:
void Execute();
void DebugDump();
template <class ReturnType, class... FuncArgs, class... CallArgs>
ReturnType ExecuteGuest(PS4_SYSV_ABI ReturnType (*func)(FuncArgs...),
CallArgs&&... args) const {
// Make sure TLS is initialized for the thread before entering guest.
EnsureThreadInitialized();
return ExecuteGuestWithoutTls(func, args...);
}
private:
const Module* FindExportedModule(const ModuleInfo& m, const LibraryInfo& l);
void EnsureThreadInitialized(bool is_primary = false) const;
void InitTlsForThread(bool is_primary) const;
template <class ReturnType, class... FuncArgs, class... CallArgs>
ReturnType ExecuteGuestWithoutTls(PS4_SYSV_ABI ReturnType (*func)(FuncArgs...),
CallArgs&&... args) const {
return func(std::forward<CallArgs>(args)...);
}
MemoryManager* memory;
std::mutex mutex;

View file

@ -148,7 +148,7 @@ public:
VAddr SystemReservedVirtualBase() noexcept {
return impl.SystemReservedVirtualBase();
}
bool IsValidAddress(const void* addr) const noexcept {
const VAddr virtual_addr = reinterpret_cast<VAddr>(addr);
const auto end_it = std::prev(vma_map.end());

View file

@ -9,10 +9,10 @@
#include "common/string_util.h"
#include "core/aerolib/aerolib.h"
#include "core/cpu_patches.h"
#include "core/linker.h"
#include "core/loader/dwarf.h"
#include "core/memory.h"
#include "core/module.h"
#include "core/tls.h"
namespace Core {
@ -70,9 +70,8 @@ Module::~Module() = default;
s32 Module::Start(size_t args, const void* argp, void* param) {
LOG_INFO(Core_Linker, "Module started : {}", name);
const auto* linker = Common::Singleton<Core::Linker>::Instance();
const VAddr addr = dynamic_info.init_virtual_addr + GetBaseAddress();
return linker->ExecuteGuest(reinterpret_cast<EntryFunc>(addr), args, argp, param);
return ExecuteGuest(reinterpret_cast<EntryFunc>(addr), args, argp, param);
}
void Module::LoadModuleToMemory(u32& max_tls_index) {

View file

@ -5,6 +5,8 @@
#include "common/arch.h"
#include "common/assert.h"
#include "common/types.h"
#include "core/cpu_patches.h"
#include "core/libraries/kernel/threads/threads.h"
#include "core/tls.h"
#ifdef _WIN32
@ -181,4 +183,15 @@ Tcb* GetTcbBase() {
#endif
thread_local std::once_flag init_tls_flag;
void EnsureThreadInitialized() {
std::call_once(init_tls_flag, [] {
#ifdef ARCH_X86_64
InitializeThreadPatchStack();
#endif
SetTcbBase(Libraries::Kernel::g_curthread->tcb);
});
}
} // namespace Core

View file

@ -12,7 +12,7 @@ class CodeGenerator;
namespace Core {
union DtvEntry {
size_t counter;
std::size_t counter;
u8* pointer;
};
@ -33,4 +33,13 @@ void SetTcbBase(void* image_address);
/// Retrieves Tcb structure for the calling thread.
Tcb* GetTcbBase();
/// Makes sure TLS is initialized for the thread before entering guest.
void EnsureThreadInitialized();
template <class ReturnType, class... FuncArgs, class... CallArgs>
ReturnType ExecuteGuest(PS4_SYSV_ABI ReturnType (*func)(FuncArgs...), CallArgs&&... args) {
EnsureThreadInitialized();
return func(std::forward<CallArgs>(args)...);
}
} // namespace Core

View file

@ -29,7 +29,6 @@
#include "core/file_sys/fs.h"
#include "core/libraries/disc_map/disc_map.h"
#include "core/libraries/fiber/fiber.h"
#include "core/libraries/kernel/thread_management.h"
#include "core/libraries/libc_internal/libc_internal.h"
#include "core/libraries/libs.h"
#include "core/libraries/ngs2/ngs2.h"
@ -222,7 +221,6 @@ void Emulator::Run(const std::filesystem::path& file) {
VideoCore::SetOutputDir(mount_captures_dir, id);
// Initialize kernel and library facilities.
Libraries::Kernel::init_pthreads();
Libraries::InitHLELibs(&linker->GetHLESymbols());
// Load the module with the linker
@ -257,9 +255,7 @@ void Emulator::Run(const std::filesystem::path& file) {
}
#endif
// start execution
std::jthread mainthread =
std::jthread([this](std::stop_token stop_token) { linker->Execute(); });
linker->Execute();
window->initTimers();
while (window->isOpen()) {