-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Progress Dialog: Fix race that could lead to ever-inaccurate results #14531
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -117,15 +117,27 @@ void progress_dialog_server::operator()() | |
u32 pdone = 0; | ||
auto text1 = text0; | ||
|
||
const u64 start_time = get_system_time(); | ||
|
||
// Update progress | ||
while (!g_system_progress_stopping && thread_ctrl::state() != thread_state::aborting) | ||
{ | ||
const auto text_new = +g_progr.load(); | ||
auto whole_state = std::make_tuple(+g_progr.load(), +g_progr_ftotal, +g_progr_fdone, +g_progr_ptotal, +g_progr_pdone); | ||
|
||
while (true) | ||
{ | ||
const auto new_state = std::make_tuple(+g_progr.load(), +g_progr_ftotal, +g_progr_fdone, +g_progr_ptotal, +g_progr_pdone); | ||
|
||
if (new_state == whole_state) | ||
{ | ||
// Only leave while it has a complete (atomic) state | ||
break; | ||
} | ||
|
||
whole_state = new_state; | ||
} | ||
|
||
const u32 ftotal_new = g_progr_ftotal; | ||
const u32 fdone_new = g_progr_fdone; | ||
const u32 ptotal_new = g_progr_ptotal; | ||
const u32 pdone_new = g_progr_pdone; | ||
const auto [text_new, ftotal_new, fdone_new, ptotal_new, pdone_new] = whole_state; | ||
|
||
if (ftotal != ftotal_new || fdone != fdone_new || ptotal != ptotal_new || pdone != pdone_new || text_new != text1) | ||
{ | ||
|
@@ -137,17 +149,20 @@ void progress_dialog_server::operator()() | |
|
||
if (!text_new) | ||
{ | ||
// Close dialog | ||
break; | ||
// Incomplete state | ||
continue; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why? |
||
} | ||
|
||
if (show_overlay_message) | ||
{ | ||
// Show a message instead | ||
if (g_cfg.misc.show_ppu_compilation_hint) | ||
// Show a message instead (if compilation period is estimated to be lengthy) | ||
const u64 passed = (get_system_time() - start_time); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This could've easily been optimized into another scope |
||
|
||
if (pdone < ptotal && g_cfg.misc.show_ppu_compilation_hint && (pdone ? (passed * (ptotal - pdone) / pdone) : (passed * (ptotal + 1))) >= 100'000) | ||
{ | ||
rsx::overlays::show_ppu_compile_notification(); | ||
} | ||
|
||
thread_ctrl::wait_for(10000); | ||
continue; | ||
} | ||
|
@@ -182,6 +197,12 @@ void progress_dialog_server::operator()() | |
}); | ||
} | ||
} | ||
// Leave only if total count is equal to done count | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why? |
||
else if (ftotal == fdone && ptotal == pdone && !text_new) | ||
{ | ||
// Complete state, empty message: close dialog | ||
break; | ||
} | ||
|
||
if (show_overlay_message) | ||
{ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And why should that make any difference?
It may change a nanosecond later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Before (race example in steps):
After:
Another example:
Before:
After:
TLDR: Thread-safety is a headache.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's purely random now, same as before, if this loop runs faster than the next change is supplied.
There's zero thread safety here.
You should've just used a struct with a mutex and call it a day.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No there is no race here now. The fact that SPU does not crash for games is a live example for it. GETLLAR is an atomic 128-byte load. This loop recheck is a technique to load atomicaly any amount of bytes without a mutex.