mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-04 05:51:27 +12:00
Fix suspend_all bug (TSX, TSX-FA)
Could cause freezes.
This commit is contained in:
parent
71ca413067
commit
5b69eda39a
1 changed files with 33 additions and 15 deletions
|
@ -24,6 +24,9 @@ LOG_CHANNEL(sys_log, "SYS");
|
||||||
|
|
||||||
static thread_local u64 s_tls_thread_slot = -1;
|
static thread_local u64 s_tls_thread_slot = -1;
|
||||||
|
|
||||||
|
// Suspend counter stamp
|
||||||
|
static thread_local u64 s_tls_sctr = -1;
|
||||||
|
|
||||||
extern thread_local void(*g_tls_log_control)(const char* fmt, u64 progress);
|
extern thread_local void(*g_tls_log_control)(const char* fmt, u64 progress);
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
|
@ -585,7 +588,6 @@ bool cpu_thread::check_state() noexcept
|
||||||
bool cpu_sleep_called = false;
|
bool cpu_sleep_called = false;
|
||||||
bool cpu_can_stop = true;
|
bool cpu_can_stop = true;
|
||||||
bool escape, retval;
|
bool escape, retval;
|
||||||
u64 susp_ctr = -1;
|
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
|
@ -597,16 +599,26 @@ bool cpu_thread::check_state() noexcept
|
||||||
if (flags & cpu_flag::pause)
|
if (flags & cpu_flag::pause)
|
||||||
{
|
{
|
||||||
// Save value before state is saved and cpu_flag::wait is observed
|
// Save value before state is saved and cpu_flag::wait is observed
|
||||||
susp_ctr = g_suspend_counter;
|
if (s_tls_sctr == umax)
|
||||||
|
|
||||||
if (susp_ctr & 1 && flags & cpu_flag::wait)
|
|
||||||
{
|
{
|
||||||
susp_ctr = -1;
|
u64 ctr = g_suspend_counter;
|
||||||
|
|
||||||
|
if (flags & cpu_flag::wait)
|
||||||
|
{
|
||||||
|
if ((ctr & 3) == 2)
|
||||||
|
{
|
||||||
|
s_tls_sctr = ctr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
susp_ctr = -1;
|
s_tls_sctr = ctr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
s_tls_sctr = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & cpu_flag::temp) [[unlikely]]
|
if (flags & cpu_flag::temp) [[unlikely]]
|
||||||
|
@ -724,22 +736,22 @@ bool cpu_thread::check_state() noexcept
|
||||||
// Wait for current suspend_all operation
|
// Wait for current suspend_all operation
|
||||||
for (u64 i = 0;; i++)
|
for (u64 i = 0;; i++)
|
||||||
{
|
{
|
||||||
if (i < 20 || susp_ctr & 1)
|
u64 ctr = g_suspend_counter;
|
||||||
|
|
||||||
|
if (i < 20 || ctr & 1)
|
||||||
{
|
{
|
||||||
busy_wait(300);
|
busy_wait(300);
|
||||||
}
|
}
|
||||||
else if (g_suspend_counter.load() >> 1 >= susp_ctr >> 1)
|
else if (ctr >> 2 == s_tls_sctr >> 2)
|
||||||
{
|
{
|
||||||
g_suspend_counter.wait(susp_ctr, -2);
|
g_suspend_counter.wait(ctr, -4);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
if (!(state & cpu_flag::pause))
|
|
||||||
{
|
{
|
||||||
|
s_tls_sctr = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
susp_ctr = -1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -869,6 +881,9 @@ bool cpu_thread::suspend_work::push(cpu_thread* _this, bool cancel_if_not_suspen
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Initialization (first increment)
|
||||||
|
g_suspend_counter += 2;
|
||||||
|
|
||||||
// Copy of thread bits
|
// Copy of thread bits
|
||||||
decltype(ctr->cpu_copy_bits) copy2{};
|
decltype(ctr->cpu_copy_bits) copy2{};
|
||||||
|
|
||||||
|
@ -910,6 +925,7 @@ bool cpu_thread::suspend_work::push(cpu_thread* _this, bool cancel_if_not_suspen
|
||||||
_mm_pause();
|
_mm_pause();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Second increment: all threads paused
|
||||||
g_suspend_counter++;
|
g_suspend_counter++;
|
||||||
|
|
||||||
// Extract queue and reverse element order (FILO to FIFO) (TODO: maybe leave order as is?)
|
// Extract queue and reverse element order (FILO to FIFO) (TODO: maybe leave order as is?)
|
||||||
|
@ -964,7 +980,7 @@ bool cpu_thread::suspend_work::push(cpu_thread* _this, bool cancel_if_not_suspen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finalization (second increment)
|
// Finalization (last increment)
|
||||||
verify(HERE), g_suspend_counter++ & 1;
|
verify(HERE), g_suspend_counter++ & 1;
|
||||||
|
|
||||||
// Exact bitset for flag pause removal
|
// Exact bitset for flag pause removal
|
||||||
|
@ -978,8 +994,10 @@ bool cpu_thread::suspend_work::push(cpu_thread* _this, bool cancel_if_not_suspen
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Seems safe to set pause on self because wait flag hasn't been observed yet
|
// Seems safe to set pause on self because wait flag hasn't been observed yet
|
||||||
_this->state += cpu_flag::pause + cpu_flag::temp;
|
s_tls_sctr = g_suspend_counter;
|
||||||
|
_this->state += cpu_flag::pause + cpu_flag::wait + cpu_flag::temp;
|
||||||
_this->check_state();
|
_this->check_state();
|
||||||
|
s_tls_sctr = -1;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue