diff --git a/src/xenia/base/memory.h b/src/xenia/base/memory.h index 4188af763..bbcfec6e8 100644 --- a/src/xenia/base/memory.h +++ b/src/xenia/base/memory.h @@ -99,7 +99,7 @@ typedef void* FileMappingHandle; FileMappingHandle CreateFileMappingHandle(std::wstring path, size_t length, PageAccess access, bool commit); -void CloseFileMappingHandle(FileMappingHandle handle); +void CloseFileMappingHandle(FileMappingHandle handle, std::wstring path); void* MapFileView(FileMappingHandle handle, void* base_address, size_t length, PageAccess access, size_t file_offset); bool UnmapFileView(FileMappingHandle handle, void* base_address, size_t length); diff --git a/src/xenia/base/memory_posix.cc b/src/xenia/base/memory_posix.cc index 1e55f99d9..13484dd29 100644 --- a/src/xenia/base/memory_posix.cc +++ b/src/xenia/base/memory_posix.cc @@ -87,7 +87,8 @@ FileMappingHandle CreateFileMappingHandle(std::wstring path, size_t length, } oflag |= O_CREAT; - int ret = shm_open(xe::to_string(path).c_str(), oflag, 0777); + std::string full_path = "/" + xe::to_string(path); + int ret = shm_open(full_path.c_str(), oflag, 0777); if (ret > 0) { ftruncate64(ret, length); } @@ -95,8 +96,9 @@ FileMappingHandle CreateFileMappingHandle(std::wstring path, size_t length, return ret <= 0 ? nullptr : reinterpret_cast(ret); } -void CloseFileMappingHandle(FileMappingHandle handle) { - close(static_cast(reinterpret_cast(handle))); +void CloseFileMappingHandle(FileMappingHandle handle, std::wstring path) { + std::string full_path = "/" + xe::to_string(path); + shm_unlink(full_path.c_str()); } void* MapFileView(FileMappingHandle handle, void* base_address, size_t length, diff --git a/src/xenia/base/memory_win.cc b/src/xenia/base/memory_win.cc index 0113c5f6d..72fcb084b 100644 --- a/src/xenia/base/memory_win.cc +++ b/src/xenia/base/memory_win.cc @@ -146,12 +146,15 @@ FileMappingHandle CreateFileMappingHandle(std::wstring path, size_t length, PageAccess access, bool commit) { DWORD protect = ToWin32ProtectFlags(access) | (commit ? SEC_COMMIT : SEC_RESERVE); + std::wstring full_path = L"Local\\" + path; return CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, protect, static_cast(length >> 32), - static_cast(length), path.c_str()); + static_cast(length), full_path.c_str()); } -void CloseFileMappingHandle(FileMappingHandle handle) { CloseHandle(handle); } +void CloseFileMappingHandle(FileMappingHandle handle, std::wstring path) { + CloseHandle(handle); +} void* MapFileView(FileMappingHandle handle, void* base_address, size_t length, PageAccess access, size_t file_offset) { diff --git a/src/xenia/base/testing/memory_test.cc b/src/xenia/base/testing/memory_test.cc index 5433dc118..9083eef40 100644 --- a/src/xenia/base/testing/memory_test.cc +++ b/src/xenia/base/testing/memory_test.cc @@ -414,6 +414,55 @@ TEST_CASE("copy_and_swap_16_in_32_unaligned", "Copy and Swap") { REQUIRE(true == true); } +TEST_CASE("create_and_close_file_mapping", "Virtual Memory Mapping") { + auto memory = xe::memory::CreateFileMappingHandle( + L"test", 0x100, xe::memory::PageAccess::kReadWrite, false); + REQUIRE(memory); + xe::memory::CloseFileMappingHandle(memory, L"test"); +} + +TEST_CASE("map_view", "Virtual Memory Mapping") { + const size_t length = 0x100; + auto memory = xe::memory::CreateFileMappingHandle( + L"test", length, xe::memory::PageAccess::kReadWrite, false); + REQUIRE(memory); + + uintptr_t address = 0x100000000; + auto view = + xe::memory::MapFileView(memory, reinterpret_cast(address), length, + xe::memory::PageAccess::kReadWrite, 0); + REQUIRE(reinterpret_cast(view) == address); + + xe::memory::UnmapFileView(memory, reinterpret_cast(address), length); + xe::memory::CloseFileMappingHandle(memory, L"test"); +} + +TEST_CASE("read_write_view", "Virtual Memory Mapping") { + const size_t length = 0x100; + auto memory = xe::memory::CreateFileMappingHandle( + L"test", length, xe::memory::PageAccess::kReadWrite, false); + REQUIRE(memory); + + uintptr_t address = 0x100000000; + auto view = + xe::memory::MapFileView(memory, reinterpret_cast(address), length, + xe::memory::PageAccess::kReadWrite, 0); + REQUIRE(reinterpret_cast(view) == address); + + for (uint32_t i = 0; i < length; i += sizeof(uint8_t)) { + auto p_value = reinterpret_cast(address + i); + *p_value = i; + } + for (uint32_t i = 0; i < length; i += sizeof(uint8_t)) { + auto p_value = reinterpret_cast(address + i); + uint8_t value = *p_value; + REQUIRE(value == i); + } + + xe::memory::UnmapFileView(memory, reinterpret_cast(address), length); + xe::memory::CloseFileMappingHandle(memory, L"test"); +} + } // namespace test } // namespace base } // namespace xe diff --git a/src/xenia/cpu/backend/x64/x64_code_cache.cc b/src/xenia/cpu/backend/x64/x64_code_cache.cc index 021d51c62..57a2fd097 100644 --- a/src/xenia/cpu/backend/x64/x64_code_cache.cc +++ b/src/xenia/cpu/backend/x64/x64_code_cache.cc @@ -42,7 +42,7 @@ X64CodeCache::~X64CodeCache() { if (mapping_) { xe::memory::UnmapFileView(mapping_, generated_code_base_, kGeneratedCodeSize); - xe::memory::CloseFileMappingHandle(mapping_); + xe::memory::CloseFileMappingHandle(mapping_, file_name_); mapping_ = nullptr; } } @@ -61,7 +61,7 @@ bool X64CodeCache::Initialize() { } // Create mmap file. This allows us to share the code cache with the debugger. - file_name_ = std::wstring(L"Local\\xenia_code_cache_") + + file_name_ = std::wstring(L"xenia_code_cache_") + std::to_wstring(Clock::QueryHostTickCount()); mapping_ = xe::memory::CreateFileMappingHandle( file_name_, kGeneratedCodeSize, xe::memory::PageAccess::kExecuteReadWrite, diff --git a/src/xenia/kernel/util/shim_utils.h b/src/xenia/kernel/util/shim_utils.h index 60e7525c5..05c8ce2f8 100644 --- a/src/xenia/kernel/util/shim_utils.h +++ b/src/xenia/kernel/util/shim_utils.h @@ -147,7 +147,7 @@ class Param { protected: Param() : ordinal_(-1) {} - explicit Param(Init& init) : ordinal_(--init.ordinal) {} + explicit Param(Init& init) : ordinal_(init.ordinal++) {} template void LoadValue(Init& init, V* out_value) { @@ -518,10 +518,13 @@ xe::cpu::Export* RegisterExport(R (*fn)(Ps&...), const char* name, ++export_entry->function_data.call_count; Param::Init init = { ppc_context, - sizeof...(Ps), 0, }; - auto params = std::make_tuple(Ps(init)...); + // Using braces initializer instead of make_tuple because braces + // enforce execution order across compilers. + // The make_tuple order is undefined per the C++ standard and + // cause inconsitencies between msvc and clang. + std::tuple params = {Ps(init)...}; if (export_entry->tags & xe::cpu::ExportTag::kLog && (!(export_entry->tags & xe::cpu::ExportTag::kHighFrequency) || cvars::log_high_frequency_kernel_calls)) { @@ -553,9 +556,13 @@ xe::cpu::Export* RegisterExport(void (*fn)(Ps&...), const char* name, ++export_entry->function_data.call_count; Param::Init init = { ppc_context, - sizeof...(Ps), + 0, }; - auto params = std::make_tuple(Ps(init)...); + // Using braces initializer instead of make_tuple because braces + // enforce execution order across compilers. + // The make_tuple order is undefined per the C++ standard and + // cause inconsitencies between msvc and clang. + std::tuple params = {Ps(init)...}; if (export_entry->tags & xe::cpu::ExportTag::kLog && (!(export_entry->tags & xe::cpu::ExportTag::kHighFrequency) || cvars::log_high_frequency_kernel_calls)) { diff --git a/src/xenia/memory.cc b/src/xenia/memory.cc index cec4da18b..d3bad1240 100644 --- a/src/xenia/memory.cc +++ b/src/xenia/memory.cc @@ -112,7 +112,7 @@ Memory::~Memory() { // Unmap all views and close mapping. if (mapping_) { UnmapViews(); - xe::memory::CloseFileMappingHandle(mapping_); + xe::memory::CloseFileMappingHandle(mapping_, file_name_); mapping_base_ = nullptr; mapping_ = nullptr; } @@ -122,7 +122,7 @@ Memory::~Memory() { } bool Memory::Initialize() { - file_name_ = std::wstring(L"Local\\xenia_memory_") + + file_name_ = std::wstring(L"xenia_memory_") + std::to_wstring(Clock::QueryHostTickCount()); // Create main page file-backed mapping. This is all reserved but