Merge branch 'master' into vulkan

This commit is contained in:
Triang3l
2020-11-22 14:21:21 +03:00
11 changed files with 125 additions and 36 deletions

View File

@@ -18,6 +18,7 @@
#include "xenia/base/assert.h" #include "xenia/base/assert.h"
#include "xenia/base/byte_order.h" #include "xenia/base/byte_order.h"
#include "xenia/base/platform.h"
namespace xe { namespace xe {
namespace memory { namespace memory {
@@ -96,12 +97,21 @@ void AlignedFree(T* ptr) {
#endif // XE_COMPILER_MSVC #endif // XE_COMPILER_MSVC
} }
#if XE_PLATFORM_WIN32
// HANDLE.
typedef void* FileMappingHandle; typedef void* FileMappingHandle;
constexpr FileMappingHandle kFileMappingHandleInvalid = nullptr;
#else
// File descriptor.
typedef int FileMappingHandle;
constexpr FileMappingHandle kFileMappingHandleInvalid = -1;
#endif
FileMappingHandle CreateFileMappingHandle(const std::filesystem::path& path, FileMappingHandle CreateFileMappingHandle(const std::filesystem::path& path,
size_t length, PageAccess access, size_t length, PageAccess access,
bool commit); bool commit);
void CloseFileMappingHandle(FileMappingHandle handle); void CloseFileMappingHandle(FileMappingHandle handle,
const std::filesystem::path& path);
void* MapFileView(FileMappingHandle handle, void* base_address, size_t length, void* MapFileView(FileMappingHandle handle, void* base_address, size_t length,
PageAccess access, size_t file_offset); PageAccess access, size_t file_offset);
bool UnmapFileView(FileMappingHandle handle, void* base_address, size_t length); bool UnmapFileView(FileMappingHandle handle, void* base_address, size_t length);

View File

@@ -40,7 +40,13 @@ void* AllocFixed(void* base_address, size_t length,
AllocationType allocation_type, PageAccess access) { AllocationType allocation_type, PageAccess access) {
// mmap does not support reserve / commit, so ignore allocation_type. // mmap does not support reserve / commit, so ignore allocation_type.
uint32_t prot = ToPosixProtectFlags(access); uint32_t prot = ToPosixProtectFlags(access);
return mmap(base_address, length, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); void* result = mmap(base_address, length, prot,
MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
if (result == MAP_FAILED) {
return nullptr;
} else {
return result;
}
} }
bool DeallocFixed(void* base_address, size_t length, bool DeallocFixed(void* base_address, size_t length,
@@ -80,25 +86,28 @@ FileMappingHandle CreateFileMappingHandle(const std::filesystem::path& path,
assert_always(); assert_always();
return nullptr; return nullptr;
} }
oflag |= O_CREAT; oflag |= O_CREAT;
int ret = shm_open(path.c_str(), oflag, 0777); auto full_path = "/" / path;
if (ret > 0) { int ret = shm_open(full_path.c_str(), oflag, 0777);
ftruncate64(ret, length); if (ret < 0) {
return kFileMappingHandleInvalid;
} }
ftruncate64(ret, length);
return ret <= 0 ? nullptr : reinterpret_cast<FileMappingHandle>(ret); return ret;
} }
void CloseFileMappingHandle(FileMappingHandle handle) { void CloseFileMappingHandle(FileMappingHandle handle,
close((intptr_t)handle); const std::filesystem::path& path) {
close(handle);
auto full_path = "/" / path;
shm_unlink(full_path.c_str());
} }
void* MapFileView(FileMappingHandle handle, void* base_address, size_t length, void* MapFileView(FileMappingHandle handle, void* base_address, size_t length,
PageAccess access, size_t file_offset) { PageAccess access, size_t file_offset) {
uint32_t prot = ToPosixProtectFlags(access); uint32_t prot = ToPosixProtectFlags(access);
return mmap64(base_address, length, prot, MAP_PRIVATE | MAP_ANONYMOUS, return mmap64(base_address, length, prot, MAP_PRIVATE | MAP_ANONYMOUS, handle,
reinterpret_cast<intptr_t>(handle), file_offset); file_offset);
} }
bool UnmapFileView(FileMappingHandle handle, void* base_address, bool UnmapFileView(FileMappingHandle handle, void* base_address,

View File

@@ -147,12 +147,16 @@ FileMappingHandle CreateFileMappingHandle(const std::filesystem::path& path,
bool commit) { bool commit) {
DWORD protect = DWORD protect =
ToWin32ProtectFlags(access) | (commit ? SEC_COMMIT : SEC_RESERVE); ToWin32ProtectFlags(access) | (commit ? SEC_COMMIT : SEC_RESERVE);
auto full_path = "Local" / path;
return CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, protect, return CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, protect,
static_cast<DWORD>(length >> 32), static_cast<DWORD>(length >> 32),
static_cast<DWORD>(length), path.c_str()); static_cast<DWORD>(length), full_path.c_str());
} }
void CloseFileMappingHandle(FileMappingHandle handle) { CloseHandle(handle); } void CloseFileMappingHandle(FileMappingHandle handle,
const std::filesystem::path& path) {
CloseHandle(handle);
}
void* MapFileView(FileMappingHandle handle, void* base_address, size_t length, void* MapFileView(FileMappingHandle handle, void* base_address, size_t length,
PageAccess access, size_t file_offset) { PageAccess access, size_t file_offset) {

View File

@@ -10,6 +10,9 @@
#include "xenia/base/memory.h" #include "xenia/base/memory.h"
#include "third_party/catch/include/catch.hpp" #include "third_party/catch/include/catch.hpp"
#include "third_party/fmt/include/fmt/format.h"
#include "xenia/base/clock.h"
namespace xe { namespace xe {
namespace base { namespace base {
@@ -414,6 +417,58 @@ TEST_CASE("copy_and_swap_16_in_32_unaligned", "Copy and Swap") {
REQUIRE(true == true); REQUIRE(true == true);
} }
TEST_CASE("create_and_close_file_mapping", "Virtual Memory Mapping") {
auto path = fmt::format("xenia_test_{}", Clock::QueryHostTickCount());
auto memory = xe::memory::CreateFileMappingHandle(
path, 0x100, xe::memory::PageAccess::kReadWrite, true);
REQUIRE(memory != xe::memory::FileMappingHandleInvalid);
xe::memory::CloseFileMappingHandle(memory, path);
}
TEST_CASE("map_view", "Virtual Memory Mapping") {
auto path = fmt::format("xenia_test_{}", Clock::QueryHostTickCount());
const size_t length = 0x100;
auto memory = xe::memory::CreateFileMappingHandle(
path, length, xe::memory::PageAccess::kReadWrite, true);
REQUIRE(memory != xe::memory::FileMappingHandleInvalid);
uintptr_t address = 0x100000000;
auto view =
xe::memory::MapFileView(memory, reinterpret_cast<void*>(address), length,
xe::memory::PageAccess::kReadWrite, 0);
REQUIRE(reinterpret_cast<uintptr_t>(view) == address);
xe::memory::UnmapFileView(memory, reinterpret_cast<void*>(address), length);
xe::memory::CloseFileMappingHandle(memory, path);
}
TEST_CASE("read_write_view", "Virtual Memory Mapping") {
const size_t length = 0x100;
auto path = fmt::format("xenia_test_{}", Clock::QueryHostTickCount());
auto memory = xe::memory::CreateFileMappingHandle(
path, length, xe::memory::PageAccess::kReadWrite, true);
REQUIRE(memory != xe::memory::FileMappingHandleInvalid);
uintptr_t address = 0x100000000;
auto view =
xe::memory::MapFileView(memory, reinterpret_cast<void*>(address), length,
xe::memory::PageAccess::kReadWrite, 0);
REQUIRE(reinterpret_cast<uintptr_t>(view) == address);
for (uint32_t i = 0; i < length; i += sizeof(uint8_t)) {
auto p_value = reinterpret_cast<uint8_t*>(address + i);
*p_value = i;
}
for (uint32_t i = 0; i < length; i += sizeof(uint8_t)) {
auto p_value = reinterpret_cast<uint8_t*>(address + i);
uint8_t value = *p_value;
REQUIRE(value == i);
}
xe::memory::UnmapFileView(memory, reinterpret_cast<void*>(address), length);
xe::memory::CloseFileMappingHandle(memory, path);
}
} // namespace test } // namespace test
} // namespace base } // namespace base
} // namespace xe } // namespace xe

View File

@@ -813,7 +813,7 @@ TEST_CASE("Create and Run Thread", "Thread") {
result = Wait(Thread::GetCurrentThread(), false, 50ms); result = Wait(Thread::GetCurrentThread(), false, 50ms);
REQUIRE(result == WaitResult::kTimeout); REQUIRE(result == WaitResult::kTimeout);
params.stack_size = 16 * 1024; params.stack_size = 16 * 1024 * 1024;
thread = Thread::Create(params, [] { thread = Thread::Create(params, [] {
while (true) { while (true) {
Thread::Exit(-1); Thread::Exit(-1);

View File

@@ -505,6 +505,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
} }
} }
if (pthread_create(&thread_, &attr, ThreadStartRoutine, start_data) != 0) { if (pthread_create(&thread_, &attr, ThreadStartRoutine, start_data) != 0) {
pthread_attr_destroy(&attr);
return false; return false;
} }
pthread_attr_destroy(&attr); pthread_attr_destroy(&attr);
@@ -1006,7 +1007,10 @@ Thread* Thread::GetCurrentThread() {
pthread_t handle = pthread_self(); pthread_t handle = pthread_self();
current_thread_ = new PosixThread(handle); current_thread_ = new PosixThread(handle);
atexit([] { delete current_thread_; }); // TODO(bwrsandman): Disabling deleting thread_local current thread to prevent
// assert in destructor. Since this is thread local, the
// "memory leaking" is controlled.
// atexit([] { delete current_thread_; });
return current_thread_; return current_thread_;
} }

View File

@@ -40,11 +40,11 @@ X64CodeCache::~X64CodeCache() {
} }
// Unmap all views and close mapping. // Unmap all views and close mapping.
if (mapping_) { if (mapping_ != xe::memory::kFileMappingHandleInvalid) {
xe::memory::UnmapFileView(mapping_, generated_code_base_, xe::memory::UnmapFileView(mapping_, generated_code_base_,
kGeneratedCodeSize); kGeneratedCodeSize);
xe::memory::CloseFileMappingHandle(mapping_); xe::memory::CloseFileMappingHandle(mapping_, file_name_);
mapping_ = nullptr; mapping_ = xe::memory::kFileMappingHandleInvalid;
} }
} }
@@ -63,12 +63,11 @@ bool X64CodeCache::Initialize() {
} }
// Create mmap file. This allows us to share the code cache with the debugger. // Create mmap file. This allows us to share the code cache with the debugger.
file_name_ = file_name_ = fmt::format("xenia_code_cache_{}", Clock::QueryHostTickCount());
fmt::format("Local\\xenia_code_cache_{}", Clock::QueryHostTickCount());
mapping_ = xe::memory::CreateFileMappingHandle( mapping_ = xe::memory::CreateFileMappingHandle(
file_name_, kGeneratedCodeSize, xe::memory::PageAccess::kExecuteReadWrite, file_name_, kGeneratedCodeSize, xe::memory::PageAccess::kExecuteReadWrite,
false); false);
if (!mapping_) { if (mapping_ == xe::memory::kFileMappingHandleInvalid) {
XELOGE("Unable to create code cache mmap"); XELOGE("Unable to create code cache mmap");
return false; return false;
} }

View File

@@ -100,7 +100,8 @@ class X64CodeCache : public CodeCache {
UnwindReservation unwind_reservation) {} UnwindReservation unwind_reservation) {}
std::filesystem::path file_name_; std::filesystem::path file_name_;
xe::memory::FileMappingHandle mapping_ = nullptr; xe::memory::FileMappingHandle mapping_ =
xe::memory::kFileMappingHandleInvalid;
// NOTE: the global critical region must be held when manipulating the offsets // NOTE: the global critical region must be held when manipulating the offsets
// or counts of anything, to keep the tables consistent and ordered. // or counts of anything, to keep the tables consistent and ordered.

View File

@@ -148,7 +148,7 @@ class Param {
protected: protected:
Param() : ordinal_(-1) {} Param() : ordinal_(-1) {}
explicit Param(Init& init) : ordinal_(--init.ordinal) {} explicit Param(Init& init) : ordinal_(init.ordinal++) {}
template <typename V> template <typename V>
void LoadValue(Init& init, V* out_value) { void LoadValue(Init& init, V* out_value) {
@@ -519,10 +519,13 @@ xe::cpu::Export* RegisterExport(R (*fn)(Ps&...), const char* name,
++export_entry->function_data.call_count; ++export_entry->function_data.call_count;
Param::Init init = { Param::Init init = {
ppc_context, ppc_context,
sizeof...(Ps),
0, 0,
}; };
auto params = std::make_tuple<Ps...>(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<Ps...> params = {Ps(init)...};
if (export_entry->tags & xe::cpu::ExportTag::kLog && if (export_entry->tags & xe::cpu::ExportTag::kLog &&
(!(export_entry->tags & xe::cpu::ExportTag::kHighFrequency) || (!(export_entry->tags & xe::cpu::ExportTag::kHighFrequency) ||
cvars::log_high_frequency_kernel_calls)) { cvars::log_high_frequency_kernel_calls)) {
@@ -554,9 +557,13 @@ xe::cpu::Export* RegisterExport(void (*fn)(Ps&...), const char* name,
++export_entry->function_data.call_count; ++export_entry->function_data.call_count;
Param::Init init = { Param::Init init = {
ppc_context, ppc_context,
sizeof...(Ps), 0,
}; };
auto params = std::make_tuple<Ps...>(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<Ps...> params = {Ps(init)...};
if (export_entry->tags & xe::cpu::ExportTag::kLog && if (export_entry->tags & xe::cpu::ExportTag::kLog &&
(!(export_entry->tags & xe::cpu::ExportTag::kHighFrequency) || (!(export_entry->tags & xe::cpu::ExportTag::kHighFrequency) ||
cvars::log_high_frequency_kernel_calls)) { cvars::log_high_frequency_kernel_calls)) {

View File

@@ -113,11 +113,11 @@ Memory::~Memory() {
heaps_.physical.Dispose(); heaps_.physical.Dispose();
// Unmap all views and close mapping. // Unmap all views and close mapping.
if (mapping_) { if (mapping_ != xe::memory::kFileMappingHandleInvalid) {
UnmapViews(); UnmapViews();
xe::memory::CloseFileMappingHandle(mapping_); xe::memory::CloseFileMappingHandle(mapping_, file_name_);
mapping_base_ = nullptr; mapping_base_ = nullptr;
mapping_ = nullptr; mapping_ = xe::memory::kFileMappingHandleInvalid;
} }
virtual_membase_ = nullptr; virtual_membase_ = nullptr;
@@ -125,8 +125,7 @@ Memory::~Memory() {
} }
bool Memory::Initialize() { bool Memory::Initialize() {
file_name_ = file_name_ = fmt::format("xenia_memory_{}", Clock::QueryHostTickCount());
fmt::format("Local\\xenia_memory_{}", Clock::QueryHostTickCount());
// Create main page file-backed mapping. This is all reserved but // Create main page file-backed mapping. This is all reserved but
// uncommitted (so it shouldn't expand page file). // uncommitted (so it shouldn't expand page file).
@@ -134,9 +133,9 @@ bool Memory::Initialize() {
file_name_, file_name_,
// entire 4gb space + 512mb physical: // entire 4gb space + 512mb physical:
0x11FFFFFFF, xe::memory::PageAccess::kReadWrite, false); 0x11FFFFFFF, xe::memory::PageAccess::kReadWrite, false);
if (!mapping_) { if (mapping_ == xe::memory::kFileMappingHandleInvalid) {
XELOGE("Unable to reserve the 4gb guest address space."); XELOGE("Unable to reserve the 4gb guest address space.");
assert_not_null(mapping_); assert_always();
return false; return false;
} }

View File

@@ -491,7 +491,8 @@ class Memory {
uint8_t* virtual_membase_ = nullptr; uint8_t* virtual_membase_ = nullptr;
uint8_t* physical_membase_ = nullptr; uint8_t* physical_membase_ = nullptr;
xe::memory::FileMappingHandle mapping_ = nullptr; xe::memory::FileMappingHandle mapping_ =
xe::memory::kFileMappingHandleInvalid;
uint8_t* mapping_base_ = nullptr; uint8_t* mapping_base_ = nullptr;
union { union {
struct { struct {