mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-03 21:41:26 +12:00
Implement thread_state::errored
State after calling thread emergency_exit() function. Also default-construct thread result in this case.
This commit is contained in:
parent
eb2dcaf602
commit
c577bd2111
5 changed files with 50 additions and 15 deletions
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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())
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue