Просмотр исходного кода

core: memory: Ensure thread safe access when pages are rasterizer cached (#5206)

* core: memory: Ensure thread safe access when pages are rasterizer cached.
bunnei 5 лет назад
Родитель
Сommit
c8a4967c9d
1 измененных файлов с 40 добавлено и 12 удалено
  1. 40 12
      src/core/memory.cpp

+ 40 - 12
src/core/memory.cpp

@@ -4,6 +4,7 @@
 
 
 #include <algorithm>
 #include <algorithm>
 #include <cstring>
 #include <cstring>
+#include <mutex>
 #include <optional>
 #include <optional>
 #include <utility>
 #include <utility>
 
 
@@ -497,7 +498,21 @@ struct Memory::Impl {
         return CopyBlock(*system.CurrentProcess(), dest_addr, src_addr, size);
         return CopyBlock(*system.CurrentProcess(), dest_addr, src_addr, size);
     }
     }
 
 
+    struct PageEntry {
+        u8* const pointer;
+        const Common::PageType attribute;
+    };
+
+    PageEntry SafePageEntry(std::size_t base) const {
+        std::lock_guard lock{rasterizer_cache_guard};
+        return {
+            .pointer = current_page_table->pointers[base],
+            .attribute = current_page_table->attributes[base],
+        };
+    }
+
     void RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached) {
     void RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached) {
+        std::lock_guard lock{rasterizer_cache_guard};
         if (vaddr == 0) {
         if (vaddr == 0) {
             return;
             return;
         }
         }
@@ -630,16 +645,22 @@ struct Memory::Impl {
      */
      */
     template <typename T>
     template <typename T>
     T Read(const VAddr vaddr) {
     T Read(const VAddr vaddr) {
-        const u8* const page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS];
-        if (page_pointer != nullptr) {
-            // NOTE: Avoid adding any extra logic to this fast-path block
+        // Avoid adding any extra logic to this fast-path block
+        if (const u8* const pointer = current_page_table->pointers[vaddr >> PAGE_BITS]) {
             T value;
             T value;
-            std::memcpy(&value, &page_pointer[vaddr], sizeof(T));
+            std::memcpy(&value, &pointer[vaddr], sizeof(T));
             return value;
             return value;
         }
         }
 
 
-        const Common::PageType type = current_page_table->attributes[vaddr >> PAGE_BITS];
-        switch (type) {
+        // Otherwise, we need to grab the page with a lock, in case it is currently being modified
+        const auto entry = SafePageEntry(vaddr >> PAGE_BITS);
+        if (entry.pointer) {
+            T value;
+            std::memcpy(&value, &entry.pointer[vaddr], sizeof(T));
+            return value;
+        }
+
+        switch (entry.attribute) {
         case Common::PageType::Unmapped:
         case Common::PageType::Unmapped:
             LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:08X}", sizeof(T) * 8, vaddr);
             LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:08X}", sizeof(T) * 8, vaddr);
             return 0;
             return 0;
@@ -670,15 +691,21 @@ struct Memory::Impl {
      */
      */
     template <typename T>
     template <typename T>
     void Write(const VAddr vaddr, const T data) {
     void Write(const VAddr vaddr, const T data) {
-        u8* const page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS];
-        if (page_pointer != nullptr) {
-            // NOTE: Avoid adding any extra logic to this fast-path block
-            std::memcpy(&page_pointer[vaddr], &data, sizeof(T));
+        // Avoid adding any extra logic to this fast-path block
+        if (u8* const pointer = current_page_table->pointers[vaddr >> PAGE_BITS]) {
+            std::memcpy(&pointer[vaddr], &data, sizeof(T));
             return;
             return;
         }
         }
 
 
-        const Common::PageType type = current_page_table->attributes[vaddr >> PAGE_BITS];
-        switch (type) {
+        // Otherwise, we need to grab the page with a lock, in case it is currently being modified
+        const auto entry = SafePageEntry(vaddr >> PAGE_BITS);
+        if (entry.pointer) {
+            // Memory was mapped, we are done
+            std::memcpy(&entry.pointer[vaddr], &data, sizeof(T));
+            return;
+        }
+
+        switch (entry.attribute) {
         case Common::PageType::Unmapped:
         case Common::PageType::Unmapped:
             LOG_ERROR(HW_Memory, "Unmapped Write{} 0x{:08X} @ 0x{:016X}", sizeof(data) * 8,
             LOG_ERROR(HW_Memory, "Unmapped Write{} 0x{:08X} @ 0x{:016X}", sizeof(data) * 8,
                       static_cast<u32>(data), vaddr);
                       static_cast<u32>(data), vaddr);
@@ -756,6 +783,7 @@ struct Memory::Impl {
         return true;
         return true;
     }
     }
 
 
+    mutable std::mutex rasterizer_cache_guard;
     Common::PageTable* current_page_table = nullptr;
     Common::PageTable* current_page_table = nullptr;
     Core::System& system;
     Core::System& system;
 };
 };