From 17f3a114becf3ff99eb0bcff29f8938496aaa8c3 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Fri, 10 Apr 2020 16:57:15 +0300 Subject: [PATCH 1/2] Fat atomics: implement exchange() and compare_exchange() Also includes compare_and_swap() and compare_and_swap_test(). Also includes fixes for load(), store(), and atomic_op(). --- rpcs3/util/atomic.hpp | 55 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/rpcs3/util/atomic.hpp b/rpcs3/util/atomic.hpp index 5799b0db12d7..c400d3584213 100644 --- a/rpcs3/util/atomic.hpp +++ b/rpcs3/util/atomic.hpp @@ -1176,7 +1176,6 @@ class atomic_with_lock_bit static_assert(std::is_pointer_v == (BitWidth == 0), "BitWidth should be 0 for pointers"); static_assert(!std::is_pointer_v || (alignof(std::remove_pointer_t) >= 4), "Pointer type should have align 4 or more"); - // Use the most significant bit as a mutex atomic_t m_data; public: @@ -1255,7 +1254,6 @@ class atomic_with_lock_bit // Try to set dirty bit if not set already if (!m_data.compare_and_swap_test(old_val, old_val | c_dirty)) { - // Situation changed continue; } } @@ -1301,6 +1299,7 @@ class atomic_with_lock_bit { if (!m_data.compare_and_swap_test(old_val, old_val | c_dirty)) { + old_val = m_data.load(); continue; } } @@ -1313,6 +1312,11 @@ class atomic_with_lock_bit } void store(T value) + { + static_cast(exchange(value)); + } + + T exchange(T value) { type old_val = m_data.load(); @@ -1322,6 +1326,7 @@ class atomic_with_lock_bit { if (!m_data.compare_and_swap_test(old_val, old_val | c_dirty)) { + old_val = m_data.load(); continue; } } @@ -1329,6 +1334,51 @@ class atomic_with_lock_bit m_data.wait(old_val); old_val = m_data.load(); } + + return reinterpret_cast(clamp_value(old_val)); + } + + T compare_and_swap(T cmp, T exch) + { + static_cast(compare_exchange(cmp, exch)); + return cmp; + } + + bool compare_and_swap_test(T cmp, T exch) + { + return compare_exchange(cmp, exch); + } + + bool compare_exchange(T& cmp_and_old, T exch) + { + type old_val = m_data.load(); + type expected = clamp_value(reinterpret_cast(cmp_and_old)); + type new_val = clamp_value(reinterpret_cast(exch)); + + while (is_locked(old_val) || (old_val == expected && !m_data.compare_and_swap_test(expected, new_val))) [[unlikely]] + { + if (old_val == expected) + { + old_val = m_data.load(); + continue; + } + + if ((old_val & c_dirty) == 0) + { + if (!m_data.compare_and_swap_test(old_val, old_val | c_dirty)) + { + old_val = m_data.load(); + continue; + } + } + + m_data.wait(old_val); + old_val = m_data.load(); + } + + cmp_and_old = reinterpret_cast(clamp_value(old_val)); + + return clamp_value(old_val) == expected; } template > @@ -1345,6 +1395,7 @@ class atomic_with_lock_bit { if (!m_data.compare_and_swap_test(old, old | c_dirty)) { + old = m_data.load(); continue; } } From 5524cd1e757ef0a57dd896c6c5bc0e8fc6b8952f Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Sun, 12 Apr 2020 00:47:58 +0300 Subject: [PATCH 2/2] Improve TAR loader Don't overwrite unchanged files. Print error if failed to overwrite. This commit affects PS3 firmware installation. Trying to workaround a bug where some files cannot be overwritten. --- rpcs3/Loader/TAR.cpp | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/rpcs3/Loader/TAR.cpp b/rpcs3/Loader/TAR.cpp index 61849c39f63b..2d829c59b83c 100644 --- a/rpcs3/Loader/TAR.cpp +++ b/rpcs3/Loader/TAR.cpp @@ -114,9 +114,29 @@ bool tar_object::extract(std::string path, std::string ignore) { case '0': { + auto data = get_file(header.name).release(); + + if (fs::file prev{result}) + { + if (prev.to_vector() == static_cast>*>(data.get())->obj) + { + // Workaround: avoid overwriting existing data if it's the same. + tar_log.notice("TAR Loader: skipped existing file %s", header.name); + break; + } + } + fs::file file(result, fs::rewrite); - file.write(get_file(header.name).to_vector()); - break; + + if (file) + { + file.write(static_cast>*>(data.get())->obj); + tar_log.notice("TAR Loader: written file %s", header.name); + break; + } + + tar_log.error("TAR Loader: failed to write file %s (%s)", header.name, fs::g_tls_error); + return false; } case '5':