mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-20 19:45:20 +00:00
Progress Dialog: Fix race on PPU compilation status
This commit is contained in:
parent
36dce454dd
commit
a001e6ef09
6 changed files with 74 additions and 15 deletions
|
@ -3971,7 +3971,7 @@ extern void ppu_initialize()
|
|||
// Validate analyser results (not required)
|
||||
_main.validate(0);
|
||||
|
||||
g_progr = "Scanning PPU Modules...";
|
||||
progr = "Scanning PPU Modules...";
|
||||
|
||||
bool compile_main = false;
|
||||
|
||||
|
@ -4556,7 +4556,7 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
|
|||
|
||||
if (!workload.empty())
|
||||
{
|
||||
g_progr = "Compiling PPU modules...";
|
||||
*progr = "Compiling PPU modules...";
|
||||
}
|
||||
|
||||
// Create worker threads for compilation (TODO: how many threads)
|
||||
|
@ -4624,7 +4624,7 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
|
|||
if (workload.size() < link_workload.size())
|
||||
{
|
||||
// Only show this message if this task is relevant
|
||||
g_progr = "Linking PPU modules...";
|
||||
*progr = "Linking PPU modules...";
|
||||
}
|
||||
|
||||
for (auto [obj_name, is_compiled] : link_workload)
|
||||
|
|
|
@ -654,7 +654,7 @@ void spu_cache::initialize()
|
|||
break;
|
||||
}
|
||||
|
||||
g_progr_ptotal.wait(v);
|
||||
thread_ctrl::wait_on(g_progr_ptotal, v);
|
||||
}
|
||||
|
||||
g_progr_ptotal += ::size32(func_list);
|
||||
|
|
|
@ -2678,7 +2678,7 @@ void Emulator::Kill(bool allow_autoexit, bool savestate)
|
|||
{
|
||||
// Show visual feedback to the user in case that stopping takes a while.
|
||||
// This needs to be done before actually stopping, because otherwise the necessary threads will be terminated before we can show an image.
|
||||
if (auto progress_dialog = g_fxo->try_get<named_thread<progress_dialog_server>>(); progress_dialog && +g_progr)
|
||||
if (auto progress_dialog = g_fxo->try_get<named_thread<progress_dialog_server>>(); progress_dialog && g_progr.load())
|
||||
{
|
||||
// We are currently showing a progress dialog. Notify it that we are going to stop emulation.
|
||||
g_system_progress_stopping = true;
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
LOG_CHANNEL(sys_log, "SYS");
|
||||
|
||||
// Progress display server synchronization variables
|
||||
atomic_t<const char*> g_progr{nullptr};
|
||||
atomic_t<progress_dialog_string_t> g_progr{};
|
||||
atomic_t<u32> g_progr_ftotal{0};
|
||||
atomic_t<u32> g_progr_fdone{0};
|
||||
atomic_t<u32> g_progr_ptotal{0};
|
||||
|
@ -40,7 +40,7 @@ void progress_dialog_server::operator()()
|
|||
while (!g_system_progress_stopping && thread_ctrl::state() != thread_state::aborting)
|
||||
{
|
||||
// Wait for the start condition
|
||||
auto text0 = +g_progr;
|
||||
const char* text0 = g_progr.load();
|
||||
|
||||
while (!text0)
|
||||
{
|
||||
|
@ -50,7 +50,7 @@ void progress_dialog_server::operator()()
|
|||
}
|
||||
|
||||
thread_ctrl::wait_for(5000);
|
||||
text0 = +g_progr;
|
||||
text0 = g_progr.load();
|
||||
}
|
||||
|
||||
if (g_system_progress_stopping || thread_ctrl::state() == thread_state::aborting)
|
||||
|
@ -120,7 +120,7 @@ void progress_dialog_server::operator()()
|
|||
// Update progress
|
||||
while (!g_system_progress_stopping && thread_ctrl::state() != thread_state::aborting)
|
||||
{
|
||||
const auto text_new = g_progr.load();
|
||||
const auto text_new = +g_progr.load();
|
||||
|
||||
const u32 ftotal_new = g_progr_ftotal;
|
||||
const u32 fdone_new = g_progr_fdone;
|
||||
|
@ -239,5 +239,5 @@ progress_dialog_server::~progress_dialog_server()
|
|||
g_progr_fdone.release(0);
|
||||
g_progr_ptotal.release(0);
|
||||
g_progr_pdone.release(0);
|
||||
g_progr.release(nullptr);
|
||||
g_progr.release(progress_dialog_string_t{});
|
||||
}
|
||||
|
|
|
@ -3,7 +3,19 @@
|
|||
#include "util/types.hpp"
|
||||
#include "util/atomic.hpp"
|
||||
|
||||
extern atomic_t<const char*> g_progr;
|
||||
struct alignas(16) progress_dialog_string_t
|
||||
{
|
||||
const char* m_text;
|
||||
u32 m_user_count;
|
||||
u32 m_update_id;
|
||||
|
||||
operator const char*() const noexcept
|
||||
{
|
||||
return m_text;
|
||||
}
|
||||
};
|
||||
|
||||
extern atomic_t<progress_dialog_string_t> g_progr;
|
||||
extern atomic_t<u32> g_progr_ftotal;
|
||||
extern atomic_t<u32> g_progr_fdone;
|
||||
extern atomic_t<u32> g_progr_ptotal;
|
||||
|
@ -15,21 +27,68 @@ extern atomic_t<bool> g_system_progress_stopping;
|
|||
class scoped_progress_dialog final
|
||||
{
|
||||
// Saved previous value
|
||||
const char* const m_prev;
|
||||
const char* m_prev;
|
||||
u32 m_prev_id;
|
||||
u32 m_id;
|
||||
|
||||
public:
|
||||
scoped_progress_dialog(const char* text) noexcept
|
||||
: m_prev(g_progr.exchange(text ? text : ""))
|
||||
{
|
||||
std::tie(m_prev, m_prev_id, m_id) = g_progr.atomic_op([this, text = ensure(text)](progress_dialog_string_t& progr)
|
||||
{
|
||||
const char* old = progr.m_text;
|
||||
progr.m_user_count++;
|
||||
progr.m_update_id++;
|
||||
progr.m_text = text;
|
||||
|
||||
ensure(progr.m_user_count > 1 || !old); // Ensure it was nullptr before first use
|
||||
return std::make_tuple(old, progr.m_update_id - 1, progr.m_update_id);
|
||||
});
|
||||
}
|
||||
|
||||
scoped_progress_dialog(const scoped_progress_dialog&) = delete;
|
||||
|
||||
scoped_progress_dialog& operator=(const scoped_progress_dialog&) = delete;
|
||||
|
||||
scoped_progress_dialog& operator=(const char* text) noexcept
|
||||
{
|
||||
// This method is destroying the previous value and replacing it with a new one
|
||||
std::tie(m_prev, m_prev_id, m_id) = g_progr.atomic_op([this, text = ensure(text)](progress_dialog_string_t& progr)
|
||||
{
|
||||
if (m_id == progr.m_update_id)
|
||||
{
|
||||
progr.m_update_id = m_prev_id;
|
||||
progr.m_text = m_prev;
|
||||
}
|
||||
|
||||
const char* old = progr.m_text;
|
||||
progr.m_text = text;
|
||||
progr.m_update_id++;
|
||||
|
||||
ensure(progr.m_user_count > 0);
|
||||
return std::make_tuple(old, progr.m_update_id - 1, progr.m_update_id);
|
||||
});
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
~scoped_progress_dialog() noexcept
|
||||
{
|
||||
g_progr.release(m_prev);
|
||||
g_progr.atomic_op([this](progress_dialog_string_t& progr)
|
||||
{
|
||||
if (progr.m_user_count-- == 1)
|
||||
{
|
||||
// Clean text only on last user
|
||||
progr.m_text = nullptr;
|
||||
progr.m_update_id = 0;
|
||||
}
|
||||
else if (m_id == progr.m_update_id)
|
||||
{
|
||||
// Restore text only if no other updates were made by other threads
|
||||
progr.m_text = ensure(m_prev);
|
||||
progr.m_update_id = m_prev_id;
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -579,7 +579,7 @@ bool gs_frame::get_mouse_lock_state()
|
|||
|
||||
void gs_frame::hide_on_close()
|
||||
{
|
||||
if (!(+g_progr))
|
||||
if (!g_progr.load())
|
||||
{
|
||||
// Hide the dialog before stopping if no progress bar is being shown.
|
||||
// Otherwise users might think that the game softlocked if stopping takes too long.
|
||||
|
|
Loading…
Add table
Reference in a new issue