mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-07-03 15:46:20 +00:00
kernel: Fix a bunch of bugs, kernel thread heap
This commit is contained in:
parent
00b84b2c7f
commit
d0d8b5eee5
35 changed files with 924 additions and 242 deletions
|
@ -821,6 +821,9 @@ else()
|
|||
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()
|
||||
|
||||
|
|
163
src/common/slab_heap.h
Normal file
163
src/common/slab_heap.h
Normal file
|
@ -0,0 +1,163 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include "common/assert.h"
|
||||
#include "common/spin_lock.h"
|
||||
|
||||
namespace Common {
|
||||
|
||||
class SlabHeapImpl {
|
||||
public:
|
||||
struct Node {
|
||||
Node* next{};
|
||||
};
|
||||
|
||||
public:
|
||||
constexpr SlabHeapImpl() = default;
|
||||
|
||||
void Initialize() {
|
||||
ASSERT(m_head == nullptr);
|
||||
}
|
||||
|
||||
Node* GetHead() const {
|
||||
return m_head;
|
||||
}
|
||||
|
||||
void* Allocate() {
|
||||
m_lock.lock();
|
||||
|
||||
Node* ret = m_head;
|
||||
if (ret != nullptr) {
|
||||
m_head = ret->next;
|
||||
}
|
||||
|
||||
m_lock.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Free(void* obj) {
|
||||
m_lock.lock();
|
||||
|
||||
Node* node = static_cast<Node*>(obj);
|
||||
node->next = m_head;
|
||||
m_head = node;
|
||||
|
||||
m_lock.unlock();
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic<Node*> m_head{};
|
||||
Common::SpinLock m_lock;
|
||||
};
|
||||
|
||||
class SlabHeapBase : protected SlabHeapImpl {
|
||||
private:
|
||||
size_t m_obj_size{};
|
||||
uintptr_t m_peak{};
|
||||
uintptr_t m_start{};
|
||||
uintptr_t m_end{};
|
||||
|
||||
public:
|
||||
constexpr SlabHeapBase() = default;
|
||||
|
||||
bool Contains(uintptr_t address) const {
|
||||
return m_start <= address && address < m_end;
|
||||
}
|
||||
|
||||
void Initialize(size_t obj_size, void* memory, size_t memory_size) {
|
||||
// Ensure we don't initialize a slab using null memory.
|
||||
ASSERT(memory != nullptr);
|
||||
|
||||
// Set our object size.
|
||||
m_obj_size = obj_size;
|
||||
|
||||
// Initialize the base allocator.
|
||||
SlabHeapImpl::Initialize();
|
||||
|
||||
// Set our tracking variables.
|
||||
const size_t num_obj = (memory_size / obj_size);
|
||||
m_start = reinterpret_cast<uintptr_t>(memory);
|
||||
m_end = m_start + num_obj * obj_size;
|
||||
m_peak = m_start;
|
||||
|
||||
// Free the objects.
|
||||
u8* cur = reinterpret_cast<u8*>(m_end);
|
||||
|
||||
for (size_t i = 0; i < num_obj; i++) {
|
||||
cur -= obj_size;
|
||||
SlabHeapImpl::Free(cur);
|
||||
}
|
||||
}
|
||||
|
||||
size_t GetSlabHeapSize() const {
|
||||
return (m_end - m_start) / this->GetObjectSize();
|
||||
}
|
||||
|
||||
size_t GetObjectSize() const {
|
||||
return m_obj_size;
|
||||
}
|
||||
|
||||
void* Allocate() {
|
||||
void* obj = SlabHeapImpl::Allocate();
|
||||
return obj;
|
||||
}
|
||||
|
||||
void Free(void* obj) {
|
||||
// Don't allow freeing an object that wasn't allocated from this heap.
|
||||
const bool contained = this->Contains(reinterpret_cast<uintptr_t>(obj));
|
||||
ASSERT(contained);
|
||||
SlabHeapImpl::Free(obj);
|
||||
}
|
||||
|
||||
size_t GetObjectIndex(const void* obj) const {
|
||||
return (reinterpret_cast<uintptr_t>(obj) - m_start) / this->GetObjectSize();
|
||||
}
|
||||
|
||||
size_t GetPeakIndex() const {
|
||||
return this->GetObjectIndex(reinterpret_cast<const void*>(m_peak));
|
||||
}
|
||||
|
||||
uintptr_t GetSlabHeapAddress() const {
|
||||
return m_start;
|
||||
}
|
||||
|
||||
size_t GetNumRemaining() const {
|
||||
// Only calculate the number of remaining objects under debug configuration.
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class SlabHeap final : public SlabHeapBase {
|
||||
private:
|
||||
using BaseHeap = SlabHeapBase;
|
||||
|
||||
public:
|
||||
constexpr SlabHeap() = default;
|
||||
|
||||
void Initialize(void* memory, size_t memory_size) {
|
||||
BaseHeap::Initialize(sizeof(T), memory, memory_size);
|
||||
}
|
||||
|
||||
T* Allocate() {
|
||||
T* obj = static_cast<T*>(BaseHeap::Allocate());
|
||||
|
||||
if (obj != nullptr) [[likely]] {
|
||||
std::construct_at(obj);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
void Free(T* obj) {
|
||||
BaseHeap::Free(obj);
|
||||
}
|
||||
|
||||
size_t GetObjectIndex(const T* obj) const {
|
||||
return BaseHeap::GetObjectIndex(obj);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Common
|
|
@ -3,10 +3,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <bit>
|
||||
#include <compare>
|
||||
#include <numeric>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "common/assert.h"
|
||||
|
|
53
src/common/spin_lock.cpp
Executable file
53
src/common/spin_lock.cpp
Executable file
|
@ -0,0 +1,53 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/spin_lock.h"
|
||||
|
||||
#if _MSC_VER
|
||||
#include <intrin.h>
|
||||
#if _M_AMD64
|
||||
#define __x86_64__ 1
|
||||
#endif
|
||||
#if _M_ARM64
|
||||
#define __aarch64__ 1
|
||||
#endif
|
||||
#else
|
||||
#if __x86_64__
|
||||
#include <xmmintrin.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
void ThreadPause() {
|
||||
#if __x86_64__
|
||||
_mm_pause();
|
||||
#elif __aarch64__ && _MSC_VER
|
||||
__yield();
|
||||
#elif __aarch64__
|
||||
asm("yield");
|
||||
#endif
|
||||
}
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
namespace Common {
|
||||
|
||||
void SpinLock::lock() {
|
||||
while (lck.test_and_set(std::memory_order_acquire)) {
|
||||
ThreadPause();
|
||||
}
|
||||
}
|
||||
|
||||
void SpinLock::unlock() {
|
||||
lck.clear(std::memory_order_release);
|
||||
}
|
||||
|
||||
bool SpinLock::try_lock() {
|
||||
if (lck.test_and_set(std::memory_order_acquire)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Common
|
33
src/common/spin_lock.h
Executable file
33
src/common/spin_lock.h
Executable file
|
@ -0,0 +1,33 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
|
||||
namespace Common {
|
||||
|
||||
/**
|
||||
* SpinLock class
|
||||
* a lock similar to mutex that forces a thread to spin wait instead calling the
|
||||
* supervisor. Should be used on short sequences of code.
|
||||
*/
|
||||
class SpinLock {
|
||||
public:
|
||||
SpinLock() = default;
|
||||
|
||||
SpinLock(const SpinLock&) = delete;
|
||||
SpinLock& operator=(const SpinLock&) = delete;
|
||||
|
||||
SpinLock(SpinLock&&) = delete;
|
||||
SpinLock& operator=(SpinLock&&) = delete;
|
||||
|
||||
void lock();
|
||||
void unlock();
|
||||
[[nodiscard]] bool try_lock();
|
||||
|
||||
private:
|
||||
std::atomic_flag lck = ATOMIC_FLAG_INIT;
|
||||
};
|
||||
|
||||
} // namespace Common
|
|
@ -305,7 +305,7 @@ void RegisterlibSceAvPlayer(Core::Loader::SymbolsResolver* sym) {
|
|||
LIB_FUNCTION("XC9wM+xULz8", "libSceAvPlayer", 1, "libSceAvPlayer", 1, 0, sceAvPlayerJumpToTime);
|
||||
LIB_FUNCTION("9y5v+fGN4Wk", "libSceAvPlayer", 1, "libSceAvPlayer", 1, 0, sceAvPlayerPause);
|
||||
LIB_FUNCTION("HD1YKVU26-M", "libSceAvPlayer", 1, "libSceAvPlayer", 1, 0, sceAvPlayerPostInit);
|
||||
LIB_FUNCTION("agig-iDRrTE", "libSceAvPlayer", 1, "libSceAvPlayer", 1, 0, sceAvPlayerPrintf);
|
||||
// LIB_FUNCTION("agig-iDRrTE", "libSceAvPlayer", 1, "libSceAvPlayer", 1, 0, sceAvPlayerPrintf);
|
||||
LIB_FUNCTION("w5moABNwnRY", "libSceAvPlayer", 1, "libSceAvPlayer", 1, 0, sceAvPlayerResume);
|
||||
LIB_FUNCTION("k-q+xOxdc3E", "libSceAvPlayer", 1, "libSceAvPlayer", 1, 0,
|
||||
sceAvPlayerSetAvSyncMode);
|
||||
|
|
|
@ -252,11 +252,9 @@ bool AvPlayerSource::Start() {
|
|||
LOG_ERROR(Lib_AvPlayer, "Could not start playback. NULL context.");
|
||||
return false;
|
||||
}
|
||||
m_demuxer_thread = std::jthread([this](std::stop_token stop) { this->DemuxerThread(stop); });
|
||||
m_video_decoder_thread =
|
||||
std::jthread([this](std::stop_token stop) { this->VideoDecoderThread(stop); });
|
||||
m_audio_decoder_thread =
|
||||
std::jthread([this](std::stop_token stop) { this->AudioDecoderThread(stop); });
|
||||
m_demuxer_thread.Run([this](std::stop_token stop) { this->DemuxerThread(stop); });
|
||||
m_video_decoder_thread.Run([this](std::stop_token stop) { this->VideoDecoderThread(stop); });
|
||||
m_audio_decoder_thread.Run([this](std::stop_token stop) { this->AudioDecoderThread(stop); });
|
||||
m_start_time = std::chrono::high_resolution_clock::now();
|
||||
return true;
|
||||
}
|
||||
|
@ -269,18 +267,10 @@ bool AvPlayerSource::Stop() {
|
|||
return false;
|
||||
}
|
||||
|
||||
m_video_decoder_thread.request_stop();
|
||||
m_audio_decoder_thread.request_stop();
|
||||
m_demuxer_thread.request_stop();
|
||||
if (m_demuxer_thread.joinable()) {
|
||||
m_demuxer_thread.join();
|
||||
}
|
||||
if (m_video_decoder_thread.joinable()) {
|
||||
m_video_decoder_thread.join();
|
||||
}
|
||||
if (m_audio_decoder_thread.joinable()) {
|
||||
m_audio_decoder_thread.join();
|
||||
}
|
||||
m_video_decoder_thread.Stop();
|
||||
m_audio_decoder_thread.Stop();
|
||||
m_demuxer_thread.Stop();
|
||||
|
||||
if (m_current_audio_frame.has_value()) {
|
||||
m_audio_buffers.Push(std::move(m_current_audio_frame.value()));
|
||||
m_current_audio_frame.reset();
|
||||
|
@ -504,12 +494,8 @@ void AvPlayerSource::DemuxerThread(std::stop_token stop) {
|
|||
m_video_frames_cv.Notify();
|
||||
m_audio_frames_cv.Notify();
|
||||
|
||||
if (m_video_decoder_thread.joinable()) {
|
||||
m_video_decoder_thread.join();
|
||||
}
|
||||
if (m_audio_decoder_thread.joinable()) {
|
||||
m_audio_decoder_thread.join();
|
||||
}
|
||||
m_video_decoder_thread.Join();
|
||||
m_audio_decoder_thread.Join();
|
||||
m_state.OnEOF();
|
||||
|
||||
LOG_INFO(Lib_AvPlayer, "Demuxer Thread exited normally");
|
||||
|
@ -802,8 +788,8 @@ void AvPlayerSource::AudioDecoderThread(std::stop_token stop) {
|
|||
}
|
||||
|
||||
bool AvPlayerSource::HasRunningThreads() const {
|
||||
return m_demuxer_thread.joinable() || m_video_decoder_thread.joinable() ||
|
||||
m_audio_decoder_thread.joinable();
|
||||
return m_demuxer_thread.Joinable() || m_video_decoder_thread.Joinable() ||
|
||||
m_audio_decoder_thread.Joinable();
|
||||
}
|
||||
|
||||
} // namespace Libraries::AvPlayer
|
||||
|
|
|
@ -11,10 +11,10 @@
|
|||
#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"
|
||||
#include "core/libraries/kernel/thread_management.h"
|
||||
|
||||
struct AVCodecContext;
|
||||
struct AVFormatContext;
|
||||
|
@ -200,9 +200,9 @@ private:
|
|||
EventCV m_stop_cv{};
|
||||
|
||||
std::mutex m_state_mutex{};
|
||||
std::jthread m_demuxer_thread{};
|
||||
std::jthread m_video_decoder_thread{};
|
||||
std::jthread m_audio_decoder_thread{};
|
||||
Kernel::Thread m_demuxer_thread{};
|
||||
Kernel::Thread m_video_decoder_thread{};
|
||||
Kernel::Thread m_audio_decoder_thread{};
|
||||
|
||||
AVFormatContextPtr m_avformat_context{nullptr, &ReleaseAVFormatContext};
|
||||
AVCodecContextPtr m_video_codec_context{nullptr, &ReleaseAVCodecContext};
|
||||
|
|
|
@ -117,10 +117,7 @@ AvPlayerState::~AvPlayerState() {
|
|||
std::unique_lock lock(m_source_mutex);
|
||||
m_up_source.reset();
|
||||
}
|
||||
if (m_controller_thread.joinable()) {
|
||||
m_controller_thread.request_stop();
|
||||
m_controller_thread.join();
|
||||
}
|
||||
m_controller_thread.Stop();
|
||||
m_event_queue.Clear();
|
||||
}
|
||||
|
||||
|
@ -221,8 +218,7 @@ void AvPlayerState::WarningEvent(s32 id) {
|
|||
|
||||
// Called inside GAME thread
|
||||
void AvPlayerState::StartControllerThread() {
|
||||
m_controller_thread =
|
||||
std::jthread([this](std::stop_token stop) { this->AvControllerThread(stop); });
|
||||
m_controller_thread.Run([this](std::stop_token stop) { this->AvControllerThread(stop); });
|
||||
}
|
||||
|
||||
// Called inside GAME thread
|
||||
|
|
|
@ -7,9 +7,9 @@
|
|||
#include <mutex>
|
||||
#include <shared_mutex>
|
||||
|
||||
#include "common/polyfill_thread.h"
|
||||
#include "core/libraries/avplayer/avplayer.h"
|
||||
#include "core/libraries/avplayer/avplayer_source.h"
|
||||
#include "core/libraries/kernel/thread_management.h"
|
||||
|
||||
namespace Libraries::AvPlayer {
|
||||
|
||||
|
@ -80,7 +80,7 @@ private:
|
|||
std::shared_mutex m_source_mutex{};
|
||||
std::mutex m_state_machine_mutex{};
|
||||
std::mutex m_event_handler_mutex{};
|
||||
std::jthread m_controller_thread{};
|
||||
Kernel::Thread m_controller_thread{};
|
||||
AvPlayerQueue<AvPlayerEvent> m_event_queue{};
|
||||
};
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma clang optimize off
|
||||
#include "gnm_error.h"
|
||||
#include "gnmdriver.h"
|
||||
|
||||
|
|
|
@ -85,8 +85,6 @@ struct iovec {
|
|||
};
|
||||
|
||||
size_t PS4_SYSV_ABI _writev(int fd, const struct iovec* iov, int iovcn) {
|
||||
// weird it gives fd ==0 and writes to stdout , i am not sure if it that is valid (found in
|
||||
// openorbis)
|
||||
size_t total_written = 0;
|
||||
for (int i = 0; i < iovcn; i++) {
|
||||
total_written += ::fwrite(iov[i].iov_base, 1, iov[i].iov_len, stdout);
|
||||
|
|
|
@ -3,7 +3,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <algorithm>
|
||||
#include <fmt/core.h>
|
||||
#include "common/logging/log.h"
|
||||
#include "common/types.h"
|
||||
#include "core/libraries/error_codes.h"
|
||||
|
||||
|
@ -17,11 +19,21 @@ void ErrSceToPosix(int result);
|
|||
int ErrnoToSceKernelError(int e);
|
||||
void SetPosixErrno(int e);
|
||||
|
||||
template <class F, F f>
|
||||
template <size_t N>
|
||||
struct StringLiteral {
|
||||
constexpr StringLiteral(const char (&str)[N]) {
|
||||
std::copy_n(str, N, value);
|
||||
}
|
||||
|
||||
char value[N];
|
||||
};
|
||||
|
||||
template <StringLiteral name, class F, F f>
|
||||
struct WrapperImpl;
|
||||
|
||||
template <class R, class... Args, PS4_SYSV_ABI R (*f)(Args...)>
|
||||
struct WrapperImpl<PS4_SYSV_ABI R (*)(Args...), f> {
|
||||
template <StringLiteral name, class R, class... Args, PS4_SYSV_ABI R (*f)(Args...)>
|
||||
struct WrapperImpl<name, PS4_SYSV_ABI R (*)(Args...), f> {
|
||||
static constexpr StringLiteral Name{name};
|
||||
static R PS4_SYSV_ABI wrap(Args... args) {
|
||||
u32 ret = f(args...);
|
||||
if (ret != 0) {
|
||||
|
@ -31,10 +43,10 @@ struct WrapperImpl<PS4_SYSV_ABI R (*)(Args...), f> {
|
|||
}
|
||||
};
|
||||
|
||||
template <class F, F f>
|
||||
constexpr auto OrbisWrapper = WrapperImpl<F, f>::wrap;
|
||||
template <StringLiteral name, class F, F f>
|
||||
constexpr auto OrbisWrapper = WrapperImpl<name, F, f>::wrap;
|
||||
|
||||
#define ORBIS(func) OrbisWrapper<decltype(&func), func>
|
||||
#define ORBIS(func) WrapperImpl<#func, decltype(&func), func>::wrap
|
||||
|
||||
int* PS4_SYSV_ABI __Error();
|
||||
|
||||
|
|
|
@ -129,6 +129,10 @@ s32 PS4_SYSV_ABI sceKernelMemoryPoolDecommit(void* addr, size_t len, int flags);
|
|||
|
||||
int PS4_SYSV_ABI sceKernelMunmap(void* addr, size_t len);
|
||||
|
||||
void* Malloc(size_t size);
|
||||
|
||||
void Free(void* ptr);
|
||||
|
||||
void RegisterMemory(Core::Loader::SymbolsResolver* sym);
|
||||
|
||||
} // namespace Libraries::Kernel
|
||||
|
|
|
@ -7,20 +7,6 @@
|
|||
|
||||
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);
|
||||
|
|
|
@ -11,8 +11,60 @@ class SymbolsResolver;
|
|||
|
||||
namespace Libraries::Kernel {
|
||||
|
||||
PthreadT LaunchThread(PthreadEntryFunc start_routine, void* arg, const char* name);
|
||||
int PS4_SYSV_ABI posix_pthread_attr_init(PthreadAttrT* attr);
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_attr_destroy(PthreadAttrT* attr);
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_create(PthreadT* thread, const PthreadAttrT* attr,
|
||||
PthreadEntryFunc start_routine, void* arg);
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_join(PthreadT pthread, void** thread_return);
|
||||
|
||||
void RegisterThreads(Core::Loader::SymbolsResolver* sym);
|
||||
|
||||
class Thread {
|
||||
public:
|
||||
explicit Thread() = default;
|
||||
~Thread() {
|
||||
Stop();
|
||||
}
|
||||
|
||||
void Run(std::function<void(std::stop_token)>&& func) {
|
||||
this->func = std::move(func);
|
||||
PthreadAttrT attr{};
|
||||
posix_pthread_attr_init(&attr);
|
||||
posix_pthread_create(&thread, &attr, RunWrapper, this);
|
||||
posix_pthread_attr_destroy(&attr);
|
||||
}
|
||||
|
||||
void Join() {
|
||||
if (thread) {
|
||||
posix_pthread_join(thread, nullptr);
|
||||
thread = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool Joinable() const {
|
||||
return thread != nullptr;
|
||||
}
|
||||
|
||||
void Stop() {
|
||||
if (Joinable()) {
|
||||
stop.request_stop();
|
||||
Join();
|
||||
}
|
||||
}
|
||||
|
||||
static void* RunWrapper(void* arg) {
|
||||
Thread* thr = (Thread*)arg;
|
||||
thr->func(thr->stop.get_token());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
PthreadT thread{};
|
||||
std::function<void(std::stop_token)> func;
|
||||
std::stop_source stop;
|
||||
};
|
||||
|
||||
} // namespace Libraries::Kernel
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma clang optimize off
|
||||
#include "core/libraries/error_codes.h"
|
||||
#include "core/libraries/kernel/libkernel.h"
|
||||
#include "core/libraries/kernel/threads/thread_state.h"
|
||||
|
@ -18,9 +18,9 @@ struct PthreadPrio {
|
|||
};
|
||||
|
||||
static constexpr std::array<PthreadPrio, 3> ThrPriorities = {{
|
||||
{0x2BC, 0x300, 0x3BF}, // Fifo
|
||||
{0x384, 0x100, 0x2FF}, // Other
|
||||
{0x2BC, 0, 1}, // Round-Robin
|
||||
{0x100, 0x2FF, 0x2BC}, // Fifo
|
||||
{0x300, 0x3BF, 0x384}, // Other
|
||||
{0x100, 0x2FF, 0x2BC}, // Round-Robin
|
||||
}};
|
||||
|
||||
PthreadAttr PthreadAttrDefault = {
|
||||
|
@ -33,13 +33,14 @@ PthreadAttr PthreadAttrDefault = {
|
|||
.stacksize_attr = ThrStackDefault,
|
||||
.guardsize_attr = 0,
|
||||
.cpusetsize = 0,
|
||||
.cpuset = nullptr,
|
||||
};
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_attr_destroy(PthreadAttrT* attr) {
|
||||
if (attr == nullptr || *attr == nullptr) {
|
||||
return POSIX_EINVAL;
|
||||
}
|
||||
free(*attr);
|
||||
delete *attr;
|
||||
*attr = nullptr;
|
||||
return 0;
|
||||
}
|
||||
|
@ -112,7 +113,7 @@ int PS4_SYSV_ABI posix_pthread_attr_getstacksize(const PthreadAttrT* attr, size_
|
|||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_attr_init(PthreadAttrT* attr) {
|
||||
PthreadAttrT pattr = (PthreadAttrT)malloc(sizeof(PthreadAttr));
|
||||
PthreadAttrT pattr = new PthreadAttr{};
|
||||
if (pattr == nullptr) {
|
||||
return POSIX_ENOMEM;
|
||||
}
|
||||
|
@ -180,7 +181,7 @@ int PS4_SYSV_ABI posix_pthread_attr_setschedparam(PthreadAttrT* attr, const sche
|
|||
}
|
||||
|
||||
const auto policy = (*attr)->sched_policy;
|
||||
if (policy == SchedPolicy::Fifo || policy == SchedPolicy::RoundRobin) {
|
||||
if (policy == SchedPolicy::RoundRobin) {
|
||||
if (param->sched_priority < ThrPriorities[u32(policy) - 1].pri_min ||
|
||||
param->sched_priority > ThrPriorities[u32(policy) - 1].pri_max) {
|
||||
return POSIX_ENOTSUP;
|
||||
|
@ -224,13 +225,63 @@ 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();
|
||||
pthread->lock.unlock();
|
||||
if (ret == 0) {
|
||||
memcpy(dst, &attr, sizeof(PthreadAttr));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_attr_getaffinity_np(const PthreadAttrT* pattr, size_t cpusetsize,
|
||||
Cpuset* cpusetp) {
|
||||
if (pattr == nullptr) {
|
||||
return POSIX_EINVAL;
|
||||
}
|
||||
PthreadAttrT attr = *pattr;
|
||||
if (attr == nullptr) {
|
||||
return POSIX_EINVAL;
|
||||
}
|
||||
if (attr->cpuset != nullptr)
|
||||
memcpy(cpusetp, attr->cpuset, std::min(cpusetsize, attr->cpusetsize));
|
||||
else
|
||||
memset(cpusetp, -1, sizeof(Cpuset));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI scePthreadAttrGetaffinity(PthreadAttrT* param_1, Cpuset* mask) {
|
||||
Cpuset cpuset;
|
||||
const int ret = posix_pthread_attr_getaffinity_np(param_1, 0x10, &cpuset);
|
||||
if (ret == 0) {
|
||||
*mask = cpuset;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_attr_setaffinity_np(PthreadAttrT* pattr, size_t cpusetsize,
|
||||
const Cpuset* cpusetp) {
|
||||
if (pattr == nullptr) {
|
||||
return POSIX_EINVAL;
|
||||
}
|
||||
PthreadAttrT attr = *pattr;
|
||||
if (attr == nullptr) {
|
||||
return POSIX_EINVAL;
|
||||
}
|
||||
if (cpusetsize == 0 || cpusetp == nullptr) {
|
||||
if (attr->cpuset != nullptr) {
|
||||
free(attr->cpuset);
|
||||
attr->cpuset = NULL;
|
||||
attr->cpusetsize = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (attr->cpuset == nullptr) {
|
||||
attr->cpuset = (Cpuset*)calloc(1, sizeof(Cpuset));
|
||||
attr->cpusetsize = sizeof(Cpuset);
|
||||
}
|
||||
memcpy(attr->cpuset, cpusetp, sizeof(Cpuset));
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RegisterThreadAttr(Core::Loader::SymbolsResolver* sym) {
|
||||
// Posix
|
||||
LIB_FUNCTION("wtkt-teR1so", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_attr_init);
|
||||
|
@ -280,6 +331,8 @@ void RegisterThreadAttr(Core::Loader::SymbolsResolver* sym) {
|
|||
ORBIS(posix_pthread_attr_setstackaddr));
|
||||
LIB_FUNCTION("El+cQ20DynU", "libkernel", 1, "libkernel", 1, 1,
|
||||
ORBIS(posix_pthread_attr_setguardsize));
|
||||
LIB_FUNCTION("8+s5BzZjxSg", "libkernel", 1, "libkernel", 1, 1,
|
||||
ORBIS(scePthreadAttrGetaffinity));
|
||||
}
|
||||
|
||||
} // namespace Libraries::Kernel
|
||||
|
|
|
@ -15,7 +15,7 @@ void __pthread_cleanup_push_imp(PthreadCleanupFunc routine, void* arg, PthreadCl
|
|||
|
||||
void PS4_SYSV_ABI posix_pthread_cleanup_push(PthreadCleanupFunc routine, void* arg) {
|
||||
Pthread* curthread = g_curthread;
|
||||
PthreadCleanup* newbuf = (PthreadCleanup*)malloc(sizeof(PthreadCleanup));
|
||||
PthreadCleanup* newbuf = new PthreadCleanup{};
|
||||
if (newbuf == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ void PS4_SYSV_ABI posix_pthread_cleanup_pop(int execute) {
|
|||
old->routine(old->routine_arg);
|
||||
}
|
||||
if (old->onheap) {
|
||||
free(old);
|
||||
delete old;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#pragma clang optimize off
|
||||
#include <cstring>
|
||||
#include "common/assert.h"
|
||||
#include "core/libraries/error_codes.h"
|
||||
#include "core/libraries/kernel/libkernel.h"
|
||||
#include "core/libraries/kernel/threads/threads.h"
|
||||
|
@ -14,33 +15,29 @@ static std::mutex CondStaticLock;
|
|||
#define THR_COND_INITIALIZER ((PthreadCond*)NULL)
|
||||
#define THR_COND_DESTROYED ((PthreadCond*)1)
|
||||
|
||||
enum class ClockId : u32 {
|
||||
Realtime = 0,
|
||||
Virtual = 1,
|
||||
Prof = 2,
|
||||
Monotonic = 4,
|
||||
Uptime = 5,
|
||||
UptimePrecise = 7,
|
||||
UptimeFast = 8,
|
||||
RealtimePrecise = 9,
|
||||
RealtimeFast = 10,
|
||||
MonotonicPrecise = 11,
|
||||
MonotonicFast = 12,
|
||||
Second = 13,
|
||||
ThreadCputimeID = 14,
|
||||
static constexpr PthreadCondAttr PhreadCondattrDefault = {
|
||||
.c_pshared = 0,
|
||||
.c_clockid = ClockId::Realtime,
|
||||
};
|
||||
|
||||
static constexpr PthreadCondAttr PhreadCondattrDefault = {.c_pshared = PTHREAD_PROCESS_PRIVATE,
|
||||
.c_clockid = CLOCK_REALTIME};
|
||||
static int CondInit(PthreadCondT* cond, const PthreadCondAttrT* cond_attr, const char* name) {
|
||||
auto* cvp = (PthreadCond*)malloc(sizeof(PthreadCond));
|
||||
std::memset(cvp, 0, sizeof(PthreadCond));
|
||||
std::construct_at(cvp);
|
||||
|
||||
static int CondInit(PthreadCondT* cond, const PthreadCondAttrT* cond_attr) {
|
||||
PthreadCond* cvp = (PthreadCond*)calloc(1, sizeof(PthreadCond));
|
||||
if (cvp == nullptr) {
|
||||
return POSIX_ENOMEM;
|
||||
}
|
||||
std::construct_at(cvp);
|
||||
|
||||
if (name) {
|
||||
cvp->name = name;
|
||||
} else {
|
||||
static int CondId = 0;
|
||||
cvp->name = fmt::format("Cond{}", CondId++);
|
||||
}
|
||||
|
||||
if (cond_attr == nullptr || *cond_attr == nullptr) {
|
||||
cvp->clock_id = CLOCK_REALTIME;
|
||||
cvp->clock_id = ClockId::Realtime;
|
||||
} else {
|
||||
// if ((*cond_attr)->c_pshared) {
|
||||
// cvp->flags |= USYNC_PROCESS_SHARED;
|
||||
|
@ -53,8 +50,9 @@ static int CondInit(PthreadCondT* cond, const PthreadCondAttrT* cond_attr) {
|
|||
|
||||
static int InitStatic(Pthread* thread, PthreadCondT* cond) {
|
||||
std::scoped_lock lk{CondStaticLock};
|
||||
if (*cond == NULL)
|
||||
return CondInit(cond, NULL);
|
||||
if (*cond == nullptr) {
|
||||
return CondInit(cond, nullptr, nullptr);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -73,7 +71,13 @@ static int InitStatic(Pthread* thread, PthreadCondT* cond) {
|
|||
|
||||
int PS4_SYSV_ABI posix_pthread_cond_init(PthreadCondT* cond, const PthreadCondAttrT* cond_attr) {
|
||||
*cond = nullptr;
|
||||
return CondInit(cond, cond_attr);
|
||||
return CondInit(cond, cond_attr, nullptr);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI scePthreadCondInit(PthreadCondT* cond, const PthreadCondAttrT* cond_attr,
|
||||
const char* name) {
|
||||
*cond = nullptr;
|
||||
return CondInit(cond, cond_attr, name);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_cond_destroy(PthreadCondT* cond) {
|
||||
|
@ -86,33 +90,168 @@ int PS4_SYSV_ABI posix_pthread_cond_destroy(PthreadCondT* cond) {
|
|||
}
|
||||
cvp = *cond;
|
||||
*cond = THR_COND_DESTROYED;
|
||||
std::destroy_at(cvp);
|
||||
free(cvp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PthreadCond::Wait(PthreadMutexT* mutex, const OrbisKernelTimespec* abstime) {
|
||||
Pthread* curthread = g_curthread;
|
||||
PthreadMutex* mp = *mutex;
|
||||
static std::mutex sc_lock;
|
||||
static std::unordered_map<void*, SleepQueue*> sc_table;
|
||||
|
||||
if (int error = mp->IsOwned(curthread); error != 0) {
|
||||
void _sleepq_lock(void* wchan) {
|
||||
sc_lock.lock();
|
||||
}
|
||||
|
||||
void _sleepq_unlock(void* wchan) {
|
||||
sc_lock.unlock();
|
||||
}
|
||||
|
||||
SleepQueue* _sleepq_lookup(void* wchan) {
|
||||
const auto it = sc_table.find(wchan);
|
||||
if (it != sc_table.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void _sleepq_add(void* wchan, Pthread* td) {
|
||||
SleepQueue* sq = _sleepq_lookup(wchan);
|
||||
if (sq != NULL) {
|
||||
sq->sq_freeq.push_front(td->sleepqueue);
|
||||
} else {
|
||||
sc_table.emplace(wchan, td->sleepqueue);
|
||||
td->sleepqueue->sq_wchan = wchan;
|
||||
}
|
||||
td->sleepqueue = nullptr;
|
||||
td->wchan = wchan;
|
||||
sq->sq_blocked.push_front(td);
|
||||
}
|
||||
|
||||
bool _sleepq_remove(SleepQueue* sq, Pthread* td) {
|
||||
std::erase(sq->sq_blocked, td);
|
||||
if (sq->sq_blocked.empty()) {
|
||||
sc_table.erase(td->wchan);
|
||||
td->sleepqueue = sq;
|
||||
td->wchan = nullptr;
|
||||
return false;
|
||||
} else {
|
||||
td->sleepqueue = sq->sq_freeq.front();
|
||||
sq->sq_freeq.pop_front();
|
||||
td->wchan = nullptr;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void _sleepq_drop(SleepQueue* sq, void (*cb)(Pthread*, void* arg), void* arg) {
|
||||
if (sq->sq_blocked.empty()) {
|
||||
return;
|
||||
}
|
||||
Pthread* td = sq->sq_blocked.front();
|
||||
sc_table.erase(td->wchan);
|
||||
std::erase(sq->sq_blocked, td);
|
||||
|
||||
cb(td, arg);
|
||||
td->sleepqueue = sq;
|
||||
td->wchan = nullptr;
|
||||
|
||||
auto sq2 = sq->sq_freeq.begin();
|
||||
for (Pthread* td : sq->sq_blocked) {
|
||||
cb(td, arg);
|
||||
td->sleepqueue = *sq2;
|
||||
td->wchan = NULL;
|
||||
sq2++;
|
||||
}
|
||||
|
||||
sq->sq_blocked.clear();
|
||||
sq->sq_freeq.clear();
|
||||
}
|
||||
|
||||
/*static int cond_wait_user(PthreadCond *cvp, PthreadMutex* mp,
|
||||
const OrbisKernelTimespec *abstime, int cancel) {
|
||||
Pthread* curthread = g_curthread;
|
||||
int recurse;
|
||||
int error;
|
||||
|
||||
ASSERT_MSG(curthread->wchan == nullptr, "Thread was already on queue");
|
||||
//if (cancel)
|
||||
//_thr_testcancel(curthread);
|
||||
|
||||
_sleepq_lock(cvp);
|
||||
cvp->has_user_waiters = 1;
|
||||
curthread->will_sleep = 1;
|
||||
_mutex_cv_unlock(mp, &recurse);
|
||||
curthread->mutex_obj = mp;
|
||||
_sleepq_add(cvp, curthread);
|
||||
for(;;) {
|
||||
_thr_clear_wake(curthread);
|
||||
_sleepq_unlock(cvp);
|
||||
|
||||
if (cancel) {
|
||||
//_thr_cancel_enter2(curthread, 0);
|
||||
error = _thr_sleep(curthread, cvp->__clock_id, abstime);
|
||||
//_thr_cancel_leave(curthread, 0);
|
||||
} else {
|
||||
error = _thr_sleep(curthread, cvp->__clock_id, abstime);
|
||||
}
|
||||
|
||||
_sleepq_lock(cvp);
|
||||
if (curthread->wchan == nullptr) {
|
||||
error = 0;
|
||||
break;
|
||||
} else if (cancel && curthread->ShouldCancel()) {
|
||||
SleepQueue* sq = _sleepq_lookup(cvp);
|
||||
cvp->has_user_waiters = _sleepq_remove(sq, curthread);
|
||||
_sleepq_unlock(cvp);
|
||||
curthread->mutex_obj = NULL;
|
||||
_mutex_cv_lock(mp, recurse);
|
||||
if (!THR_IN_CRITICAL(curthread))
|
||||
_pthread_exit(PTHREAD_CANCELED);
|
||||
else
|
||||
return (0);
|
||||
} else if (error == POSIX_ETIMEDOUT) {
|
||||
SleepQueue* sq = _sleepq_lookup(cvp);
|
||||
cvp->has_user_waiters = _sleepq_remove(sq, curthread);
|
||||
break;
|
||||
}
|
||||
}
|
||||
_sleepq_unlock(cvp);
|
||||
curthread->mutex_obj = NULL;
|
||||
_mutex_cv_lock(mp, recurse);
|
||||
return (error);
|
||||
}*/
|
||||
|
||||
int PthreadCond::Wait(PthreadMutexT* mutex, const OrbisKernelTimespec* abstime) {
|
||||
PthreadMutex* mp = *mutex;
|
||||
if (int error = mp->IsOwned(g_curthread); error != 0) {
|
||||
return error;
|
||||
}
|
||||
|
||||
//_thr_testcancel(curthread);
|
||||
//_thr_cancel_enter2(curthread, 0);
|
||||
if (abstime) {
|
||||
const auto status = cond.wait_until(mp->m_lock, abstime->TimePoint());
|
||||
const auto status = cond.wait_until(*mp, abstime->TimePoint());
|
||||
return status == std::cv_status::timeout ? POSIX_ETIMEDOUT : 0;
|
||||
} else {
|
||||
cond.wait(mp->m_lock);
|
||||
cond.wait(*mp);
|
||||
return 0;
|
||||
}
|
||||
//_thr_cancel_leave(curthread, 0);
|
||||
}
|
||||
|
||||
int PthreadCond::Wait(PthreadMutexT* mutex, u64 usec) {
|
||||
PthreadMutex* mp = *mutex;
|
||||
if (int error = mp->IsOwned(g_curthread); error != 0) {
|
||||
return error;
|
||||
}
|
||||
|
||||
//_thr_testcancel(curthread);
|
||||
//_thr_cancel_enter2(curthread, 0);
|
||||
const auto status = cond.wait_for(*mp, std::chrono::microseconds(usec));
|
||||
return status == std::cv_status::timeout ? POSIX_ETIMEDOUT : 0;
|
||||
//_thr_cancel_leave(curthread, 0);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_cond_wait(PthreadCondT* cond, PthreadMutexT* mutex) {
|
||||
PthreadCond* cvp;
|
||||
PthreadCond* cvp{};
|
||||
CHECK_AND_INIT_COND
|
||||
return cvp->Wait(mutex, nullptr);
|
||||
}
|
||||
|
@ -124,27 +263,34 @@ int PS4_SYSV_ABI posix_pthread_cond_timedwait(PthreadCondT* cond, PthreadMutexT*
|
|||
return POSIX_EINVAL;
|
||||
}
|
||||
|
||||
PthreadCond* cvp;
|
||||
PthreadCond* cvp{};
|
||||
CHECK_AND_INIT_COND
|
||||
return cvp->Wait(mutex, abstime);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_cond_reltimedwait_np(PthreadCondT* cond, PthreadMutexT* mutex,
|
||||
u64 usec) {
|
||||
PthreadCond* cvp{};
|
||||
CHECK_AND_INIT_COND
|
||||
return cvp->Wait(mutex, usec);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_cond_signal(PthreadCondT* cond) {
|
||||
PthreadCond* cvp;
|
||||
PthreadCond* cvp{};
|
||||
CHECK_AND_INIT_COND
|
||||
cvp->cond.notify_one();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_cond_broadcast(PthreadCondT* cond) {
|
||||
PthreadCond* cvp;
|
||||
PthreadCond* cvp{};
|
||||
CHECK_AND_INIT_COND
|
||||
cvp->cond.notify_all();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_condattr_init(PthreadCondAttrT* attr) {
|
||||
PthreadCondAttr* pattr = (PthreadCondAttr*)malloc(sizeof(PthreadCondAttr));
|
||||
PthreadCondAttr* pattr = new PthreadCondAttr{};
|
||||
if (pattr == nullptr) {
|
||||
return POSIX_ENOMEM;
|
||||
}
|
||||
|
@ -157,7 +303,7 @@ int PS4_SYSV_ABI posix_pthread_condattr_destroy(PthreadCondAttrT* attr) {
|
|||
if (attr == nullptr || *attr == nullptr) {
|
||||
return POSIX_EINVAL;
|
||||
}
|
||||
free(*attr);
|
||||
delete *attr;
|
||||
*attr = nullptr;
|
||||
return 0;
|
||||
}
|
||||
|
@ -178,7 +324,7 @@ int PS4_SYSV_ABI posix_pthread_condattr_setclock(PthreadCondAttrT* attr, ClockId
|
|||
clock_id != ClockId::Prof && clock_id != ClockId::Monotonic) {
|
||||
return POSIX_EINVAL;
|
||||
}
|
||||
(*attr)->c_clockid = static_cast<int>(clock_id);
|
||||
(*attr)->c_clockid = clock_id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -214,7 +360,7 @@ void RegisterCond(Core::Loader::SymbolsResolver* sym) {
|
|||
LIB_FUNCTION("mkx2fVhNMsg", "libkernel", 1, "libkernel", 1, 1, posix_pthread_cond_broadcast);
|
||||
|
||||
// Orbis
|
||||
LIB_FUNCTION("2Tb92quprl0", "libkernel", 1, "libkernel", 1, 1, ORBIS(posix_pthread_cond_init));
|
||||
LIB_FUNCTION("2Tb92quprl0", "libkernel", 1, "libkernel", 1, 1, ORBIS(scePthreadCondInit));
|
||||
LIB_FUNCTION("m5-2bsNfv7s", "libkernel", 1, "libkernel", 1, 1,
|
||||
ORBIS(posix_pthread_condattr_init));
|
||||
LIB_FUNCTION("JGgj7Uvrl+A", "libkernel", 1, "libkernel", 1, 1,
|
||||
|
@ -225,7 +371,7 @@ void RegisterCond(Core::Loader::SymbolsResolver* sym) {
|
|||
LIB_FUNCTION("kDh-NfxgMtE", "libkernel", 1, "libkernel", 1, 1,
|
||||
ORBIS(posix_pthread_cond_signal));
|
||||
LIB_FUNCTION("BmMjYxmew1w", "libkernel", 1, "libkernel", 1, 1,
|
||||
ORBIS(posix_pthread_cond_timedwait));
|
||||
ORBIS(posix_pthread_cond_reltimedwait_np));
|
||||
LIB_FUNCTION("g+PZd2hiacg", "libkernel", 1, "libkernel", 1, 1,
|
||||
ORBIS(posix_pthread_cond_destroy));
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma clang optimize off
|
||||
#include "common/assert.h"
|
||||
#include "common/thread.h"
|
||||
#include "core/debug_state.h"
|
||||
|
@ -25,6 +25,13 @@ extern PthreadAttr PthreadAttrDefault;
|
|||
|
||||
void _thread_cleanupspecific();
|
||||
|
||||
using ThreadDtor = void (*)();
|
||||
static ThreadDtor* ThreadDtors{};
|
||||
|
||||
void PS4_SYSV_ABI _sceKernelSetThreadDtors(ThreadDtor* dtor) {
|
||||
ThreadDtors = dtor;
|
||||
}
|
||||
|
||||
static void ExitThread() {
|
||||
Pthread* curthread = g_curthread;
|
||||
|
||||
|
@ -37,7 +44,7 @@ static void ExitThread() {
|
|||
auto* thread_state = ThrState::Instance();
|
||||
ASSERT(thread_state->active_threads.fetch_sub(1) != 1);
|
||||
|
||||
curthread->lock->lock();
|
||||
curthread->lock.lock();
|
||||
curthread->state = PthreadState::Dead;
|
||||
ASSERT(False(curthread->flags & ThreadFlags::NeedSuspend));
|
||||
|
||||
|
@ -46,7 +53,7 @@ static void ExitThread() {
|
|||
* reference count to allow it to be garbage collected.
|
||||
*/
|
||||
curthread->refcount--;
|
||||
thread_state->TryCollect(curthread, curthread); /* thread lock released */
|
||||
thread_state->TryCollect(curthread); /* thread lock released */
|
||||
|
||||
/*
|
||||
* Kernel will do wakeup at the address, so joiner thread
|
||||
|
@ -80,10 +87,12 @@ void PS4_SYSV_ABI posix_pthread_exit(void* status) {
|
|||
curthread->cleanup.pop_front();
|
||||
old->routine(old->routine_arg);
|
||||
if (old->onheap) {
|
||||
free(old);
|
||||
delete old;
|
||||
}
|
||||
}
|
||||
|
||||
/*if (ThreadDtors && *ThreadDtors) {
|
||||
(*ThreadDtors)();
|
||||
}*/
|
||||
ExitThread();
|
||||
}
|
||||
|
||||
|
@ -111,16 +120,16 @@ static int JoinThread(PthreadT pthread, void** thread_return, const OrbisKernelT
|
|||
ret = POSIX_ENOTSUP;
|
||||
}
|
||||
if (ret) {
|
||||
pthread->lock->unlock();
|
||||
pthread->lock.unlock();
|
||||
return ret;
|
||||
}
|
||||
/* Set the running thread to be the joiner: */
|
||||
pthread->joiner = curthread;
|
||||
pthread->lock->unlock();
|
||||
pthread->lock.unlock();
|
||||
|
||||
const auto backout_join = [](void* arg) {
|
||||
Pthread* pthread = (Pthread*)arg;
|
||||
std::scoped_lock lk{*pthread->lock};
|
||||
std::scoped_lock lk{pthread->lock};
|
||||
pthread->joiner = nullptr;
|
||||
};
|
||||
|
||||
|
@ -145,10 +154,10 @@ static int JoinThread(PthreadT pthread, void** thread_return, const OrbisKernelT
|
|||
}
|
||||
|
||||
void* tmp = pthread->ret;
|
||||
pthread->lock->lock();
|
||||
pthread->lock.lock();
|
||||
pthread->flags |= ThreadFlags::Detached;
|
||||
pthread->joiner = nullptr;
|
||||
thread_state->TryCollect(curthread, pthread); /* thread lock released */
|
||||
thread_state->TryCollect(pthread); /* thread lock released */
|
||||
if (thread_return != nullptr) {
|
||||
*thread_return = tmp;
|
||||
}
|
||||
|
@ -182,13 +191,13 @@ int PS4_SYSV_ABI posix_pthread_detach(PthreadT pthread) {
|
|||
|
||||
/* Check if the thread is already detached or has a joiner. */
|
||||
if (True(pthread->flags & ThreadFlags::Detached) || (pthread->joiner != NULL)) {
|
||||
pthread->lock->unlock();
|
||||
pthread->lock.unlock();
|
||||
return POSIX_EINVAL;
|
||||
}
|
||||
|
||||
/* Flag the thread as detached. */
|
||||
pthread->flags |= ThreadFlags::Detached;
|
||||
thread_state->TryCollect(g_curthread, pthread); /* thread lock released */
|
||||
thread_state->TryCollect(pthread); /* thread lock released */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -231,7 +240,8 @@ int PS4_SYSV_ABI posix_pthread_create_name_np(PthreadT* thread, const PthreadAtt
|
|||
new_thread->attr.sched_policy = curthread->attr.sched_policy;
|
||||
}
|
||||
|
||||
new_thread->tid = TidTerminated;
|
||||
static int TidCounter = 1;
|
||||
new_thread->tid = ++TidCounter;
|
||||
|
||||
if (thread_state->CreateStack(&new_thread->attr) != 0) {
|
||||
/* Insufficient memory to create a stack: */
|
||||
|
@ -248,9 +258,11 @@ int PS4_SYSV_ABI posix_pthread_create_name_np(PthreadT* thread, const PthreadAtt
|
|||
new_thread->arg = arg;
|
||||
new_thread->cancel_enable = 1;
|
||||
new_thread->cancel_async = 0;
|
||||
static std::atomic<int> counter = 0;
|
||||
new_thread->name = fmt::format("NoName{}", counter++);
|
||||
|
||||
auto* memory = Core::Memory::Instance();
|
||||
if (name && (std::string_view{name} == "GAME_MainThread" || memory->IsValidAddress(name))) {
|
||||
if (name && memory->IsValidAddress(name)) {
|
||||
new_thread->name = name;
|
||||
}
|
||||
|
||||
|
@ -269,10 +281,11 @@ int PS4_SYSV_ABI posix_pthread_create_name_np(PthreadT* thread, const PthreadAtt
|
|||
(*thread) = new_thread;
|
||||
|
||||
/* Create thread */
|
||||
pthread_t pthr;
|
||||
pthread_attr_t pattr;
|
||||
pthread_attr_init(&pattr);
|
||||
pthread_attr_setstack(&pattr, new_thread->attr.stackaddr_attr, new_thread->attr.stacksize_attr);
|
||||
pthread_t pthr;
|
||||
// pthread_attr_setstack(&pattr, new_thread->attr.stackaddr_attr,
|
||||
// new_thread->attr.stacksize_attr);
|
||||
int ret = pthread_create(&pthr, &pattr, (PthreadEntryFunc)RunThread, new_thread);
|
||||
ASSERT_MSG(ret == 0, "Failed to create thread with error {}", ret);
|
||||
if (ret) {
|
||||
|
@ -281,6 +294,11 @@ int PS4_SYSV_ABI posix_pthread_create_name_np(PthreadT* thread, const PthreadAtt
|
|||
return ret;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_create(PthreadT* thread, const PthreadAttrT* attr,
|
||||
PthreadEntryFunc start_routine, void* arg) {
|
||||
return posix_pthread_create_name_np(thread, attr, start_routine, arg, nullptr);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_getthreadid_np() {
|
||||
return g_curthread->tid;
|
||||
}
|
||||
|
@ -361,7 +379,51 @@ int PS4_SYSV_ABI posix_pthread_rename_np(PthreadT thread, const char* name) {
|
|||
return SCE_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_getschedparam(PthreadT pthread, SchedPolicy* policy,
|
||||
SchedParam* param) {
|
||||
if (policy == nullptr || param == nullptr) {
|
||||
return POSIX_EINVAL;
|
||||
}
|
||||
|
||||
if (pthread == g_curthread) {
|
||||
/*
|
||||
* Avoid searching the thread list when it is the current
|
||||
* thread.
|
||||
*/
|
||||
std::scoped_lock lk{g_curthread->lock};
|
||||
*policy = g_curthread->attr.sched_policy;
|
||||
param->sched_priority = g_curthread->attr.prio;
|
||||
return 0;
|
||||
}
|
||||
auto* thread_state = ThrState::Instance();
|
||||
/* Find the thread in the list of active threads. */
|
||||
if (int ret = thread_state->RefAdd(pthread, /*include dead*/ 0); ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
pthread->lock.lock();
|
||||
*policy = pthread->attr.sched_policy;
|
||||
param->sched_priority = pthread->attr.prio;
|
||||
pthread->lock.unlock();
|
||||
thread_state->RefDelete(pthread);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI scePthreadGetprio(PthreadT thread, int* priority) {
|
||||
SchedParam param;
|
||||
SchedPolicy policy;
|
||||
|
||||
posix_pthread_getschedparam(thread, &policy, ¶m);
|
||||
*priority = param.sched_priority;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sceNpWebApiTerminate() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RegisterThread(Core::Loader::SymbolsResolver* sym) {
|
||||
LIB_FUNCTION("asz3TtIqGF8", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1, sceNpWebApiTerminate);
|
||||
|
||||
// Posix
|
||||
LIB_FUNCTION("Z4QosVuAsA0", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_once);
|
||||
LIB_FUNCTION("7Xl257M4VNI", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_equal);
|
||||
|
@ -370,9 +432,13 @@ void RegisterThread(Core::Loader::SymbolsResolver* sym) {
|
|||
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);
|
||||
LIB_FUNCTION("h9CcP3J0oVM", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_join);
|
||||
LIB_FUNCTION("OxhIB8LB-PQ", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_create);
|
||||
LIB_FUNCTION("Jmi+9w9u0E4", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_create_name_np);
|
||||
|
||||
// Posix-Kernel
|
||||
LIB_FUNCTION("EotR8a3ASf4", "libkernel", 1, "libkernel", 1, 1, posix_pthread_self);
|
||||
LIB_FUNCTION("OxhIB8LB-PQ", "libkernel", 1, "libkernel", 1, 1, posix_pthread_create);
|
||||
|
||||
// Orbis
|
||||
LIB_FUNCTION("14bOACANTBo", "libkernel", 1, "libkernel", 1, 1, ORBIS(posix_pthread_once));
|
||||
|
@ -380,10 +446,14 @@ void RegisterThread(Core::Loader::SymbolsResolver* sym) {
|
|||
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("onNY9Byn-W8", "libkernel", 1, "libkernel", 1, 1, ORBIS(posix_pthread_join));
|
||||
LIB_FUNCTION("3kg7rT0NQIs", "libkernel", 1, "libkernel", 1, 1, posix_pthread_exit);
|
||||
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);
|
||||
LIB_FUNCTION("EI-5-jlq2dE", "libkernel", 1, "libkernel", 1, 1, posix_pthread_getthreadid_np);
|
||||
LIB_FUNCTION("1tKyG7RlMJo", "libkernel", 1, "libkernel", 1, 1, scePthreadGetprio);
|
||||
LIB_FUNCTION("rNhWz+lvOMU", "libkernel", 1, "libkernel", 1, 1, _sceKernelSetThreadDtors);
|
||||
}
|
||||
|
||||
} // namespace Libraries::Kernel
|
||||
|
|
|
@ -25,7 +25,7 @@ Core::Tcb* TcbCtor(Pthread* thread, int initial) {
|
|||
// Initialize allocated memory and allocate DTV table.
|
||||
const u32 num_dtvs = linker->MaxTlsIndex();
|
||||
const auto static_tls_size = linker->StaticTlsSize();
|
||||
auto* dtv_table = new Core::DtvEntry[num_dtvs + 2];
|
||||
auto* dtv_table = new Core::DtvEntry[num_dtvs + 2]{};
|
||||
|
||||
// Initialize thread control block
|
||||
u8* addr = reinterpret_cast<u8*>(addr_out);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma clang optimize off
|
||||
#include "common/assert.h"
|
||||
#include "common/scope_exit.h"
|
||||
#include "common/types.h"
|
||||
|
@ -17,6 +17,7 @@ static std::mutex MutxStaticLock;
|
|||
#define THR_MUTEX_INITIALIZER ((PthreadMutex*)NULL)
|
||||
#define THR_ADAPTIVE_MUTEX_INITIALIZER ((PthreadMutex*)1)
|
||||
#define THR_MUTEX_DESTROYED ((PthreadMutex*)2)
|
||||
#define THR_MUTEX_RELTIME (const OrbisKernelTimespec*)-1
|
||||
|
||||
#define CPU_SPINWAIT __asm__ volatile("pause")
|
||||
|
||||
|
@ -39,8 +40,7 @@ static constexpr PthreadMutexAttr PthreadMutexattrAdaptiveDefault = {
|
|||
|
||||
using CallocFun = void* (*)(size_t, size_t);
|
||||
|
||||
static int MutexInit(PthreadMutexT* mutex, const PthreadMutexAttr* mutex_attr,
|
||||
CallocFun calloc_cb) {
|
||||
static int MutexInit(PthreadMutexT* mutex, const PthreadMutexAttr* mutex_attr, const char* name) {
|
||||
const PthreadMutexAttr* attr;
|
||||
if (mutex_attr == NULL) {
|
||||
attr = &PthreadMutexattrDefault;
|
||||
|
@ -53,14 +53,22 @@ static int MutexInit(PthreadMutexT* mutex, const PthreadMutexAttr* mutex_attr,
|
|||
return POSIX_EINVAL;
|
||||
}
|
||||
}
|
||||
PthreadMutex* pmutex = (PthreadMutex*)calloc(1, sizeof(PthreadMutex));
|
||||
auto* pmutex = (PthreadMutex*)malloc(sizeof(PthreadMutex));
|
||||
std::memset(pmutex, 0, sizeof(PthreadMutex));
|
||||
std::construct_at(pmutex);
|
||||
if (pmutex == nullptr) {
|
||||
return POSIX_ENOMEM;
|
||||
}
|
||||
|
||||
std::construct_at(pmutex);
|
||||
if (name) {
|
||||
pmutex->name = name;
|
||||
} else {
|
||||
static int MutexId = 0;
|
||||
pmutex->name = fmt::format("Mutex{}", MutexId++);
|
||||
}
|
||||
|
||||
pmutex->m_flags = PthreadMutexFlags(attr->m_type);
|
||||
pmutex->m_owner = NULL;
|
||||
pmutex->m_owner = nullptr;
|
||||
pmutex->m_count = 0;
|
||||
pmutex->m_spinloops = 0;
|
||||
pmutex->m_yieldloops = 0;
|
||||
|
@ -78,16 +86,21 @@ static int InitStatic(Pthread* thread, PthreadMutexT* mutex) {
|
|||
std::scoped_lock lk{MutxStaticLock};
|
||||
|
||||
if (*mutex == THR_MUTEX_INITIALIZER) {
|
||||
return MutexInit(mutex, &PthreadMutexattrDefault, calloc);
|
||||
return MutexInit(mutex, &PthreadMutexattrDefault, nullptr);
|
||||
} else if (*mutex == THR_ADAPTIVE_MUTEX_INITIALIZER) {
|
||||
return MutexInit(mutex, &PthreadMutexattrAdaptiveDefault, calloc);
|
||||
return MutexInit(mutex, &PthreadMutexattrAdaptiveDefault, nullptr);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_mutex_init(PthreadMutexT* mutex,
|
||||
const PthreadMutexAttrT* mutex_attr) {
|
||||
return MutexInit(mutex, mutex_attr ? *mutex_attr : nullptr, calloc);
|
||||
return MutexInit(mutex, mutex_attr ? *mutex_attr : nullptr, nullptr);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI scePthreadMutexInit(PthreadMutexT* mutex, const PthreadMutexAttrT* mutex_attr,
|
||||
const char* name) {
|
||||
return MutexInit(mutex, mutex_attr ? *mutex_attr : nullptr, name);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_mutex_destroy(PthreadMutexT* mutex) {
|
||||
|
@ -102,7 +115,6 @@ int PS4_SYSV_ABI posix_pthread_mutex_destroy(PthreadMutexT* mutex) {
|
|||
return POSIX_EBUSY;
|
||||
}
|
||||
*mutex = THR_MUTEX_DESTROYED;
|
||||
std::destroy_at(m);
|
||||
free(m);
|
||||
return 0;
|
||||
}
|
||||
|
@ -125,11 +137,12 @@ int PthreadMutex::SelfTryLock() {
|
|||
}
|
||||
}
|
||||
|
||||
int PthreadMutex::SelfLock(const OrbisKernelTimespec* abstime) {
|
||||
switch (Type()) {
|
||||
case PthreadMutexType::ErrorCheck:
|
||||
case PthreadMutexType::AdaptiveNp: {
|
||||
if (abstime) {
|
||||
int PthreadMutex::SelfLock(const OrbisKernelTimespec* abstime, u64 usec) {
|
||||
const auto DoSleep = [&] {
|
||||
if (abstime == THR_MUTEX_RELTIME) {
|
||||
std::this_thread::sleep_for(std::chrono::microseconds(usec));
|
||||
return POSIX_ETIMEDOUT;
|
||||
} else {
|
||||
if (abstime->tv_sec < 0 || abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) {
|
||||
return POSIX_EINVAL;
|
||||
} else {
|
||||
|
@ -137,10 +150,18 @@ int PthreadMutex::SelfLock(const OrbisKernelTimespec* abstime) {
|
|||
return POSIX_ETIMEDOUT;
|
||||
}
|
||||
}
|
||||
};
|
||||
switch (Type()) {
|
||||
case PthreadMutexType::ErrorCheck:
|
||||
case PthreadMutexType::AdaptiveNp: {
|
||||
if (abstime) {
|
||||
return DoSleep();
|
||||
}
|
||||
/*
|
||||
* POSIX specifies that mutexes should return
|
||||
* EDEADLK if a recursive lock is detected.
|
||||
*/
|
||||
UNREACHABLE_MSG("Mutex deadlock occured");
|
||||
return POSIX_EDEADLK;
|
||||
}
|
||||
case PthreadMutexType::Normal: {
|
||||
|
@ -149,12 +170,7 @@ int PthreadMutex::SelfLock(const OrbisKernelTimespec* abstime) {
|
|||
* deadlock on attempts to get a lock you already own.
|
||||
*/
|
||||
if (abstime) {
|
||||
if (abstime->tv_sec < 0 || abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) {
|
||||
return POSIX_EINVAL;
|
||||
} else {
|
||||
std::this_thread::sleep_until(abstime->TimePoint());
|
||||
return POSIX_ETIMEDOUT;
|
||||
}
|
||||
return DoSleep();
|
||||
}
|
||||
UNREACHABLE_MSG("Mutex deadlock occured");
|
||||
return 0;
|
||||
|
@ -172,10 +188,10 @@ int PthreadMutex::SelfLock(const OrbisKernelTimespec* abstime) {
|
|||
}
|
||||
}
|
||||
|
||||
int PthreadMutex::Lock(const OrbisKernelTimespec* abstime) {
|
||||
int PthreadMutex::Lock(const OrbisKernelTimespec* abstime, u64 usec) {
|
||||
Pthread* curthread = g_curthread;
|
||||
if (m_owner == curthread) {
|
||||
return SelfLock(abstime);
|
||||
return SelfLock(abstime, usec);
|
||||
}
|
||||
|
||||
int ret = 0;
|
||||
|
@ -211,10 +227,15 @@ int PthreadMutex::Lock(const OrbisKernelTimespec* abstime) {
|
|||
|
||||
if (abstime == nullptr) {
|
||||
m_lock.lock();
|
||||
} else if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) [[unlikely]] {
|
||||
} else if (abstime != THR_MUTEX_RELTIME &&
|
||||
(abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)) [[unlikely]] {
|
||||
ret = POSIX_EINVAL;
|
||||
} else {
|
||||
ret = m_lock.try_lock_until(abstime->TimePoint()) ? 0 : POSIX_ETIMEDOUT;
|
||||
if (THR_MUTEX_RELTIME) {
|
||||
ret = m_lock.try_lock_for(std::chrono::microseconds(usec)) ? 0 : POSIX_ETIMEDOUT;
|
||||
} else {
|
||||
ret = m_lock.try_lock_until(abstime->TimePoint()) ? 0 : POSIX_ETIMEDOUT;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -244,9 +265,15 @@ int PS4_SYSV_ABI posix_pthread_mutex_lock(PthreadMutexT* mutex) {
|
|||
int PS4_SYSV_ABI posix_pthread_mutex_timedlock(PthreadMutexT* mutex,
|
||||
const OrbisKernelTimespec* abstime) {
|
||||
CHECK_AND_INIT_MUTEX
|
||||
UNREACHABLE();
|
||||
return (*mutex)->Lock(abstime);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_mutex_reltimedlock_np(PthreadMutexT* mutex, u64 usec) {
|
||||
CHECK_AND_INIT_MUTEX
|
||||
return (*mutex)->Lock(THR_MUTEX_RELTIME, usec);
|
||||
}
|
||||
|
||||
int PthreadMutex::Unlock() {
|
||||
Pthread* curthread = g_curthread;
|
||||
/*
|
||||
|
@ -320,7 +347,7 @@ bool PthreadMutex::IsOwned(Pthread* curthread) const {
|
|||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_mutexattr_init(PthreadMutexAttrT* attr) {
|
||||
PthreadMutexAttrT pattr = (PthreadMutexAttrT)malloc(sizeof(PthreadMutexAttr));
|
||||
PthreadMutexAttrT pattr = new PthreadMutexAttr{};
|
||||
if (pattr == nullptr) {
|
||||
return POSIX_ENOMEM;
|
||||
}
|
||||
|
@ -367,7 +394,7 @@ int PS4_SYSV_ABI posix_pthread_mutexattr_destroy(PthreadMutexAttrT* attr) {
|
|||
if (attr == nullptr || *attr == nullptr) {
|
||||
return POSIX_EINVAL;
|
||||
}
|
||||
free(*attr);
|
||||
delete *attr;
|
||||
*attr = nullptr;
|
||||
return 0;
|
||||
}
|
||||
|
@ -412,7 +439,7 @@ void RegisterMutex(Core::Loader::SymbolsResolver* sym) {
|
|||
LIB_FUNCTION("2Z+PpY6CaJg", "libkernel", 1, "libkernel", 1, 1, posix_pthread_mutex_unlock);
|
||||
|
||||
// Orbis
|
||||
LIB_FUNCTION("cmo1RIYva9o", "libkernel", 1, "libkernel", 1, 1, ORBIS(posix_pthread_mutex_init));
|
||||
LIB_FUNCTION("cmo1RIYva9o", "libkernel", 1, "libkernel", 1, 1, ORBIS(scePthreadMutexInit));
|
||||
LIB_FUNCTION("2Of0f+3mhhE", "libkernel", 1, "libkernel", 1, 1,
|
||||
ORBIS(posix_pthread_mutex_destroy));
|
||||
LIB_FUNCTION("F8bUHwAG284", "libkernel", 1, "libkernel", 1, 1,
|
||||
|
@ -429,7 +456,7 @@ void RegisterMutex(Core::Loader::SymbolsResolver* sym) {
|
|||
LIB_FUNCTION("upoVrzMHFeE", "libkernel", 1, "libkernel", 1, 1,
|
||||
ORBIS(posix_pthread_mutex_trylock));
|
||||
LIB_FUNCTION("IafI2PxcPnQ", "libkernel", 1, "libkernel", 1, 1,
|
||||
ORBIS(posix_pthread_mutex_timedlock));
|
||||
ORBIS(posix_pthread_mutex_reltimedlock_np));
|
||||
LIB_FUNCTION("qH1gXoq71RY", "libkernel", 1, "libkernel", 1, 1, ORBIS(posix_pthread_mutex_init));
|
||||
LIB_FUNCTION("n2MMpvU8igI", "libkernel", 1, "libkernel", 1, 1,
|
||||
ORBIS(posix_pthread_mutexattr_init));
|
||||
|
|
|
@ -27,11 +27,10 @@ static std::mutex RwlockStaticLock;
|
|||
}
|
||||
|
||||
static int RwlockInit(PthreadRwlockT* rwlock, const PthreadRwlockAttrT* attr) {
|
||||
PthreadRwlock* prwlock = (PthreadRwlock*)calloc(1, sizeof(PthreadRwlock));
|
||||
PthreadRwlock* prwlock = new PthreadRwlock{};
|
||||
if (prwlock == nullptr) {
|
||||
return POSIX_ENOMEM;
|
||||
}
|
||||
std::construct_at(prwlock);
|
||||
*rwlock = prwlock;
|
||||
return 0;
|
||||
}
|
||||
|
@ -45,8 +44,7 @@ int PS4_SYSV_ABI posix_pthread_rwlock_destroy(PthreadRwlockT* rwlock) {
|
|||
return POSIX_EINVAL;
|
||||
}
|
||||
*rwlock = THR_RWLOCK_DESTROYED;
|
||||
std::destroy_at(prwlock);
|
||||
free(prwlock);
|
||||
delete prwlock;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -121,21 +119,21 @@ int PthreadRwlock::Wrlock(const OrbisKernelTimespec* abstime) {
|
|||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_rwlock_rdlock(PthreadRwlockT* rwlock) {
|
||||
PthreadRwlockT prwlock;
|
||||
PthreadRwlockT prwlock{};
|
||||
CHECK_AND_INIT_RWLOCK
|
||||
return prwlock->Rdlock(nullptr);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_rwlock_timedrdlock(PthreadRwlockT* rwlock,
|
||||
const OrbisKernelTimespec* abstime) {
|
||||
PthreadRwlockT prwlock;
|
||||
PthreadRwlockT prwlock{};
|
||||
CHECK_AND_INIT_RWLOCK
|
||||
return prwlock->Rdlock(abstime);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_rwlock_tryrdlock(PthreadRwlockT* rwlock) {
|
||||
Pthread* curthread = g_curthread;
|
||||
PthreadRwlockT prwlock;
|
||||
PthreadRwlockT prwlock{};
|
||||
CHECK_AND_INIT_RWLOCK
|
||||
|
||||
if (!prwlock->lock.try_lock_shared()) {
|
||||
|
@ -148,7 +146,7 @@ int PS4_SYSV_ABI posix_pthread_rwlock_tryrdlock(PthreadRwlockT* rwlock) {
|
|||
|
||||
int PS4_SYSV_ABI posix_pthread_rwlock_trywrlock(PthreadRwlockT* rwlock) {
|
||||
Pthread* curthread = g_curthread;
|
||||
PthreadRwlockT prwlock;
|
||||
PthreadRwlockT prwlock{};
|
||||
CHECK_AND_INIT_RWLOCK
|
||||
|
||||
if (!prwlock->lock.try_lock()) {
|
||||
|
@ -159,14 +157,14 @@ int PS4_SYSV_ABI posix_pthread_rwlock_trywrlock(PthreadRwlockT* rwlock) {
|
|||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_rwlock_wrlock(PthreadRwlockT* rwlock) {
|
||||
PthreadRwlockT prwlock;
|
||||
PthreadRwlockT prwlock{};
|
||||
CHECK_AND_INIT_RWLOCK
|
||||
return prwlock->Wrlock(nullptr);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_rwlock_timedwrlock(PthreadRwlockT* rwlock,
|
||||
const OrbisKernelTimespec* abstime) {
|
||||
PthreadRwlockT prwlock;
|
||||
PthreadRwlockT prwlock{};
|
||||
CHECK_AND_INIT_RWLOCK
|
||||
return prwlock->Wrlock(abstime);
|
||||
}
|
||||
|
@ -213,7 +211,7 @@ int PS4_SYSV_ABI posix_pthread_rwlockattr_destroy(PthreadRwlockAttrT* rwlockattr
|
|||
return POSIX_EINVAL;
|
||||
}
|
||||
|
||||
free(prwlockattr);
|
||||
delete prwlockattr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -228,7 +226,7 @@ int PS4_SYSV_ABI posix_pthread_rwlockattr_init(PthreadRwlockAttrT* rwlockattr) {
|
|||
return POSIX_EINVAL;
|
||||
}
|
||||
|
||||
PthreadRwlockAttrT prwlockattr = (PthreadRwlockAttrT)malloc(sizeof(PthreadRwlockAttr));
|
||||
PthreadRwlockAttrT prwlockattr = new PthreadRwlockAttr{};
|
||||
if (prwlockattr == nullptr) {
|
||||
return POSIX_ENOMEM;
|
||||
}
|
||||
|
|
|
@ -27,9 +27,7 @@ public:
|
|||
OrbisSem(s32 init_count, s32 max_count, std::string_view name, bool is_fifo)
|
||||
: name{name}, token_count{init_count}, max_count{max_count}, init_count{init_count},
|
||||
is_fifo{is_fifo} {}
|
||||
~OrbisSem() {
|
||||
ASSERT(wait_list.empty());
|
||||
}
|
||||
~OrbisSem() = default;
|
||||
|
||||
int Wait(bool can_block, s32 need_count, u32* timeout) {
|
||||
std::unique_lock lk{mutex};
|
||||
|
@ -93,6 +91,15 @@ public:
|
|||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
void Delete() {
|
||||
std::scoped_lock lk{mutex};
|
||||
for (auto* waiter : wait_list) {
|
||||
waiter->was_deleted = true;
|
||||
waiter->cv.notify_one();
|
||||
}
|
||||
wait_list.clear();
|
||||
}
|
||||
|
||||
public:
|
||||
struct WaitingThread {
|
||||
std::condition_variable cv;
|
||||
|
@ -219,7 +226,7 @@ int PS4_SYSV_ABI sceKernelDeleteSema(OrbisKernelSema sem) {
|
|||
if (!sem) {
|
||||
return SCE_KERNEL_ERROR_ESRCH;
|
||||
}
|
||||
delete sem;
|
||||
sem->Delete();
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -90,7 +90,7 @@ void _thread_cleanupspecific() {
|
|||
}
|
||||
}
|
||||
}
|
||||
free(curthread->specific);
|
||||
delete[] curthread->specific;
|
||||
curthread->specific = nullptr;
|
||||
ASSERT(curthread->specific_data_count == 0);
|
||||
}
|
||||
|
@ -100,8 +100,7 @@ int PS4_SYSV_ABI posix_pthread_setspecific(PthreadKeyT key, const void* value) {
|
|||
Pthread* pthread = g_curthread;
|
||||
|
||||
if (!pthread->specific) {
|
||||
pthread->specific =
|
||||
(PthreadSpecificElem*)calloc(1, sizeof(PthreadSpecificElem) * PthreadKeysMax);
|
||||
pthread->specific = new PthreadSpecificElem[PthreadKeysMax];
|
||||
if (!pthread->specific) {
|
||||
return POSIX_ENOMEM;
|
||||
}
|
||||
|
|
|
@ -2,19 +2,33 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <boost/container/small_vector.hpp>
|
||||
#include "common/alignment.h"
|
||||
#include "common/scope_exit.h"
|
||||
#include "core/libraries/error_codes.h"
|
||||
#include "core/libraries/kernel/threads/thread_state.h"
|
||||
#include "core/libraries/kernel/threads/threads.h"
|
||||
#include "core/memory.h"
|
||||
#include "core/tls.h"
|
||||
|
||||
namespace Libraries::Kernel {
|
||||
|
||||
Pthread* g_curthread{};
|
||||
thread_local Pthread* g_curthread{};
|
||||
|
||||
Core::Tcb* TcbCtor(Pthread* thread, int initial);
|
||||
void TcbDtor(Core::Tcb* oldtls);
|
||||
|
||||
ThreadState::ThreadState() {
|
||||
// Reserve memory for maximum amount of threads allowed.
|
||||
auto* memory = Core::Memory::Instance();
|
||||
static constexpr u32 ThrHeapSize = Common::AlignUp(sizeof(Pthread) * MaxThreads, 16_KB);
|
||||
void* heap_addr{};
|
||||
const int ret = memory->MapMemory(&heap_addr, Core::SYSTEM_RESERVED_MIN, ThrHeapSize,
|
||||
Core::MemoryProt::CpuReadWrite, Core::MemoryMapFlags::NoFlags,
|
||||
Core::VMAType::File, "ThrHeap");
|
||||
ASSERT_MSG(ret == 0, "Unable to allocate thread heap memory {}", ret);
|
||||
thread_heap.Initialize(heap_addr, ThrHeapSize);
|
||||
}
|
||||
|
||||
void ThreadState::Collect(Pthread* curthread) {
|
||||
boost::container::small_vector<Pthread*, 8> work_list;
|
||||
{
|
||||
|
@ -35,18 +49,18 @@ void ThreadState::Collect(Pthread* curthread) {
|
|||
}
|
||||
}
|
||||
|
||||
void ThreadState::TryCollect(Pthread* curthread, Pthread* thread) {
|
||||
void ThreadState::TryCollect(Pthread* thread) {
|
||||
SCOPE_EXIT {
|
||||
thread->lock->unlock();
|
||||
thread->lock.unlock();
|
||||
};
|
||||
if (!thread->ShouldCollect()) {
|
||||
return;
|
||||
}
|
||||
|
||||
thread->refcount++;
|
||||
thread->lock->unlock();
|
||||
thread->lock.unlock();
|
||||
std::scoped_lock lk{thread_list_lock};
|
||||
thread->lock->lock();
|
||||
thread->lock.lock();
|
||||
thread->refcount--;
|
||||
if (thread->ShouldCollect()) {
|
||||
threads.erase(thread);
|
||||
|
@ -71,9 +85,7 @@ Pthread* ThreadState::Alloc(Pthread* curthread) {
|
|||
return nullptr;
|
||||
}
|
||||
total_threads.fetch_add(1);
|
||||
thread = (Pthread*)malloc(sizeof(Pthread));
|
||||
std::construct_at(thread);
|
||||
thread->lock = std::make_unique<std::mutex>();
|
||||
thread = thread_heap.Allocate();
|
||||
if (thread == nullptr) {
|
||||
total_threads.fetch_sub(1);
|
||||
return nullptr;
|
||||
|
@ -87,12 +99,13 @@ Pthread* ThreadState::Alloc(Pthread* curthread) {
|
|||
tcb = TcbCtor(thread, 1 /* initial tls */);
|
||||
}
|
||||
if (tcb != nullptr) {
|
||||
memset(thread, 0, sizeof(Pthread));
|
||||
std::construct_at(thread);
|
||||
thread->tcb = tcb;
|
||||
// thread->sleepqueue = _sleepq_alloc();
|
||||
// thread->wake_addr = _thr_alloc_wake_addr();
|
||||
} else {
|
||||
std::destroy_at(thread);
|
||||
free(thread);
|
||||
thread_heap.Free(thread);
|
||||
total_threads.fetch_sub(1);
|
||||
thread = nullptr;
|
||||
}
|
||||
|
@ -106,12 +119,12 @@ void ThreadState::Free(Pthread* curthread, Pthread* thread) {
|
|||
} else {
|
||||
TcbDtor(thread->tcb);
|
||||
}
|
||||
thread->tcb = NULL;
|
||||
thread->tcb = nullptr;
|
||||
std::destroy_at(thread);
|
||||
if (free_threads.size() >= MaxCachedThreads) {
|
||||
//_sleepq_free(thread->sleepqueue);
|
||||
//_thr_release_wake_addr(thread->wake_addr);
|
||||
std::destroy_at(thread);
|
||||
free(thread);
|
||||
thread_heap.Free(thread);
|
||||
total_threads.fetch_sub(1);
|
||||
} else {
|
||||
std::scoped_lock lk{free_thread_lock};
|
||||
|
@ -128,12 +141,33 @@ int ThreadState::FindThread(Pthread* thread, bool include_dead) {
|
|||
if (it == threads.end()) {
|
||||
return POSIX_ESRCH;
|
||||
}
|
||||
thread->lock->lock();
|
||||
thread->lock.lock();
|
||||
if (!include_dead && thread->state == PthreadState::Dead) {
|
||||
thread->lock->unlock();
|
||||
thread->lock.unlock();
|
||||
return POSIX_ESRCH;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ThreadState::RefAdd(Pthread* thread, bool include_dead) {
|
||||
if (thread == nullptr) {
|
||||
/* Invalid thread: */
|
||||
return POSIX_EINVAL;
|
||||
}
|
||||
|
||||
if (int ret = FindThread(thread, include_dead); ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
thread->refcount++;
|
||||
thread->lock.unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ThreadState::RefDelete(Pthread* thread) {
|
||||
thread->lock.lock();
|
||||
thread->refcount--;
|
||||
TryCollect(thread);
|
||||
}
|
||||
|
||||
} // namespace Libraries::Kernel
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <set>
|
||||
#include <stack>
|
||||
#include "common/singleton.h"
|
||||
#include "common/slab_heap.h"
|
||||
#include "common/types.h"
|
||||
|
||||
namespace Libraries::Kernel {
|
||||
|
@ -27,13 +28,15 @@ struct ThreadState {
|
|||
static constexpr size_t MaxThreads = 100000;
|
||||
static constexpr size_t MaxCachedThreads = 100;
|
||||
|
||||
explicit ThreadState();
|
||||
|
||||
bool GcNeeded() const noexcept {
|
||||
return gc_list.size() >= GcThreshold;
|
||||
}
|
||||
|
||||
void Collect(Pthread* curthread);
|
||||
|
||||
void TryCollect(Pthread* curthread, Pthread* thread);
|
||||
void TryCollect(Pthread* thread);
|
||||
|
||||
Pthread* Alloc(Pthread* curthread);
|
||||
|
||||
|
@ -41,6 +44,10 @@ struct ThreadState {
|
|||
|
||||
int FindThread(Pthread* thread, bool include_dead);
|
||||
|
||||
int RefAdd(Pthread* thread, bool include_dead);
|
||||
|
||||
void RefDelete(Pthread* thread);
|
||||
|
||||
int CreateStack(PthreadAttr* attr);
|
||||
|
||||
void FreeStack(PthreadAttr* attr);
|
||||
|
@ -61,6 +68,7 @@ struct ThreadState {
|
|||
active_threads.fetch_sub(1);
|
||||
}
|
||||
|
||||
Common::SlabHeap<Pthread> thread_heap;
|
||||
std::set<Pthread*> threads;
|
||||
std::list<Pthread*> free_threads;
|
||||
std::list<Pthread*> gc_list;
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <condition_variable>
|
||||
#include <deque>
|
||||
#include <forward_list>
|
||||
#include <mutex>
|
||||
#include <shared_mutex>
|
||||
|
@ -53,16 +54,25 @@ struct PthreadMutex : public ListBaseHook {
|
|||
int m_spinloops;
|
||||
int m_yieldloops;
|
||||
PthreadMutexProt m_protocol;
|
||||
std::string name;
|
||||
|
||||
PthreadMutexType Type() const noexcept {
|
||||
return static_cast<PthreadMutexType>(m_flags & PthreadMutexFlags::TypeMask);
|
||||
}
|
||||
|
||||
void lock() {
|
||||
Lock(nullptr);
|
||||
}
|
||||
|
||||
void unlock() {
|
||||
Unlock();
|
||||
}
|
||||
|
||||
int SelfTryLock();
|
||||
int SelfLock(const OrbisKernelTimespec* abstime);
|
||||
int SelfLock(const OrbisKernelTimespec* abstime, u64 usec);
|
||||
|
||||
int TryLock();
|
||||
int Lock(const OrbisKernelTimespec* abstime);
|
||||
int Lock(const OrbisKernelTimespec* abstime, u64 usec = 0);
|
||||
|
||||
int Unlock();
|
||||
|
||||
|
@ -83,20 +93,38 @@ enum class PthreadCondFlags : u32 {
|
|||
Busy = 4,
|
||||
};
|
||||
|
||||
enum class ClockId : u32 {
|
||||
Realtime = 0,
|
||||
Virtual = 1,
|
||||
Prof = 2,
|
||||
Monotonic = 4,
|
||||
Uptime = 5,
|
||||
UptimePrecise = 7,
|
||||
UptimeFast = 8,
|
||||
RealtimePrecise = 9,
|
||||
RealtimeFast = 10,
|
||||
MonotonicPrecise = 11,
|
||||
MonotonicFast = 12,
|
||||
Second = 13,
|
||||
ThreadCputimeID = 14,
|
||||
};
|
||||
|
||||
struct PthreadCond {
|
||||
std::condition_variable_any cond;
|
||||
u32 has_user_waiters;
|
||||
u32 has_kern_waiters;
|
||||
u32 flags;
|
||||
u32 clock_id;
|
||||
ClockId clock_id;
|
||||
std::string name;
|
||||
|
||||
int Wait(PthreadMutexT* mutex, const OrbisKernelTimespec* abstime);
|
||||
int Wait(PthreadMutexT* mutex, u64 usec);
|
||||
};
|
||||
using PthreadCondT = PthreadCond*;
|
||||
|
||||
struct PthreadCondAttr {
|
||||
int c_pshared;
|
||||
int c_clockid;
|
||||
ClockId c_clockid;
|
||||
};
|
||||
using PthreadCondAttrT = PthreadCondAttr*;
|
||||
|
||||
|
@ -122,6 +150,10 @@ enum class SchedPolicy : u32 {
|
|||
RoundRobin = 3,
|
||||
};
|
||||
|
||||
struct Cpuset {
|
||||
u64 bits;
|
||||
};
|
||||
|
||||
struct PthreadAttr {
|
||||
SchedPolicy sched_policy;
|
||||
int sched_inherit;
|
||||
|
@ -132,6 +164,7 @@ struct PthreadAttr {
|
|||
size_t stacksize_attr;
|
||||
size_t guardsize_attr;
|
||||
size_t cpusetsize;
|
||||
Cpuset* cpuset;
|
||||
};
|
||||
using PthreadAttrT = PthreadAttr*;
|
||||
|
||||
|
@ -198,17 +231,36 @@ using PthreadEntryFunc = void* (*)(void*);
|
|||
|
||||
constexpr u32 TidTerminated = 1;
|
||||
|
||||
struct WakeAddr {
|
||||
WakeAddr* link;
|
||||
u32 value;
|
||||
char pad[12];
|
||||
};
|
||||
|
||||
struct SleepQueue {
|
||||
std::list<Pthread*> sq_blocked;
|
||||
std::forward_list<SleepQueue*> sq_freeq;
|
||||
std::list<SleepQueue*> sq_hash;
|
||||
std::forward_list<SleepQueue*> sq_flink;
|
||||
void* sq_wchan;
|
||||
int sq_type;
|
||||
};
|
||||
|
||||
struct SchedParam {
|
||||
int sched_priority;
|
||||
};
|
||||
|
||||
struct Pthread {
|
||||
static constexpr u32 ThrMagic = 0xd09ba115U;
|
||||
|
||||
std::atomic<long> tid;
|
||||
std::unique_ptr<std::mutex> lock;
|
||||
std::mutex lock;
|
||||
u32 cycle;
|
||||
int locklevel;
|
||||
int critical_count;
|
||||
int sigblock;
|
||||
int refcount;
|
||||
void PS4_SYSV_ABI* (*start_routine)(void*);
|
||||
void* PS4_SYSV_ABI (*start_routine)(void*);
|
||||
void* arg;
|
||||
PthreadAttr attr;
|
||||
bool cancel_enable;
|
||||
|
@ -226,8 +278,8 @@ struct Pthread {
|
|||
Pthread* joiner;
|
||||
ThreadFlags flags;
|
||||
ThreadListFlags tlflags;
|
||||
boost::intrusive::list<PthreadMutex> mutexq;
|
||||
boost::intrusive::list<PthreadMutex> pp_mutexq;
|
||||
std::list<PthreadMutex> mutexq;
|
||||
std::list<PthreadMutex> pp_mutexq;
|
||||
void* ret;
|
||||
PthreadSpecificElem* specific;
|
||||
int specific_data_count;
|
||||
|
@ -240,6 +292,12 @@ struct Pthread {
|
|||
int report_events;
|
||||
int event_mask;
|
||||
std::string name;
|
||||
WakeAddr* wake_addr;
|
||||
SleepQueue* sleepqueue;
|
||||
void* wchan;
|
||||
PthreadMutex* mutex_obj;
|
||||
bool will_sleep;
|
||||
bool has_user_waiters;
|
||||
|
||||
bool InCritical() const noexcept {
|
||||
return locklevel > 0 || critical_count > 0;
|
||||
|
@ -255,17 +313,17 @@ struct Pthread {
|
|||
|
||||
void Enqueue(PthreadMutex* mutex) {
|
||||
mutex->m_owner = this;
|
||||
mutexq.push_back(*mutex);
|
||||
// mutexq.push_back(*mutex);
|
||||
}
|
||||
|
||||
void Dequeue(PthreadMutex* mutex) {
|
||||
mutex->m_owner = nullptr;
|
||||
mutexq.erase(decltype(mutexq)::s_iterator_to(*mutex));
|
||||
// mutexq.erase(decltype(mutexq)::s_iterator_to(*mutex));
|
||||
}
|
||||
};
|
||||
using PthreadT = Pthread*;
|
||||
|
||||
extern Pthread* g_curthread;
|
||||
extern thread_local Pthread* g_curthread;
|
||||
|
||||
void RegisterMutex(Core::Loader::SymbolsResolver* sym);
|
||||
void RegisterCond(Core::Loader::SymbolsResolver* sym);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma clang optimize off
|
||||
#include <thread>
|
||||
|
||||
#include "common/assert.h"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma clang optimize off
|
||||
#include "common/assert.h"
|
||||
#include "common/config.h"
|
||||
#include "common/logging/log.h"
|
||||
|
@ -95,7 +95,7 @@ s32 PS4_SYSV_ABI sceVideoOutRegisterBuffers(s32 handle, s32 startIndex, void* co
|
|||
LOG_ERROR(Lib_VideoOut, "Addresses are null");
|
||||
return ORBIS_VIDEO_OUT_ERROR_INVALID_ADDRESS;
|
||||
}
|
||||
|
||||
VAddr ret_addr = (VAddr)__builtin_return_address(0);
|
||||
auto* port = driver->GetPort(handle);
|
||||
if (!port || !port->is_open) {
|
||||
LOG_ERROR(Lib_VideoOut, "Invalid handle = {}", handle);
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#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/libraries/kernel/memory_management.h"
|
||||
|
@ -24,10 +25,8 @@ static PS4_SYSV_ABI void ProgramExitFunc() {
|
|||
}
|
||||
|
||||
#ifdef ARCH_X86_64
|
||||
static PS4_SYSV_ABI void* RunMainEntry [[noreturn]] (void* arg) {
|
||||
EntryParams* params = (EntryParams*)arg;
|
||||
static PS4_SYSV_ABI void* RunMainEntry [[noreturn]] (EntryParams* params) {
|
||||
// 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
|
||||
|
||||
|
@ -43,7 +42,7 @@ static PS4_SYSV_ABI void* RunMainEntry [[noreturn]] (void* arg) {
|
|||
"jmp *%0\n" // can't use call here, as that would mangle the prepared stack.
|
||||
// there's no coming back
|
||||
:
|
||||
: "r"(params->entry_addr), "r"(params), "r"(params->exit_func)
|
||||
: "r"(params->entry_addr), "r"(params), "r"(ProgramExitFunc)
|
||||
: "rax", "rsi", "rdi");
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
@ -82,14 +81,17 @@ void Linker::Execute() {
|
|||
}
|
||||
}
|
||||
|
||||
// Start main module.
|
||||
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");
|
||||
main_thread.Run([this, module](std::stop_token) {
|
||||
Common::SetCurrentThreadName("GAME_MainThread");
|
||||
LoadSharedLibraries();
|
||||
|
||||
// Start main module.
|
||||
EntryParams params{};
|
||||
params.argc = 1;
|
||||
params.argv[0] = "eboot.bin";
|
||||
params.entry_addr = module->GetEntryAddress();
|
||||
RunMainEntry(¶ms);
|
||||
});
|
||||
}
|
||||
|
||||
s32 Linker::LoadModule(const std::filesystem::path& elf_name, bool is_dynamic) {
|
||||
|
@ -122,10 +124,9 @@ Module* Linker::FindByAddress(VAddr address) {
|
|||
}
|
||||
|
||||
void Linker::Relocate(Module* module) {
|
||||
module->ForEachRelocation([&](elf_relocation* rel, u32 i, bool isJmpRel) {
|
||||
const u32 bit_idx =
|
||||
(isJmpRel ? module->dynamic_info.relocation_table_size / sizeof(elf_relocation) : 0) +
|
||||
i;
|
||||
module->ForEachRelocation([&](elf_relocation* rel, u32 i, bool is_jmp_rel) {
|
||||
const u32 num_relocs = module->dynamic_info.relocation_table_size / sizeof(elf_relocation);
|
||||
const u32 bit_idx = (is_jmp_rel ? num_relocs : 0) + i;
|
||||
if (module->TestRelaBit(bit_idx)) {
|
||||
return;
|
||||
}
|
||||
|
@ -133,7 +134,7 @@ void Linker::Relocate(Module* module) {
|
|||
auto symbol = rel->GetSymbol();
|
||||
auto addend = rel->rel_addend;
|
||||
auto* symbol_table = module->dynamic_info.symbol_table;
|
||||
auto* namesTlb = module->dynamic_info.str_table;
|
||||
auto* names_tlb = module->dynamic_info.str_table;
|
||||
|
||||
const VAddr rel_base_virtual_addr = module->GetBaseAddress();
|
||||
const VAddr rel_virtual_addr = rel_base_virtual_addr + rel->rel_offset;
|
||||
|
@ -189,7 +190,7 @@ void Linker::Relocate(Module* module) {
|
|||
break;
|
||||
case STB_GLOBAL:
|
||||
case STB_WEAK: {
|
||||
rel_name = namesTlb + sym.st_name;
|
||||
rel_name = names_tlb + sym.st_name;
|
||||
if (Resolve(rel_name, rel_sym_type, module, &symrec)) {
|
||||
// Only set the rela bit if the symbol was actually resolved and not stubbed.
|
||||
module->SetRelaBit(bit_idx);
|
||||
|
@ -198,7 +199,7 @@ void Linker::Relocate(Module* module) {
|
|||
break;
|
||||
}
|
||||
default:
|
||||
ASSERT_MSG(0, "unknown bind type {}", sym_bind);
|
||||
UNREACHABLE_MSG("Unknown bind type {}", sym_bind);
|
||||
}
|
||||
rel_is_resolved = (symbol_virtual_addr != 0);
|
||||
rel_value = (rel_is_resolved ? symbol_virtual_addr + addend : 0);
|
||||
|
@ -212,7 +213,7 @@ void Linker::Relocate(Module* module) {
|
|||
if (rel_is_resolved) {
|
||||
VirtualMemory::memory_patch(rel_virtual_addr, rel_value);
|
||||
} else {
|
||||
LOG_INFO(Core_Linker, "function not patched! {}", rel_name);
|
||||
LOG_INFO(Core_Linker, "Function not patched! {}", rel_name);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -295,12 +296,13 @@ void* Linker::TlsGetAddr(u64 module_index, u64 offset) {
|
|||
}
|
||||
|
||||
u8* addr = dtv_table[module_index + 1].pointer;
|
||||
Module* module = m_modules[module_index - 1].get();
|
||||
// LOG_INFO(Core_Linker, "Got DTV addr {} from module index {} with name {}",
|
||||
// fmt::ptr(addr), module_index, module->file.filename().string());
|
||||
if (!addr) {
|
||||
// Module was just loaded by above code. Allocate TLS block for it.
|
||||
Module* module = m_modules[module_index - 1].get();
|
||||
const u32 init_image_size = module->tls.init_image_size;
|
||||
u8* dest =
|
||||
reinterpret_cast<u8*>(ExecuteGuest(heap_api->heap_malloc, module->tls.image_size));
|
||||
u8* dest = reinterpret_cast<u8*>(heap_api->heap_malloc(module->tls.image_size));
|
||||
const u8* src = reinterpret_cast<const u8*>(module->tls.image_virtual_addr);
|
||||
std::memcpy(dest, src, init_image_size);
|
||||
std::memset(dest + init_image_size, 0, module->tls.image_size - init_image_size);
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <algorithm>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
#include "core/libraries/kernel/thread_management.h"
|
||||
#include "core/module.h"
|
||||
|
||||
namespace Core {
|
||||
|
@ -49,8 +50,6 @@ struct EntryParams {
|
|||
u32 padding;
|
||||
const char* argv[3];
|
||||
VAddr entry_addr;
|
||||
ExitFunc exit_func;
|
||||
Linker* linker;
|
||||
};
|
||||
|
||||
struct HeapAPI {
|
||||
|
@ -141,6 +140,7 @@ private:
|
|||
const Module* FindExportedModule(const ModuleInfo& m, const LibraryInfo& l);
|
||||
|
||||
MemoryManager* memory;
|
||||
Libraries::Kernel::Thread main_thread;
|
||||
std::mutex mutex;
|
||||
u32 dtv_generation_counter{1};
|
||||
size_t static_tls_size{};
|
||||
|
|
|
@ -166,9 +166,7 @@ void Module::LoadModuleToMemory(u32& max_tls_index) {
|
|||
tls.align = elf_pheader[i].p_align;
|
||||
tls.image_virtual_addr = elf_pheader[i].p_vaddr + base_virtual_addr;
|
||||
tls.image_size = GetAlignedSize(elf_pheader[i]);
|
||||
if (tls.image_size != 0) {
|
||||
tls.modid = ++max_tls_index;
|
||||
}
|
||||
tls.modid = ++max_tls_index;
|
||||
LOG_INFO(Core_Linker, "TLS virtual address = {:#x}", tls.image_virtual_addr);
|
||||
LOG_INFO(Core_Linker, "TLS image size = {}", tls.image_size);
|
||||
break;
|
||||
|
|
|
@ -68,10 +68,9 @@ void Translator::V_READFIRSTLANE_B32(const GcnInst& inst) {
|
|||
}
|
||||
|
||||
void Translator::V_READLANE_B32(const GcnInst& inst) {
|
||||
const IR::ScalarReg dst{inst.dst[0].code};
|
||||
const IR::U32 value{GetSrc(inst.src[0])};
|
||||
const IR::U32 lane{GetSrc(inst.src[1])};
|
||||
ir.SetScalarReg(dst, ir.ReadLane(value, lane));
|
||||
SetDst(inst.dst[0], ir.ReadLane(value, lane));
|
||||
}
|
||||
|
||||
void Translator::V_WRITELANE_B32(const GcnInst& inst) {
|
||||
|
@ -155,7 +154,7 @@ void Translator::DS_SWIZZLE_B32(const GcnInst& inst) {
|
|||
const u8 offset0 = inst.control.ds.offset0;
|
||||
const u8 offset1 = inst.control.ds.offset1;
|
||||
const IR::U32 src{GetSrc(inst.src[1])};
|
||||
ASSERT(offset1 & 0x80);
|
||||
// ASSERT(offset1 & 0x80);
|
||||
const IR::U32 lane_id = ir.LaneId();
|
||||
const IR::U32 id_in_group = ir.BitwiseAnd(lane_id, ir.Imm32(0b11));
|
||||
const IR::U32 base = ir.ShiftLeftLogical(id_in_group, ir.Imm32(1));
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma clang optimize off
|
||||
// Include the vulkan platform specific header
|
||||
#if defined(ANDROID)
|
||||
#define VK_USE_PLATFORM_ANDROID_KHR
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue