mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-08 07:51:28 +12:00
Atomic waiting refactoring (#9208)
* Use atomic waitables instead instead of global thread wait as often as possible. * Add ::is_stopped() and and ::is_paued() which can be used in atomic loops and with atomic wait. (constexpr cpu flags test functions) * Fix notification bug of sys_spu_thread_group_exit/terminate. (old bug, enhanced by #9117) * Function time statistics at Emu.Stop() restored. (instead of current "X syscall failed with 0x00000000 : 0")
This commit is contained in:
parent
cf384795d2
commit
f43260bd58
40 changed files with 375 additions and 234 deletions
|
@ -185,7 +185,7 @@ struct cpu_prof
|
|||
if (threads.empty())
|
||||
{
|
||||
// Wait for messages if no work (don't waste CPU)
|
||||
atomic_wait::list(registered).wait();
|
||||
thread_ctrl::wait_on(registered, nullptr);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -557,7 +557,14 @@ void cpu_thread::operator()()
|
|||
while (!(state & cpu_flag::exit) && thread_ctrl::state() != thread_state::aborting)
|
||||
{
|
||||
// Check stop status
|
||||
if (!(state & cpu_flag::stop))
|
||||
const auto state0 = +state;
|
||||
|
||||
if (is_stopped(state0 - cpu_flag::stop))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(state0 & cpu_flag::stop))
|
||||
{
|
||||
cpu_task();
|
||||
|
||||
|
@ -569,7 +576,7 @@ void cpu_thread::operator()()
|
|||
continue;
|
||||
}
|
||||
|
||||
thread_ctrl::wait();
|
||||
thread_ctrl::wait_on(state, state0);
|
||||
|
||||
if (state & cpu_flag::ret && state.test_and_reset(cpu_flag::ret))
|
||||
{
|
||||
|
@ -593,9 +600,9 @@ cpu_thread::cpu_thread(u32 id)
|
|||
g_threads_created++;
|
||||
}
|
||||
|
||||
void cpu_thread::cpu_wait()
|
||||
void cpu_thread::cpu_wait(bs_t<cpu_flag> old)
|
||||
{
|
||||
thread_ctrl::wait();
|
||||
thread_ctrl::wait_on(state, old);
|
||||
}
|
||||
|
||||
bool cpu_thread::check_state() noexcept
|
||||
|
@ -607,6 +614,7 @@ bool cpu_thread::check_state() noexcept
|
|||
while (true)
|
||||
{
|
||||
// Process all flags in a single atomic op
|
||||
bs_t<cpu_flag> state1;
|
||||
const auto state0 = state.fetch_op([&](bs_t<cpu_flag>& flags)
|
||||
{
|
||||
bool store = false;
|
||||
|
@ -660,7 +668,7 @@ bool cpu_thread::check_state() noexcept
|
|||
}
|
||||
|
||||
// Atomically clean wait flag and escape
|
||||
if (!(flags & (cpu_flag::exit + cpu_flag::ret + cpu_flag::stop)))
|
||||
if (!(flags & (cpu_flag::exit + cpu_flag::ret + cpu_flag::stop)))
|
||||
{
|
||||
// Check pause flags which hold thread inside check_state (ignore suspend on cpu_flag::temp)
|
||||
if (flags & (cpu_flag::pause + cpu_flag::dbg_global_pause + cpu_flag::dbg_pause + cpu_flag::memory + (cpu_can_stop ? cpu_flag::suspend : cpu_flag::pause)))
|
||||
|
@ -672,6 +680,7 @@ bool cpu_thread::check_state() noexcept
|
|||
}
|
||||
|
||||
escape = false;
|
||||
state1 = flags;
|
||||
return store;
|
||||
}
|
||||
|
||||
|
@ -703,6 +712,7 @@ bool cpu_thread::check_state() noexcept
|
|||
}
|
||||
|
||||
escape = true;
|
||||
state1 = flags;
|
||||
return store;
|
||||
}).first;
|
||||
|
||||
|
@ -714,6 +724,11 @@ bool cpu_thread::check_state() noexcept
|
|||
cpu_counter::add(this);
|
||||
}
|
||||
|
||||
if (retval)
|
||||
{
|
||||
cpu_on_stop();
|
||||
}
|
||||
|
||||
ensure(cpu_can_stop || !retval);
|
||||
return retval;
|
||||
}
|
||||
|
@ -739,7 +754,7 @@ bool cpu_thread::check_state() noexcept
|
|||
g_fxo->get<gdb_server>()->pause_from(this);
|
||||
}
|
||||
|
||||
cpu_wait();
|
||||
cpu_wait(state1);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -799,6 +814,9 @@ void cpu_thread::notify()
|
|||
|
||||
void cpu_thread::abort()
|
||||
{
|
||||
state += cpu_flag::exit;
|
||||
state.notify_one(cpu_flag::exit);
|
||||
|
||||
// Downcast to correct type
|
||||
if (id_type() == 1)
|
||||
{
|
||||
|
@ -1076,7 +1094,6 @@ void cpu_thread::stop_all() noexcept
|
|||
{
|
||||
auto on_stop = [](u32, cpu_thread& cpu)
|
||||
{
|
||||
cpu.state += cpu_flag::exit;
|
||||
cpu.abort();
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue