Implement thread_state::errored

State after calling thread emergency_exit() function.
Also default-construct thread result in this case.
This commit is contained in:
Nekotekina 2020-03-20 20:18:08 +03:00
parent eb2dcaf602
commit c577bd2111
5 changed files with 50 additions and 15 deletions

View file

@ -1755,6 +1755,8 @@ const bool s_terminate_handler_set = []() -> bool
thread_local DECLARE(thread_ctrl::g_tls_this_thread) = nullptr; thread_local DECLARE(thread_ctrl::g_tls_this_thread) = nullptr;
thread_local DECLARE(thread_ctrl::g_tls_error_callback) = nullptr;
DECLARE(thread_ctrl::g_native_core_layout) { native_core_arrangement::undefined }; DECLARE(thread_ctrl::g_native_core_layout) { native_core_arrangement::undefined };
void thread_base::start(native_entry entry) void thread_base::start(native_entry entry)
@ -1767,11 +1769,13 @@ void thread_base::start(native_entry entry)
#endif #endif
} }
void thread_base::initialize(bool(*wait_cb)(const void*)) void thread_base::initialize(void (*error_cb)(), bool(*wait_cb)(const void*))
{ {
// Initialize TLS variable // Initialize TLS variables
thread_ctrl::g_tls_this_thread = this; thread_ctrl::g_tls_this_thread = this;
thread_ctrl::g_tls_error_callback = error_cb;
// Initialize atomic wait callback // Initialize atomic wait callback
atomic_storage_futex::set_wait_callback(wait_cb); atomic_storage_futex::set_wait_callback(wait_cb);
@ -1828,7 +1832,7 @@ void thread_base::notify_abort() noexcept
atomic_storage_futex::raw_notify(+m_state_notifier); atomic_storage_futex::raw_notify(+m_state_notifier);
} }
bool thread_base::finalize(int) noexcept bool thread_base::finalize(thread_state result_state) noexcept
{ {
// Report pending errors // Report pending errors
error_code::error_report(0, 0, 0, 0); error_code::error_report(0, 0, 0, 0);
@ -1875,7 +1879,7 @@ bool thread_base::finalize(int) noexcept
fsoft, fhard, ctxvol, ctxinv); fsoft, fhard, ctxvol, ctxinv);
// Return true if need to delete thread object // Return true if need to delete thread object
const bool ok = m_state.exchange(thread_state::finished) <= thread_state::aborting; const bool ok = m_state.exchange(result_state) <= thread_state::aborting;
// Signal waiting threads // Signal waiting threads
m_state.notify_all(); m_state.notify_all();
@ -1984,13 +1988,18 @@ thread_base::~thread_base()
} }
} }
void thread_base::join() const bool thread_base::join() const
{ {
for (auto state = m_state.load(); state != thread_state::finished;) for (auto state = m_state.load(); state != thread_state::finished;)
{ {
m_state.wait(state); m_state.wait(state);
state = m_state; state = m_state;
if (state == thread_state::errored)
return false;
} }
return true;
} }
void thread_base::notify() void thread_base::notify()
@ -2061,7 +2070,9 @@ void thread_ctrl::emergency_exit(std::string_view reason)
if (const auto _this = g_tls_this_thread) if (const auto _this = g_tls_this_thread)
{ {
if (_this->finalize(0)) g_tls_error_callback();
if (_this->finalize(thread_state::errored))
{ {
delete _this; delete _this;
} }

View file

@ -36,6 +36,7 @@ enum class thread_state : u32
{ {
created, // Initial state created, // Initial state
aborting, // The thread has been joined in the destructor or explicitly aborted aborting, // The thread has been joined in the destructor or explicitly aborted
errored, // Set after the emergency_exit call
finished // Final state, always set at the end of thread execution finished // Final state, always set at the end of thread execution
}; };
@ -45,6 +46,8 @@ class named_thread;
template <typename T> template <typename T>
struct result_storage struct result_storage
{ {
static_assert(std::is_default_constructible_v<T> && noexcept(T()));
alignas(T) std::byte data[sizeof(T)]; alignas(T) std::byte data[sizeof(T)];
static constexpr bool empty = false; static constexpr bool empty = false;
@ -116,13 +119,13 @@ class thread_base
void start(native_entry); void start(native_entry);
// Called at the thread start // Called at the thread start
void initialize(bool(*wait_cb)(const void*)); void initialize(void (*error_cb)(), bool(*wait_cb)(const void*));
// May be called in destructor // May be called in destructor
void notify_abort() noexcept; void notify_abort() noexcept;
// Called at the thread end, returns true if needs destruction // Called at the thread end, returns true if needs destruction
bool finalize(int) noexcept; bool finalize(thread_state result) noexcept;
// Cleanup after possibly deleting the thread instance // Cleanup after possibly deleting the thread instance
static void finalize() noexcept; static void finalize() noexcept;
@ -142,7 +145,7 @@ public:
u64 get_cycles(); u64 get_cycles();
// Wait for the thread (it does NOT change thread state, and can be called from multiple threads) // Wait for the thread (it does NOT change thread state, and can be called from multiple threads)
void join() const; bool join() const;
// Notify the thread // Notify the thread
void notify(); void notify();
@ -154,6 +157,9 @@ class thread_ctrl final
// Current thread // Current thread
static thread_local thread_base* g_tls_this_thread; static thread_local thread_base* g_tls_this_thread;
// Error handling details
static thread_local void(*g_tls_error_callback)();
// Target cpu core layout // Target cpu core layout
static atomic_t<native_core_arrangement> g_native_core_layout; static atomic_t<native_core_arrangement> g_native_core_layout;
@ -272,7 +278,18 @@ class named_thread final : public Context, result_storage_t<Context>, thread_bas
bool entry_point() bool entry_point()
{ {
thread::initialize([](const void* data) auto tls_error_cb = []()
{
const auto _this = thread_ctrl::get_current();
if constexpr (!result::empty)
{
// Construct using default constructor in the case of failure
new (static_cast<result*>(static_cast<named_thread*>(_this))->get()) typename result::type();
}
};
thread::initialize(tls_error_cb, [](const void* data)
{ {
const auto _this = thread_ctrl::get_current(); const auto _this = thread_ctrl::get_current();
@ -308,7 +325,7 @@ class named_thread final : public Context, result_storage_t<Context>, thread_bas
new (result::get()) typename result::type(Context::operator()()); new (result::get()) typename result::type(Context::operator()());
} }
return thread::finalize(0); return thread::finalize(thread_state::finished);
} }
friend class thread_ctrl; friend class thread_ctrl;
@ -437,12 +454,19 @@ public:
named_thread_group& operator=(const named_thread_group&) = delete; named_thread_group& operator=(const named_thread_group&) = delete;
// Wait for completion // Wait for completion
void join() const bool join() const
{ {
bool result = true;
for (u32 i = 0; i < m_count; i++) for (u32 i = 0; i < m_count; i++)
{ {
std::as_const(*std::launder(m_threads + i))(); std::as_const(*std::launder(m_threads + i))();
if (std::as_const(*std::launder(m_threads + i)) != thread_state::finished)
result = false;
} }
return result;
} }
// Join and access specific thread // Join and access specific thread

View file

@ -257,7 +257,7 @@ namespace rsx
} }
else else
{ {
while (!exit && thread_ctrl::state() == thread_state::created) while (!exit && thread_ctrl::state() <= thread_state::aborting)
{ {
refresh(); refresh();

View file

@ -621,7 +621,7 @@ bool Emulator::InstallPkg(const std::string& path)
{ {
// Wait for the completion // Wait for the completion
while (std::this_thread::sleep_for(5ms), worker != thread_state::finished) while (std::this_thread::sleep_for(5ms), worker <= thread_state::aborting)
{ {
// TODO: update unified progress dialog // TODO: update unified progress dialog
double pval = progress; double pval = progress;

View file

@ -513,7 +513,7 @@ void main_window::HandlePackageInstallation(QStringList file_paths)
}); });
// Wait for the completion // Wait for the completion
while (std::this_thread::sleep_for(5ms), worker != thread_state::finished) while (std::this_thread::sleep_for(5ms), worker <= thread_state::aborting)
{ {
if (pdlg.wasCanceled()) if (pdlg.wasCanceled())
{ {