mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2026-10-11 21:49:59 +00:00
kernel: Implement private pthread barriers (#5308)
This commit is contained in:
@@ -326,6 +326,7 @@ set(KERNEL_LIB src/core/libraries/kernel/coredump/coredump.cpp
|
||||
src/core/libraries/kernel/sync/mutex.cpp
|
||||
src/core/libraries/kernel/sync/mutex.h
|
||||
src/core/libraries/kernel/sync/semaphore.h
|
||||
src/core/libraries/kernel/threads/barrier.cpp
|
||||
src/core/libraries/kernel/threads/condvar.cpp
|
||||
src/core/libraries/kernel/threads/event_flag.cpp
|
||||
src/core/libraries/kernel/threads/exception.cpp
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
namespace Libraries::Kernel {
|
||||
|
||||
void RegisterThreads(Core::Loader::SymbolsResolver* sym) {
|
||||
RegisterBarrier(sym);
|
||||
RegisterMutex(sym);
|
||||
RegisterCond(sym);
|
||||
RegisterRwlock(sym);
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <new>
|
||||
|
||||
#include "core/libraries/kernel/kernel.h"
|
||||
#include "core/libraries/kernel/posix_error.h"
|
||||
#include "core/libraries/kernel/threads/pthread.h"
|
||||
#include "core/libraries/libs.h"
|
||||
|
||||
namespace Libraries::Kernel {
|
||||
|
||||
static s32 BarrierInit(PthreadBarrierT* barrier, u32 count) {
|
||||
if (barrier == nullptr || count == 0) {
|
||||
return POSIX_EINVAL;
|
||||
}
|
||||
auto* value = new (std::nothrow) PthreadBarrier{};
|
||||
if (value == nullptr) {
|
||||
return POSIX_ENOMEM;
|
||||
}
|
||||
try {
|
||||
value->state = std::make_shared<PthreadBarrier::State>();
|
||||
} catch (const std::bad_alloc&) {
|
||||
delete value;
|
||||
return POSIX_ENOMEM;
|
||||
}
|
||||
value->state->count = count;
|
||||
*barrier = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI posix_pthread_barrier_init(PthreadBarrierT* barrier, const PthreadBarrierAttrT*,
|
||||
u32 count) {
|
||||
return BarrierInit(barrier, count);
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI scePthreadBarrierInit(PthreadBarrierT* barrier, const PthreadBarrierAttrT*,
|
||||
u32 count, const char*) {
|
||||
return BarrierInit(barrier, count);
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI posix_pthread_barrier_wait(PthreadBarrierT* barrier) {
|
||||
if (barrier == nullptr || *barrier == nullptr) {
|
||||
return POSIX_EINVAL;
|
||||
}
|
||||
const auto value = (*barrier)->state;
|
||||
std::unique_lock lock{value->mutex};
|
||||
if (++value->arrived == value->count) {
|
||||
value->arrived = 0;
|
||||
++value->generation;
|
||||
value->cv.notify_all();
|
||||
return PthreadBarrierSerialThread;
|
||||
}
|
||||
const u64 generation = value->generation;
|
||||
value->cv.wait(lock, [&] { return value->generation != generation; });
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI scePthreadBarrierWait(PthreadBarrierT* barrier) {
|
||||
const s32 ret = posix_pthread_barrier_wait(barrier);
|
||||
return ret > 0 ? ErrnoToSceKernelError(ret) : ret;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI posix_pthread_barrier_destroy(PthreadBarrierT* barrier) {
|
||||
if (barrier == nullptr || *barrier == nullptr) {
|
||||
return POSIX_EINVAL;
|
||||
}
|
||||
auto* handle = *barrier;
|
||||
const auto value = handle->state;
|
||||
std::unique_lock lock{value->mutex};
|
||||
if (value->arrived != 0) {
|
||||
return POSIX_EBUSY;
|
||||
}
|
||||
*barrier = nullptr;
|
||||
delete handle;
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI posix_pthread_barrierattr_init(PthreadBarrierAttrT* attr) {
|
||||
if (attr == nullptr) {
|
||||
return POSIX_EINVAL;
|
||||
}
|
||||
auto* value = new (std::nothrow) PthreadBarrierAttr{};
|
||||
if (value == nullptr) {
|
||||
return POSIX_ENOMEM;
|
||||
}
|
||||
*attr = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI posix_pthread_barrierattr_destroy(PthreadBarrierAttrT* attr) {
|
||||
if (attr == nullptr || *attr == nullptr) {
|
||||
return POSIX_EINVAL;
|
||||
}
|
||||
delete *attr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI posix_pthread_barrierattr_getpshared(const PthreadBarrierAttrT* attr,
|
||||
s32* pshared) {
|
||||
if (attr == nullptr || *attr == nullptr) {
|
||||
return POSIX_EINVAL;
|
||||
}
|
||||
*pshared = (*attr)->pshared;
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI posix_pthread_barrierattr_setpshared(PthreadBarrierAttrT* attr, s32 pshared) {
|
||||
if (attr == nullptr || *attr == nullptr || pshared != 0) {
|
||||
return POSIX_EINVAL;
|
||||
}
|
||||
(*attr)->pshared = pshared;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RegisterBarrier(Core::Loader::SymbolsResolver* sym) {
|
||||
LIB_FUNCTION("ZsXLFtd2jqQ", "libkernel", 1, "libkernel", posix_pthread_barrier_init);
|
||||
LIB_FUNCTION("CawZgCYqXWk", "libkernel", 1, "libkernel", posix_pthread_barrier_wait);
|
||||
LIB_FUNCTION("+Pqub9HZCPo", "libkernel", 1, "libkernel", posix_pthread_barrier_destroy);
|
||||
LIB_FUNCTION("4nqCnLJSvck", "libkernel", 1, "libkernel", posix_pthread_barrierattr_init);
|
||||
LIB_FUNCTION("AsCQCYTbe80", "libkernel", 1, "libkernel", posix_pthread_barrierattr_destroy);
|
||||
LIB_FUNCTION("a5JZMyjFV68", "libkernel", 1, "libkernel", posix_pthread_barrierattr_getpshared);
|
||||
LIB_FUNCTION("jqrGJJxFhmU", "libkernel", 1, "libkernel", posix_pthread_barrierattr_setpshared);
|
||||
|
||||
LIB_FUNCTION("ZsXLFtd2jqQ", "libScePosix", 1, "libkernel", posix_pthread_barrier_init);
|
||||
LIB_FUNCTION("CawZgCYqXWk", "libScePosix", 1, "libkernel", posix_pthread_barrier_wait);
|
||||
LIB_FUNCTION("+Pqub9HZCPo", "libScePosix", 1, "libkernel", posix_pthread_barrier_destroy);
|
||||
LIB_FUNCTION("4nqCnLJSvck", "libScePosix", 1, "libkernel", posix_pthread_barrierattr_init);
|
||||
LIB_FUNCTION("AsCQCYTbe80", "libScePosix", 1, "libkernel", posix_pthread_barrierattr_destroy);
|
||||
LIB_FUNCTION("a5JZMyjFV68", "libScePosix", 1, "libkernel",
|
||||
posix_pthread_barrierattr_getpshared);
|
||||
LIB_FUNCTION("jqrGJJxFhmU", "libScePosix", 1, "libkernel",
|
||||
posix_pthread_barrierattr_setpshared);
|
||||
|
||||
LIB_FUNCTION("5dgOEPsEGqw", "libkernel", 1, "libkernel", ORBIS(scePthreadBarrierInit));
|
||||
LIB_FUNCTION("t9vVyTglqHQ", "libkernel", 1, "libkernel", scePthreadBarrierWait);
|
||||
LIB_FUNCTION("HudB2Jv2MPY", "libkernel", 1, "libkernel", ORBIS(posix_pthread_barrier_destroy));
|
||||
LIB_FUNCTION("SDkV9xhINKI", "libkernel", 1, "libkernel", ORBIS(posix_pthread_barrierattr_init));
|
||||
LIB_FUNCTION("oT-j4DqJHY8", "libkernel", 1, "libkernel",
|
||||
ORBIS(posix_pthread_barrierattr_destroy));
|
||||
LIB_FUNCTION("SkutDtgqJ9g", "libkernel", 1, "libkernel",
|
||||
ORBIS(posix_pthread_barrierattr_getpshared));
|
||||
LIB_FUNCTION("NpfpcLf5PYM", "libkernel", 1, "libkernel",
|
||||
ORBIS(posix_pthread_barrierattr_setpshared));
|
||||
}
|
||||
|
||||
} // namespace Libraries::Kernel
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <condition_variable>
|
||||
#include <forward_list>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <shared_mutex>
|
||||
|
||||
@@ -28,6 +29,7 @@ class SymbolsResolver;
|
||||
namespace Libraries::Kernel {
|
||||
|
||||
constexpr int PthreadInheritSched = 4;
|
||||
constexpr s32 PthreadBarrierSerialThread = -1;
|
||||
|
||||
constexpr int ORBIS_KERNEL_PRIO_FIFO_DEFAULT = 700;
|
||||
constexpr int ORBIS_KERNEL_PRIO_FIFO_LOWEST = 256;
|
||||
@@ -41,6 +43,23 @@ constexpr int ORBIS_KERNEL_PRIO_RR_HIGHEST = 767;
|
||||
|
||||
struct Pthread;
|
||||
|
||||
struct PthreadBarrier {
|
||||
struct State {
|
||||
std::mutex mutex;
|
||||
std::condition_variable cv;
|
||||
u32 count;
|
||||
u32 arrived{};
|
||||
u64 generation{};
|
||||
};
|
||||
std::shared_ptr<State> state;
|
||||
};
|
||||
using PthreadBarrierT = PthreadBarrier*;
|
||||
|
||||
struct PthreadBarrierAttr {
|
||||
s32 pshared;
|
||||
};
|
||||
using PthreadBarrierAttrT = PthreadBarrierAttr*;
|
||||
|
||||
enum class PthreadMutexFlags : u32 {
|
||||
TypeMask = 0xff,
|
||||
Private = 0x100,
|
||||
@@ -441,6 +460,7 @@ bool IsPthreadCancelSignal(int native_signal) noexcept;
|
||||
#endif
|
||||
void PS4_SYSV_ABI posix_pthread_exit(void* status);
|
||||
|
||||
void RegisterBarrier(Core::Loader::SymbolsResolver* sym);
|
||||
void RegisterMutex(Core::Loader::SymbolsResolver* sym);
|
||||
void RegisterCond(Core::Loader::SymbolsResolver* sym);
|
||||
void RegisterRwlock(Core::Loader::SymbolsResolver* sym);
|
||||
|
||||
Reference in New Issue
Block a user