From 09a39fac5dccf7ee68f6a24e2578740af498789b Mon Sep 17 00:00:00 2001 From: Elad <18193363+elad335@users.noreply.github.com> Date: Tue, 30 Jun 2026 09:25:47 +0300 Subject: [PATCH 1/9] SPU LLVM: Discourage memory mirrors use on LQD/STQD --- rpcs3/Emu/Cell/SPULLVMRecompiler.cpp | 71 +++++++++++++++++----------- 1 file changed, 44 insertions(+), 27 deletions(-) diff --git a/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp b/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp index 73396eb08a..b0c2c9854d 100644 --- a/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp +++ b/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp @@ -9288,6 +9288,11 @@ public: return byteswap(data); } + static constexpr u64 make_negative_LS_offset(u32 original) + { + return original | ~u64{SPU_LS_SIZE - 1}; + } + void STQX(spu_opcode_t op) { const auto a = get_vr(op.ra); @@ -9297,17 +9302,20 @@ public: { if (auto [ok, data] = get_const_vector(pair.first.value, m_pos); ok) { - data._u32[3] %= SPU_LS_SIZE; + // "sign extend" offset addend + // Discourage the use of multiple addresses to refer to the same block of memory (due to memory mirrors use) + // Which may confuse LLVM's optimization + const u64 addend = (data._u32[3] >= SPU_LS_SIZE) ? make_negative_LS_offset(data._u32[3]) : data._u32[3]; if (const u32 remainder = data._u32[3] % 0x10; remainder == 0) { - value_t addr = eval(splat(data._u32[3]) + zext(extract(pair.second, 3) & 0x3fff0)); + value_t addr = eval(splat(addend) + zext(extract(pair.second, 3) & 0x3fff0)); make_store_ls(addr, get_vr(op.rt)); return; } else { - value_t addr = eval(splat(data._u32[3] - remainder) + zext((extract(pair.second, 3) + remainder) & 0x3fff0)); + value_t addr = eval(splat(addend - remainder) + zext((extract(pair.second, 3) + remainder) & 0x3fff0)); make_store_ls(addr, get_vr(op.rt)); return; } @@ -9327,17 +9335,20 @@ public: { if (auto [ok, data] = get_const_vector(pair.first.value, m_pos); ok) { - data._u32[3] %= SPU_LS_SIZE; + // "sign extend" offset addend + // Discourage the use of multiple addresses to refer to the same block of memory + // Which may confuse LLVM's optimization + const u64 addend = (data._u32[3] >= SPU_LS_SIZE) ? make_negative_LS_offset(data._u32[3]) : data._u32[3]; if (const u32 remainder = data._u32[3] % 0x10; remainder == 0) { - value_t addr = eval(splat(data._u32[3]) + zext(extract(pair.second, 3) & 0x3fff0)); + value_t addr = eval(splat(addend) + zext(extract(pair.second, 3) & 0x3fff0)); set_vr(op.rt, make_load_ls(addr)); return; } else { - value_t addr = eval(splat(data._u32[3] - remainder) + zext((extract(pair.second, 3) + remainder) & 0x3fff0)); + value_t addr = eval(splat(addend - remainder) + zext((extract(pair.second, 3) + remainder) & 0x3fff0)); set_vr(op.rt, make_load_ls(addr)); return; } @@ -9398,18 +9409,22 @@ public: if (auto [ok, x, y] = match_expr(a, match() + match()); ok) { - if (auto [ok1, data] = get_const_vector(x.value, m_pos + 1); ok1 && data._u32[3] % 16 == 0) + for (auto pair : std::initializer_list, llvm_match_t>>{{x, y}, {y, x}}) { - value_t addr = eval(zext(extract(y, 3) & 0x3fff0) + ((get_imm(op.si10) << 4) + splat(data._u32[3] & 0x3fff0))); - make_store_ls(addr, get_vr(op.rt)); - return; - } + if (auto [ok, data] = get_const_vector(pair.first.value, m_pos); ok) + { + // "sign extend" offset addend + // Discourage the use of multiple addresses to refer to the same block of memory + // Which may confuse LLVM's optimization + const u64 addend = (data._u32[3] >= SPU_LS_SIZE) ? make_negative_LS_offset(data._u32[3]) : data._u32[3]; - if (auto [ok2, data] = get_const_vector(y.value, m_pos + 2); ok2 && data._u32[3] % 16 == 0) - { - value_t addr = eval(zext(extract(x, 3) & 0x3fff0) + ((get_imm(op.si10) << 4) + splat(data._u32[3] & 0x3fff0))); - make_store_ls(addr, get_vr(op.rt)); - return; + if (const u32 remainder = data._u32[3] % 0x10; remainder == 0) + { + value_t addr = eval(zext(extract(pair.second, 3) & 0x3fff0) + ((get_imm(op.si10) << 4) + splat(addend))); + make_store_ls(addr, get_vr(op.rt)); + return; + } + } } } @@ -9421,20 +9436,22 @@ public: { const auto a = get_vr(op.ra); - if (auto [ok, x1, y1] = match_expr(a, match() + match()); ok) + if (auto [ok, x, y] = match_expr(a, match() + match()); ok) { - if (auto [ok1, data] = get_const_vector(x1.value, m_pos + 1); ok1 && data._u32[3] % 16 == 0) + for (auto pair : std::initializer_list, llvm_match_t>>{{x, y}, {y, x}}) { - value_t addr = eval(zext(extract(y1, 3) & 0x3fff0) + ((get_imm(op.si10) << 4) + splat(data._u32[3] & 0x3fff0))); - set_vr(op.rt, make_load_ls(addr)); - return; - } + if (auto [ok, data] = get_const_vector(pair.first.value, m_pos); ok) + { + // "sign extend" offset addend + const u64 addend = (data._u32[3] >= SPU_LS_SIZE) ? data._u32[3] | ~u64{SPU_LS_SIZE - 1} : data._u32[3]; - if (auto [ok2, data] = get_const_vector(y1.value, m_pos + 2); ok2 && data._u32[3] % 16 == 0) - { - value_t addr = eval(zext(extract(x1, 3) & 0x3fff0) + ((get_imm(op.si10) << 4) + splat(data._u32[3] & 0x3fff0))); - set_vr(op.rt, make_load_ls(addr)); - return; + if (const u32 remainder = data._u32[3] % 0x10; remainder == 0) + { + value_t addr = eval(zext(extract(pair.second, 3) & 0x3fff0) + ((get_imm(op.si10) << 4) + splat(addend))); + set_vr(op.rt, make_load_ls(addr)); + return; + } + } } } From ceee246bdbb614f19fec5f554cb87f323b2dc737 Mon Sep 17 00:00:00 2001 From: Elad <18193363+elad335@users.noreply.github.com> Date: Tue, 30 Jun 2026 21:19:48 +0300 Subject: [PATCH 2/9] SPU: Extend LS memory mirrors --- rpcs3/Emu/Cell/SPUThread.cpp | 41 ++++++++++++++++++++++++++++++------ rpcs3/util/vm_native.cpp | 17 ++++++++++++--- 2 files changed, 48 insertions(+), 10 deletions(-) diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 31bf027e06..d968431631 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -1733,21 +1733,48 @@ void spu_thread::cleanup() static_cast&>(*this) = thread_state::finished; } +enum : s64 +{ + SIGNED_LS_SIZE = SPU_LS_SIZE +}; + spu_thread::~spu_thread() { // Unmap LS and its mirrors - shm->unmap(ls + SPU_LS_SIZE); - shm->unmap(ls); - shm->unmap(ls - SPU_LS_SIZE); - utils::memory_release(ls - SPU_LS_SIZE * 2, SPU_LS_SIZE * 5); + for (s64 ls_offs = 0 - SIGNED_LS_SIZE * 2; ls_offs <= SIGNED_LS_SIZE * 2; ls_offs += SIGNED_LS_SIZE) + { + shm->unmap(ls + ls_offs); + } + + utils::memory_release(ls - SIGNED_LS_SIZE * 3, SIGNED_LS_SIZE * 7); } u8* spu_thread::map_ls(utils::shm& shm, void* ptr) { + const auto ls = ptr ? static_cast(ptr) : static_cast(ensure(utils::memory_reserve(SIGNED_LS_SIZE * 7, nullptr, true))) + SIGNED_LS_SIZE * 3; + vm::writer_lock mlock; - const auto ls = ptr ? static_cast(ptr) : static_cast(ensure(utils::memory_reserve(SPU_LS_SIZE * 5, nullptr, true))) + SPU_LS_SIZE * 2; - ensure(shm.map_critical(ls - SPU_LS_SIZE).first && shm.map_critical(ls).first && shm.map_critical(ls + SPU_LS_SIZE).first); + for (s64 ls_offs = 0 - SIGNED_LS_SIZE * 2; ls_offs <= SIGNED_LS_SIZE * 2; ls_offs += SIGNED_LS_SIZE) + { + const auto [ptr_ret, str] = shm.map_critical(ls + ls_offs); + + if (!ptr_ret) + { + fmt::throw_exception("spu_thread::map_ls() failed: map_critical returned error (error=%s) [ls_offs=0x%x]", str, ls_offs); + } + + if (ptr_ret != ls + ls_offs) + { + fmt::throw_exception("spu_thread::map_ls() failed: map_critical returned a different address: 0x%llx vs 0x%llx (error=%s) [ls_offs=0x%x]", ptr_ret, ls + ls_offs, str, ls_offs); + } + + if (!str.empty()) + { + fmt::throw_exception("spu_thread::map_ls() failed: map_critical returned unexpected error (error=%s) [ls_offs=0x%x]", str, ls_offs); + } + } + return ls; } @@ -1792,7 +1819,7 @@ spu_thread::spu_thread(lv2_spu_group* group, u32 index, std::string_view name, u , index(index) , thread_type(group ? spu_type::threaded : is_isolated ? spu_type::isolated : spu_type::raw) , shm(std::make_shared(SPU_LS_SIZE)) - , ls(static_cast(utils::memory_reserve(SPU_LS_SIZE * 5, nullptr, true)) + SPU_LS_SIZE * 2) + , ls(static_cast(utils::memory_reserve(SPU_LS_SIZE * 7, nullptr, true)) + SPU_LS_SIZE * 3) , option(option) , lv2_id(lv2_id) , spu_tname(make_single(name)) diff --git a/rpcs3/util/vm_native.cpp b/rpcs3/util/vm_native.cpp index c66c016a52..5b5c7746f1 100644 --- a/rpcs3/util/vm_native.cpp +++ b/rpcs3/util/vm_native.cpp @@ -909,9 +909,14 @@ namespace utils #ifdef _WIN32 ::MEMORY_BASIC_INFORMATION mem{}; - if (!::VirtualQuery(target, &mem, sizeof(mem)) || mem.State != MEM_RESERVE) + if (!::VirtualQuery(target, &mem, sizeof(mem))) { - return {nullptr, fmt::format("VirtualQuery() Unexpceted memory info: state=0x%x, %s", mem.State, std::as_bytes(std::span(&mem, 1)))}; + return {nullptr, fmt::format("VirtualQuery() Failed with %s", fmt::win_error{GetLastError(), nullptr})}; + } + + if (mem.State != MEM_RESERVE) + { + return {nullptr, fmt::format("VirtualQuery() reported unexpected memory info: state=0x%x, %s", mem.State, std::as_bytes(std::span(&mem, 1)))}; } const auto base = static_cast(mem.AllocationBase); @@ -977,8 +982,14 @@ namespace utils return {nullptr, "VirtualAlloc() failed to reserve allocation end"}; } #endif + const auto mapped_addr = this->map(target, prot, cow); - return {this->map(target, prot, cow), "Failed to map"}; + if (!mapped_addr) + { + return {nullptr, "Failed to map"}; + } + + return {mapped_addr, {}}; } u8* shm::map_self(protection prot) From 9b1a65a1b7486df3166120bcd94ac4a04f47092d Mon Sep 17 00:00:00 2001 From: Elad <18193363+elad335@users.noreply.github.com> Date: Tue, 30 Jun 2026 23:07:40 +0300 Subject: [PATCH 3/9] Disable trap on MacOs --- Utilities/Thread.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp index d05eb1488a..fd29182c39 100644 --- a/Utilities/Thread.cpp +++ b/Utilities/Thread.cpp @@ -3047,7 +3047,9 @@ void thread_ctrl::set_name(std::string name) return false; }).second) { +#ifndef __APPLE__ utils::trap(); +#endif } } From 8566d4f8b4ef5b3a2c9fa2f175d48dc42724dc5c Mon Sep 17 00:00:00 2001 From: Elad <18193363+elad335@users.noreply.github.com> Date: Mon, 6 Jul 2026 19:29:15 +0300 Subject: [PATCH 4/9] SPU: Fix ppu_check_patch_spu_images --- rpcs3/Emu/Cell/PPUModule.cpp | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/rpcs3/Emu/Cell/PPUModule.cpp b/rpcs3/Emu/Cell/PPUModule.cpp index 15ff9b1fa8..dc78ddcb83 100644 --- a/rpcs3/Emu/Cell/PPUModule.cpp +++ b/rpcs3/Emu/Cell/PPUModule.cpp @@ -1185,9 +1185,11 @@ static void ppu_check_patch_spu_images(const ppu_module& mod, const ppu ensure(data.size() <= pos && index <= data.size()); + const auto data_to_search = data.substr(index, pos - index); + for (std::string_view value : values) { - if (usz pos0 = data.substr(index, pos - index).find(value); pos0 != umax && pos0 + index < pos) + if (usz pos0 = data_to_search.find(value); pos0 != umax && pos0 + index < pos) { pos = static_cast(pos0 + index); } @@ -1211,12 +1213,22 @@ static void ppu_check_patch_spu_images(const ppu_module& mod, const ppu { const u32 old_prefix_addr = prefix_addr; - auto search_guid_pattern = [&](u32 index, std::string_view data_span, s32 advance_index, u32 lower_bound, u32 uppper_bound) -> u32 + auto search_guid_pattern = [&](u32 index, std::string_view data_span, s32 advance_index, u32 lower_bound, u32 upper_bound) -> u32 { - for (u32 search = index & -16, tries = 16 * 64; tries && search >= lower_bound && search < uppper_bound; tries = tries - 1, search = advance_index < 0 ? utils::sub_saturate(search, 0 - advance_index) : search + advance_index) + ensure(upper_bound <= data_span.size()); + ensure(lower_bound <= data_span.size()); + ensure(lower_bound <= upper_bound); + + for (u32 search = index & -16, tries = 16 * 64; tries && search >= lower_bound && search < (upper_bound & -16); tries = tries - 1, search = advance_index < 0 ? utils::sub_saturate(search, 0 - advance_index) : search + advance_index) { if (seg_view[search] != 0x42 && seg_view[search] != 0x43) { + if (search == 0 && advance_index <= 0) + { + // Fast early-out + break; + } + continue; } @@ -1260,7 +1272,7 @@ static void ppu_check_patch_spu_images(const ppu_module& mod, const ppu { const u32 instruction = std::min(search_guid_pattern(addr_last, ls_segment, +16, 0, ::size32(ls_segment)), find_first_of_multiple(ls_segment, prefixes, addr_last)); - if (instruction != umax && std::memcmp(ls_segment.data() + instruction, "\x24\0\x40\x80", 4) == 0) + if (instruction < ls_segment.size() && std::memcmp(ls_segment.data() + instruction, "\x24\0\x40\x80", 4) == 0) { if (instruction % 4 != prefix_addr % 4) { From 7d1076aff926f0b9eaf7bf13efeab875dc79be64 Mon Sep 17 00:00:00 2001 From: Elad <18193363+elad335@users.noreply.github.com> Date: Mon, 6 Jul 2026 19:36:54 +0300 Subject: [PATCH 5/9] SPU LLVM: Disable NaN rulling-out in Reduced Loop on ARM64 --- rpcs3/Emu/Cell/SPURecompiler.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rpcs3/Emu/Cell/SPURecompiler.h b/rpcs3/Emu/Cell/SPURecompiler.h index e2b2f2c81e..0bc3546586 100644 --- a/rpcs3/Emu/Cell/SPURecompiler.h +++ b/rpcs3/Emu/Cell/SPURecompiler.h @@ -685,7 +685,11 @@ public: bool is_gpr_not_NaN_hint(u32 i) const noexcept { +#ifdef ARCH_X64 return gpr_not_nans.test(i); +#else + return false; +#endif } origin_t get_reg(u32 reg_val) noexcept From c198e220e25081e26a80d139ffb9b14dd4e0e29d Mon Sep 17 00:00:00 2001 From: Elad <18193363+elad335@users.noreply.github.com> Date: Mon, 6 Jul 2026 20:18:21 +0300 Subject: [PATCH 6/9] SPU: LLVM: Add spu_thread::state check in Reduced Loop --- rpcs3/Emu/Cell/SPULLVMRecompiler.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp b/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp index b0c2c9854d..6b3841280e 100644 --- a/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp +++ b/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp @@ -2981,6 +2981,11 @@ public: condition = m_ir->CreateAnd(cond_verify, condition); } } + else + { + // Check spu_thread::state + condition = m_ir->CreateAnd(m_ir->CreateICmpEQ(spu_context_attr(m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::state), true)), m_ir->getInt32(0)), condition); + } m_ir->CreateCondBr(condition, optimization_block, block_optimization_next); }; From ca029e55234a7489496b841d2b3b5b37488a1898 Mon Sep 17 00:00:00 2001 From: Elad <18193363+elad335@users.noreply.github.com> Date: Mon, 6 Jul 2026 23:16:45 +0300 Subject: [PATCH 7/9] SPU LLVM: Avoid raw pointers --- rpcs3/Emu/Cell/SPUCommonRecompiler.cpp | 5 +++++ rpcs3/Emu/Cell/SPULLVMRecompiler.cpp | 6 +++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp b/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp index b8b27e0b10..8cb252b506 100644 --- a/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp +++ b/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp @@ -9987,6 +9987,11 @@ std::array& block_reg_info::evaluate_start_state(const s void spu_recompiler_base::add_pattern(inst_attr attr, u32 start, u64 info, std::shared_ptr info_ptr) { + if (m_inst_attrs[start / 4] != inst_attr::none) + { + fmt::throw_exception("SPU Pattern is occupied! (start=0x%x)", start); + } + m_patterns[start] = pattern_info{info, info_ptr}; m_inst_attrs[start / 4] = attr; } diff --git a/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp b/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp index 6b3841280e..b8e51d28dc 100644 --- a/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp +++ b/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp @@ -210,7 +210,7 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator function_info* m_finfo = nullptr; // Reduced Loop Pattern information (if available) - reduced_loop_t* m_reduced_loop_info = nullptr; + std::shared_ptr m_reduced_loop_info; // All blocks in the current function chunk std::unordered_map> m_blocks; @@ -2689,7 +2689,7 @@ public: } const bool is_reduced_loop = m_inst_attrs[(baddr - start) / 4] == inst_attr::reduced_loop; - m_reduced_loop_info = is_reduced_loop ? std::static_pointer_cast(ensure(m_patterns.at(baddr - start).info_ptr)).get() : nullptr; + m_reduced_loop_info = is_reduced_loop ? std::static_pointer_cast(ensure(m_patterns.at(baddr - start).info_ptr)) : nullptr; BasicBlock* block_optimization_phi_parent = nullptr; const auto block_optimization_inner = is_reduced_loop ? BasicBlock::Create(m_context, fmt::format("b-loop-it-0x%x", m_pos), m_function) : nullptr; @@ -7813,7 +7813,7 @@ public: value_t clamp_smax(value_t v, u32 gpr = s_reg_max) { - if (m_reduced_loop_info && gpr < s_reg_max && m_reduced_loop_info->is_gpr_not_NaN_hint(gpr)) + if (gpr < s_reg_max && m_reduced_loop_info && m_reduced_loop_info->is_gpr_not_NaN_hint(gpr)) { return v; } From 6a622b794ac806e42194cf6979b7dd5f4ff88f99 Mon Sep 17 00:00:00 2001 From: Elad <18193363+elad335@users.noreply.github.com> Date: Tue, 7 Jul 2026 01:44:16 +0300 Subject: [PATCH 8/9] Avoid using pthread_self() partially --- Utilities/Thread.cpp | 29 ++++++++++++++++++++--------- rpcs3/util/atomic.cpp | 12 ++++++++++-- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp index fd29182c39..d2a416209e 100644 --- a/Utilities/Thread.cpp +++ b/Utilities/Thread.cpp @@ -3560,15 +3560,26 @@ std::pair thread_ctrl::get_thread_stack() u64 thread_ctrl::get_tid() { -#ifdef _WIN32 - return GetCurrentThreadId(); -#elif defined(ANDROID) - return static_cast(pthread_self()); -#elif defined(__linux__) - return syscall(SYS_gettid); -#else - return reinterpret_cast(pthread_self()); -#endif + static thread_local u64 s_tls_tid = []() -> u64 + { + #ifdef _WIN32 + return GetCurrentThreadId(); + #elif defined(ANDROID) + return pthread_gettid_np(pthread_self()); + #elif defined(__linux__) + return syscall(SYS_gettid); + #elif defined(__APPLE__) + u64 tid{}; + pthread_threadid_np(nullptr, &tid); + return tid; + #elif defined(__FreeBSD__) + return pthread_getthreadid_np(); + #else + return static_cast(pthread_self()); + #endif + }(); + + return s_tls_tid; } bool thread_ctrl::is_main() diff --git a/rpcs3/util/atomic.cpp b/rpcs3/util/atomic.cpp index 4fc0316206..9923325da2 100644 --- a/rpcs3/util/atomic.cpp +++ b/rpcs3/util/atomic.cpp @@ -186,9 +186,17 @@ namespace #ifdef _WIN32 tid = GetCurrentThreadId(); #elif defined(ANDROID) - tid = pthread_self(); + tid = pthread_gettid_np(pthread_self()); +#elif defined(__linux__) + tid = syscall(SYS_gettid); +#elif defined(__APPLE__) + u64 tid_temp{}; + pthread_threadid_np(nullptr, &tid_temp); + tid = tid_temp; // Use a temporary for extra safety +#elif defined(__FreeBSD__) + tid = pthread_getthreadid_np(); #else - tid = reinterpret_cast(pthread_self()); + tid = pthread_self(); #endif #ifdef USE_STD From 487573f2fe651298a9d7d291d919712312120188 Mon Sep 17 00:00:00 2001 From: Elad <18193363+elad335@users.noreply.github.com> Date: Tue, 7 Jul 2026 03:19:07 +0300 Subject: [PATCH 9/9] Fix possible multi-platform race-condition (depending on kernel) As well as remove another pthread_self call. --- Utilities/Thread.cpp | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp index d2a416209e..afeab41fe7 100644 --- a/Utilities/Thread.cpp +++ b/Utilities/Thread.cpp @@ -2337,6 +2337,7 @@ void thread_base::start() ensure(::ResumeThread(reinterpret_cast(+m_thread)) != static_cast(-1)); #elif defined(__APPLE__) pthread_attr_t attrs; + pthread_t thread_id{}; struct sched_param sp; memset(&sp, 0, sizeof(struct sched_param)); sp.sched_priority=99; @@ -2346,20 +2347,43 @@ void thread_base::start() pthread_attr_set_qos_class_np(&attrs, QOS_CLASS_USER_INTERACTIVE, 0); pthread_attr_setschedpolicy(&attrs, SCHED_RR); pthread_attr_setschedparam(&attrs, &sp); - ensure(pthread_create(reinterpret_cast(&m_thread.raw()), &attrs, entry_point, this) == 0); + ensure(pthread_create(&thread_id, &attrs, entry_point, this) == 0); #else - ensure(pthread_create(reinterpret_cast(&m_thread.raw()), nullptr, entry_point, this) == 0); + pthread_t thread_id{}; + ensure(pthread_create(&thread_id, nullptr, entry_point, this) == 0); +#endif + +#ifndef _WIN32 + // Update m_thread atomically + u64 dest_id = 0; + std::memcpy(&dest_id, &thread_id, sizeof(thread_id)); + + if (!m_thread && !m_thread.compare_and_swap_test(0, dest_id)) + { + ensure(m_thread == dest_id); + } #endif } void thread_base::initialize(void (*error_cb)()) { #ifndef _WIN32 -#ifdef ANDROID - m_thread.release(pthread_self()); +#ifdef __APPLE__ + while (!m_thread) + { + busy_wait(); + } + [[maybe_unused]] u64 new_tid = 0; +#elif defined(ANDROID) + const u64 new_tid = pthread_self(); #else - m_thread.release(reinterpret_cast(pthread_self())); + const u64 new_tid = reinterpret_cast(pthread_self()); #endif + + if (!m_thread && !m_thread.compare_and_swap_test(0, new_tid)) + { + ensure(m_thread == new_tid); + } #endif // Initialize TLS variables