diff --git a/Utilities/StrFmt.cpp b/Utilities/StrFmt.cpp index f927315385..e2cde956ae 100644 --- a/Utilities/StrFmt.cpp +++ b/Utilities/StrFmt.cpp @@ -2,9 +2,11 @@ #include "BEType.h" #include "StrUtil.h" #include "cfmt.h" +#include "util/logs.hpp" #include #include +#include "Thread.h" #ifdef _WIN32 #include @@ -203,7 +205,7 @@ namespace fmt { void raw_error(const char* msg) { - throw std::runtime_error{msg}; + thread_ctrl::emergency_exit(msg); } void raw_verify_error(const char* msg, const fmt_type_info* sup, u64 arg) @@ -236,7 +238,7 @@ namespace fmt out += msg; } - throw std::runtime_error{out}; + thread_ctrl::emergency_exit(out); } void raw_narrow_error(const char* msg, const fmt_type_info* sup, u64 arg) @@ -256,14 +258,14 @@ namespace fmt out += msg; } - throw std::range_error{out}; + thread_ctrl::emergency_exit(out); } void raw_throw_exception(const char* fmt, const fmt_type_info* sup, const u64* args) { std::string out; raw_append(out, fmt, sup, args); - throw std::runtime_error{out}; + thread_ctrl::emergency_exit(out); } struct cfmt_src; diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp index de4262ab0b..70c243fafc 100644 --- a/Utilities/Thread.cpp +++ b/Utilities/Thread.cpp @@ -2018,6 +2018,31 @@ u64 thread_base::get_cycles() } } +void thread_ctrl::emergency_exit(std::string_view reason) +{ + sig_log.fatal("Thread terminated due to fatal error: %s", reason); + + if (const auto _this = g_tls_this_thread) + { + if (_this->finalize(0)) + { + delete _this; + } + + // Do some not very useful cleanup + thread_base::finalize(); + +#ifdef _WIN32 + _endthreadex(0); +#else + pthread_exit(0); +#endif + } + + // Assume main thread + report_fatal_error(std::string(reason)); +} + void thread_ctrl::detect_cpu_layout() { if (!g_native_core_layout.compare_and_swap_test(native_core_arrangement::undefined, native_core_arrangement::generic)) diff --git a/Utilities/Thread.h b/Utilities/Thread.h index 4fa11af2d3..028645dbb3 100644 --- a/Utilities/Thread.h +++ b/Utilities/Thread.h @@ -225,6 +225,9 @@ public: _wait_for(-1, true); } + // Exit. + [[noreturn]] static void emergency_exit(std::string_view reason); + // Get current thread (may be nullptr) static thread_base* get_current() { diff --git a/rpcs3/Emu/CPU/CPUThread.cpp b/rpcs3/Emu/CPU/CPUThread.cpp index 00cd7ca740..98f806480a 100644 --- a/rpcs3/Emu/CPU/CPUThread.cpp +++ b/rpcs3/Emu/CPU/CPUThread.cpp @@ -349,6 +349,34 @@ void cpu_thread::operator()() state += cpu_flag::wait; g_cpu_suspend_lock.lock_unlock(); + static thread_local struct thread_cleanup_t + { + cpu_thread* _this; + u64 slot; + + thread_cleanup_t(cpu_thread* _this, u64 slot) + : _this(_this) + , slot(slot) + { + } + + ~thread_cleanup_t() + { + if (auto ptr = vm::g_tls_locked) + { + ptr->compare_and_swap(_this, nullptr); + } + + // Unregister and wait if necessary + _this->state += cpu_flag::wait; + if (g_cpu_array[slot].exchange(nullptr) != _this) + sys_log.fatal("Inconsistency for array slot %u", slot); + g_cpu_array_bits[slot / 64] &= ~(1ull << (slot % 64)); + g_cpu_array_sema--; + g_cpu_suspend_lock.lock_unlock(); + } + } cleanup{this, array_slot}; + // Check thread status while (!(state & (cpu_flag::exit + cpu_flag::dbg_global_stop)) && thread_ctrl::state() != thread_state::aborting) { @@ -373,18 +401,6 @@ void cpu_thread::operator()() thread_ctrl::wait(); } - - if (auto ptr = vm::g_tls_locked) - { - ptr->compare_and_swap(this, nullptr); - } - - // Unregister and wait if necessary - state += cpu_flag::wait; - verify("g_cpu_array[...] -> null" HERE), g_cpu_array[array_slot].exchange(nullptr) == this; - g_cpu_array_bits[array_slot / 64] &= ~(1ull << (array_slot % 64)); - g_cpu_array_sema--; - g_cpu_suspend_lock.lock_unlock(); } cpu_thread::~cpu_thread()