mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-22 00:22:57 -05:00
scePthreadCreate on Linux started guest threads with std::thread, so every thread got the host default stack (RLIMIT_STACK, usually 8 MiB) whatever the title asked for. A thread that asks for more than that and uses it crashes with SIGSEGV. Once the thread ran, scePthreadAttrGet also reported the host size instead of the requested one. Create the thread with pthread_create and a stack of the requested size plus what glibc keeps at its top (static TLS, the thread control block and the start_thread frame). That reserve is measured once with a probe thread. The thread reports [top - reserve - size, top - reserve) as its stack, as Windows reports [top - size, top), and the creator waits until the range is set, as on Windows. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
77 lines
3.0 KiB
C++
77 lines
3.0 KiB
C++
#include "SceTypes.hpp"
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <cstdlib>
|
|
|
|
extern "C" {
|
|
int APS5_VABI scePthreadCreate(Pthread* thread, const PthreadAttr* attr, PthreadEntry entry, void* arg, const char* name);
|
|
int APS5_VABI scePthreadJoin(Pthread thread, void** retval);
|
|
int APS5_VABI scePthreadAttrInit(PthreadAttr* attr);
|
|
int APS5_VABI scePthreadAttrDestroy(PthreadAttr* attr);
|
|
int APS5_VABI scePthreadAttrGet(Pthread thread, PthreadAttr* attr);
|
|
int APS5_VABI scePthreadAttrSetstacksize(PthreadAttr* attr, std::size_t stackSize);
|
|
int APS5_VABI scePthreadAttrGetstack(const PthreadAttr* attr, void** stackAddress, std::size_t* stackSize);
|
|
Pthread APS5_VABI scePthreadSelf();
|
|
}
|
|
|
|
static constexpr int SCE_OK = 0;
|
|
static constexpr std::size_t FRAME_SIZE = 4096;
|
|
static constexpr std::size_t FRAME_MARGIN = 2 * FRAME_SIZE;
|
|
static constexpr std::size_t STACK_SIZES[] = {16384, 65536, 1u << 20, 16u << 20};
|
|
|
|
thread_local unsigned char threadLocalBlock[512 * 1024];
|
|
|
|
static void Require(bool value) { if (!value) std::abort(); }
|
|
|
|
static std::uintptr_t Descend(std::uintptr_t floor);
|
|
static std::uintptr_t (*volatile descend)(std::uintptr_t) = Descend;
|
|
|
|
static std::uintptr_t Descend(std::uintptr_t floor) {
|
|
volatile unsigned char frame[FRAME_SIZE];
|
|
frame[0] = 0x5a;
|
|
frame[FRAME_SIZE - 1] = 0xa5;
|
|
const auto here = reinterpret_cast<std::uintptr_t>(&frame[0]);
|
|
const auto deepest = here < floor + FRAME_MARGIN ? here : descend(floor);
|
|
Require(frame[0] == 0x5a && frame[FRAME_SIZE - 1] == 0xa5);
|
|
return deepest;
|
|
}
|
|
|
|
static void* APS5_VABI Worker(void* arg) {
|
|
const auto requested = *static_cast<const std::size_t*>(arg);
|
|
threadLocalBlock[0] = 1;
|
|
threadLocalBlock[sizeof(threadLocalBlock) - 1] = 2;
|
|
|
|
PthreadAttr attr = nullptr;
|
|
Require(scePthreadAttrInit(&attr) == SCE_OK);
|
|
Require(scePthreadAttrGet(scePthreadSelf(), &attr) == SCE_OK);
|
|
void* address = nullptr;
|
|
std::size_t size = 0;
|
|
Require(scePthreadAttrGetstack(&attr, &address, &size) == SCE_OK);
|
|
Require(scePthreadAttrDestroy(&attr) == SCE_OK);
|
|
Require(size == requested);
|
|
|
|
const auto begin = reinterpret_cast<std::uintptr_t>(address);
|
|
const auto local = reinterpret_cast<std::uintptr_t>(&size);
|
|
Require(local > begin && local < begin + size);
|
|
Require(local - begin + FRAME_SIZE >= requested);
|
|
const auto deepest = Descend(begin);
|
|
Require(deepest >= begin && deepest < begin + FRAME_MARGIN);
|
|
|
|
Require(threadLocalBlock[0] == 1 && threadLocalBlock[sizeof(threadLocalBlock) - 1] == 2);
|
|
return arg;
|
|
}
|
|
|
|
int main() {
|
|
for (auto stackSize : STACK_SIZES) {
|
|
PthreadAttr attr = nullptr;
|
|
Require(scePthreadAttrInit(&attr) == SCE_OK);
|
|
Require(scePthreadAttrSetstacksize(&attr, stackSize) == SCE_OK);
|
|
Pthread thread = nullptr;
|
|
Require(scePthreadCreate(&thread, &attr, Worker, &stackSize, nullptr) == SCE_OK);
|
|
Require(scePthreadAttrDestroy(&attr) == SCE_OK);
|
|
void* result = nullptr;
|
|
Require(scePthreadJoin(thread, &result) == SCE_OK);
|
|
Require(result == &stackSize);
|
|
}
|
|
}
|