diff --git a/Utilities/Thread.h b/Utilities/Thread.h index 3130c0fcb20b..ae4d625f1e42 100644 --- a/Utilities/Thread.h +++ b/Utilities/Thread.h @@ -635,13 +635,21 @@ class named_thread final : public Context, result_storage, thread_base // Join thread by thread_state::finished named_thread& operator=(thread_state s) { + bool notify_sync = false; + + if (s >= thread_state::aborting && thread::m_sync.fetch_op([](u64& v){ return !(v & 3) && (v |= 1); }).second) + { + notify_sync = true; + } + if constexpr (std::is_assignable_v) { static_cast(*this) = s; } - if (s >= thread_state::aborting && thread::m_sync.fetch_op([](u64& v){ return !(v & 3) && (v |= 1); }).second) + if (notify_sync) { + // Notify after context abortion has been made so all conditions for wake-up be satisfied by the time of notification thread::m_sync.notify_one(1); } diff --git a/rpcs3/Emu/CPU/CPUThread.cpp b/rpcs3/Emu/CPU/CPUThread.cpp index d48f902f634d..211e5b2924c6 100644 --- a/rpcs3/Emu/CPU/CPUThread.cpp +++ b/rpcs3/Emu/CPU/CPUThread.cpp @@ -881,8 +881,19 @@ void cpu_thread::notify() cpu_thread& cpu_thread::operator=(thread_state) { - state += cpu_flag::exit; - state.notify_one(cpu_flag::exit); + if (state & cpu_flag::exit) + { + // Must be notified elsewhere or self-raised + return *this; + } + + const auto old = state.fetch_add(cpu_flag::exit); + + if (old & cpu_flag::wait && old.none_of(cpu_flag::again + cpu_flag::exit)) + { + state.notify_one(cpu_flag::exit); + } + return *this; } diff --git a/rpcs3/Emu/Cell/SPURecompiler.cpp b/rpcs3/Emu/Cell/SPURecompiler.cpp index d84b48bc07b8..e7169c89e421 100644 --- a/rpcs3/Emu/Cell/SPURecompiler.cpp +++ b/rpcs3/Emu/Cell/SPURecompiler.cpp @@ -12,6 +12,7 @@ #include "Utilities/StrUtil.h" #include "Utilities/JIT.h" #include "util/init_mutex.hpp" +#include "util/shared_ptr.hpp" #include "SPUThread.h" #include "SPUAnalyser.h" @@ -10647,6 +10648,7 @@ struct spu_llvm { // Workload lf_queue> registered; + atomic_ptr> m_workers; spu_llvm() { @@ -10716,7 +10718,9 @@ struct spu_llvm u32 worker_index = 0; - named_thread_group workers("SPUW.", worker_count); + m_workers = make_single>("SPUW.", worker_count); + auto workers_ptr = m_workers.load(); + auto& workers = *workers_ptr; while (thread_ctrl::state() != thread_state::aborting) { @@ -10769,12 +10773,27 @@ struct spu_llvm static_cast(prof_mutex.init_always([&]{ samples.clear(); })); + m_workers.reset(); + for (u32 i = 0; i < worker_count; i++) { - (workers.begin() + i)->registered.push(0, nullptr); + (workers.begin() + i)->operator=(thread_state::aborting); } } + spu_llvm& operator=(thread_state) + { + if (const auto workers = m_workers.load()) + { + for (u32 i = 0; i < workers->size(); i++) + { + (workers->begin() + i)->operator=(thread_state::aborting); + } + } + + return *this; + } + static constexpr auto thread_name = "SPU LLVM"sv; }; diff --git a/rpcs3/Emu/Cell/lv2/sys_fs.cpp b/rpcs3/Emu/Cell/lv2/sys_fs.cpp index 0121236ff614..937567c4b122 100644 --- a/rpcs3/Emu/Cell/lv2/sys_fs.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_fs.cpp @@ -313,7 +313,7 @@ void lv2_file::save(utils::serial& ar) } // UNIX allows deletion of files while descriptors are still opened - // descriptpors shall keep the data in memory in this case + // descriptors shall keep the data in memory in this case const bool in_mem = [&]() { if (mp->flags & lv2_mp_flag::read_only) @@ -323,11 +323,31 @@ void lv2_file::save(utils::serial& ar) fs::file test{real_path}; - if (!test) return true; + if (!test) + { + if (fs::is_file(real_path + ".66600")) + { + // May be a split-files descriptor, don't even bother + return false; + } + + return true; + } - return test.stat() != file.stat(); + fs::stat_t test_s = test.stat(); + fs::stat_t file_s = file.stat(); + + // They don't matter for comparison and only create problems with encrypted files + test_s.is_writable = file_s.is_writable; + test_s.size = file_s.size; + return test_s != file_s; }(); + if (in_mem) + { + sys_fs.error("Saving \'%s\' LV2 file descriptor in memory! (exists=%s, type=%s, flags=0x%x)", name.data(), fs::is_file(real_path), type, flags); + } + ar(in_mem); if (in_mem)