mirror of
https://github.com/WinampDesktop/winamp.git
synced 2025-04-28 12:45:42 -04:00
System: Add advanced 'Export Shared Memory' option
Memory map is exported as duckstation_<pid>. Previously, this only worked on Windows, now it is extended to Linux as well.
This commit is contained in:
parent
c538df317a
commit
02fbfae6a0
@ -85,6 +85,7 @@ static bool WriteMinidump(HMODULE hDbgHelp, HANDLE hFile, HANDLE hProcess, DWORD
|
|||||||
|
|
||||||
static std::wstring s_write_directory;
|
static std::wstring s_write_directory;
|
||||||
static DynamicLibrary s_dbghelp_module;
|
static DynamicLibrary s_dbghelp_module;
|
||||||
|
static CrashHandler::CleanupHandler s_cleanup_handler;
|
||||||
static bool s_in_crash_handler = false;
|
static bool s_in_crash_handler = false;
|
||||||
|
|
||||||
static void GenerateCrashFilename(wchar_t* buf, size_t len, const wchar_t* prefix, const wchar_t* extension)
|
static void GenerateCrashFilename(wchar_t* buf, size_t len, const wchar_t* prefix, const wchar_t* extension)
|
||||||
@ -99,8 +100,6 @@ static void GenerateCrashFilename(wchar_t* buf, size_t len, const wchar_t* prefi
|
|||||||
|
|
||||||
static void WriteMinidumpAndCallstack(PEXCEPTION_POINTERS exi)
|
static void WriteMinidumpAndCallstack(PEXCEPTION_POINTERS exi)
|
||||||
{
|
{
|
||||||
s_in_crash_handler = true;
|
|
||||||
|
|
||||||
wchar_t filename[1024] = {};
|
wchar_t filename[1024] = {};
|
||||||
GenerateCrashFilename(filename, std::size(filename), s_write_directory.empty() ? nullptr : s_write_directory.c_str(),
|
GenerateCrashFilename(filename, std::size(filename), s_write_directory.empty() ? nullptr : s_write_directory.c_str(),
|
||||||
L"txt");
|
L"txt");
|
||||||
@ -148,7 +147,13 @@ static LONG NTAPI ExceptionHandler(PEXCEPTION_POINTERS exi)
|
|||||||
{
|
{
|
||||||
// if the debugger is attached, or we're recursively crashing, let it take care of it.
|
// if the debugger is attached, or we're recursively crashing, let it take care of it.
|
||||||
if (!s_in_crash_handler)
|
if (!s_in_crash_handler)
|
||||||
|
{
|
||||||
|
s_in_crash_handler = true;
|
||||||
|
if (s_cleanup_handler)
|
||||||
|
s_cleanup_handler();
|
||||||
|
|
||||||
WriteMinidumpAndCallstack(exi);
|
WriteMinidumpAndCallstack(exi);
|
||||||
|
}
|
||||||
|
|
||||||
// returning EXCEPTION_CONTINUE_SEARCH makes sense, except for the fact that it seems to leave zombie processes
|
// returning EXCEPTION_CONTINUE_SEARCH makes sense, except for the fact that it seems to leave zombie processes
|
||||||
// around. instead, force ourselves to terminate.
|
// around. instead, force ourselves to terminate.
|
||||||
@ -156,7 +161,7 @@ static LONG NTAPI ExceptionHandler(PEXCEPTION_POINTERS exi)
|
|||||||
return EXCEPTION_CONTINUE_SEARCH;
|
return EXCEPTION_CONTINUE_SEARCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CrashHandler::Install()
|
bool CrashHandler::Install(CleanupHandler cleanup_handler)
|
||||||
{
|
{
|
||||||
// load dbghelp at install/startup, that way we're not LoadLibrary()'ing after a crash
|
// load dbghelp at install/startup, that way we're not LoadLibrary()'ing after a crash
|
||||||
// .. because that probably wouldn't go down well.
|
// .. because that probably wouldn't go down well.
|
||||||
@ -165,6 +170,7 @@ bool CrashHandler::Install()
|
|||||||
s_dbghelp_module.Adopt(mod);
|
s_dbghelp_module.Adopt(mod);
|
||||||
|
|
||||||
SetUnhandledExceptionFilter(ExceptionHandler);
|
SetUnhandledExceptionFilter(ExceptionHandler);
|
||||||
|
s_cleanup_handler = cleanup_handler;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,6 +214,7 @@ static void LogCallstack(int signal, const void* exception_pc);
|
|||||||
static std::recursive_mutex s_crash_mutex;
|
static std::recursive_mutex s_crash_mutex;
|
||||||
static bool s_in_signal_handler = false;
|
static bool s_in_signal_handler = false;
|
||||||
|
|
||||||
|
static CleanupHandler s_cleanup_handler;
|
||||||
static backtrace_state* s_backtrace_state = nullptr;
|
static backtrace_state* s_backtrace_state = nullptr;
|
||||||
} // namespace CrashHandler
|
} // namespace CrashHandler
|
||||||
|
|
||||||
@ -304,6 +311,9 @@ void CrashHandler::CrashSignalHandler(int signal, siginfo_t* siginfo, void* ctx)
|
|||||||
{
|
{
|
||||||
s_in_signal_handler = true;
|
s_in_signal_handler = true;
|
||||||
|
|
||||||
|
if (s_cleanup_handler)
|
||||||
|
s_cleanup_handler();
|
||||||
|
|
||||||
#if defined(__APPLE__) && defined(__x86_64__)
|
#if defined(__APPLE__) && defined(__x86_64__)
|
||||||
void* const exception_pc = reinterpret_cast<void*>(static_cast<ucontext_t*>(ctx)->uc_mcontext->__ss.__rip);
|
void* const exception_pc = reinterpret_cast<void*>(static_cast<ucontext_t*>(ctx)->uc_mcontext->__ss.__rip);
|
||||||
#elif defined(__FreeBSD__) && defined(__x86_64__)
|
#elif defined(__FreeBSD__) && defined(__x86_64__)
|
||||||
@ -327,7 +337,7 @@ void CrashHandler::CrashSignalHandler(int signal, siginfo_t* siginfo, void* ctx)
|
|||||||
std::abort();
|
std::abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CrashHandler::Install()
|
bool CrashHandler::Install(CleanupHandler cleanup_handler)
|
||||||
{
|
{
|
||||||
const std::string progpath = FileSystem::GetProgramPath();
|
const std::string progpath = FileSystem::GetProgramPath();
|
||||||
s_backtrace_state = backtrace_create_state(progpath.empty() ? nullptr : progpath.c_str(), 0, nullptr, nullptr);
|
s_backtrace_state = backtrace_create_state(progpath.empty() ? nullptr : progpath.c_str(), 0, nullptr, nullptr);
|
||||||
@ -344,6 +354,7 @@ bool CrashHandler::Install()
|
|||||||
if (sigaction(SIGSEGV, &sa, nullptr) != 0)
|
if (sigaction(SIGSEGV, &sa, nullptr) != 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
s_cleanup_handler = cleanup_handler;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -358,7 +369,7 @@ void CrashHandler::WriteDumpForCaller()
|
|||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
bool CrashHandler::Install()
|
bool CrashHandler::Install(CleanupHandler cleanup_handler)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
||||||
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
||||||
|
|
||||||
#include "types.h"
|
#pragma once
|
||||||
|
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
@ -9,13 +10,21 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace CrashHandler {
|
namespace CrashHandler {
|
||||||
bool Install();
|
|
||||||
|
/// Adds a callback to run just before the crash handler exits.
|
||||||
|
/// It's not guaranteed that this handler will actually run, because the process state could be very messed up by this
|
||||||
|
/// point. It's mainly a thing so that we can free up the shared memory object if there was one created.
|
||||||
|
using CleanupHandler = void(*)();
|
||||||
|
|
||||||
|
bool Install(CleanupHandler cleanup_handler);
|
||||||
void SetWriteDirectory(std::string_view dump_directory);
|
void SetWriteDirectory(std::string_view dump_directory);
|
||||||
void WriteDumpForCaller();
|
void WriteDumpForCaller();
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
|
|
||||||
// Allow crash handler to be invoked from a signal.
|
// Allow crash handler to be invoked from a signal.
|
||||||
void CrashSignalHandler(int signal, siginfo_t* siginfo, void* ctx);
|
void CrashSignalHandler(int signal, siginfo_t* siginfo, void* ctx);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} // namespace CrashHandler
|
} // namespace CrashHandler
|
||||||
|
@ -66,9 +66,10 @@ std::string MemMap::GetFileMappingName(const char* prefix)
|
|||||||
|
|
||||||
void* MemMap::CreateSharedMemory(const char* name, size_t size, Error* error)
|
void* MemMap::CreateSharedMemory(const char* name, size_t size, Error* error)
|
||||||
{
|
{
|
||||||
|
const std::wstring mapping_name = name ? StringUtil::UTF8StringToWideString(name) : std::wstring();
|
||||||
const HANDLE mapping =
|
const HANDLE mapping =
|
||||||
CreateFileMappingW(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, static_cast<DWORD>(size >> 32),
|
CreateFileMappingW(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, static_cast<DWORD>(size >> 32),
|
||||||
static_cast<DWORD>(size), StringUtil::UTF8StringToWideString(name).c_str());
|
static_cast<DWORD>(size), mapping_name.empty() ? nullptr : mapping_name.c_str());
|
||||||
if (!mapping)
|
if (!mapping)
|
||||||
Error::SetWin32(error, "CreateFileMappingW() failed: ", GetLastError());
|
Error::SetWin32(error, "CreateFileMappingW() failed: ", GetLastError());
|
||||||
|
|
||||||
@ -80,6 +81,11 @@ void MemMap::DestroySharedMemory(void* ptr)
|
|||||||
CloseHandle(static_cast<HANDLE>(ptr));
|
CloseHandle(static_cast<HANDLE>(ptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MemMap::DeleteSharedMemory(const char* name)
|
||||||
|
{
|
||||||
|
// Automatically freed on close.
|
||||||
|
}
|
||||||
|
|
||||||
void* MemMap::MapSharedMemory(void* handle, size_t offset, void* baseaddr, size_t size, PageProtect mode)
|
void* MemMap::MapSharedMemory(void* handle, size_t offset, void* baseaddr, size_t size, PageProtect mode)
|
||||||
{
|
{
|
||||||
void* ret = MapViewOfFileEx(static_cast<HANDLE>(handle), FILE_MAP_READ | FILE_MAP_WRITE,
|
void* ret = MapViewOfFileEx(static_cast<HANDLE>(handle), FILE_MAP_READ | FILE_MAP_WRITE,
|
||||||
@ -374,6 +380,10 @@ void MemMap::DestroySharedMemory(void* ptr)
|
|||||||
mach_port_deallocate(mach_task_self(), static_cast<mach_port_t>(reinterpret_cast<uintptr_t>(ptr)));
|
mach_port_deallocate(mach_task_self(), static_cast<mach_port_t>(reinterpret_cast<uintptr_t>(ptr)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MemMap::DeleteSharedMemory(const char* name)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void* MemMap::MapSharedMemory(void* handle, size_t offset, void* baseaddr, size_t size, PageProtect mode)
|
void* MemMap::MapSharedMemory(void* handle, size_t offset, void* baseaddr, size_t size, PageProtect mode)
|
||||||
{
|
{
|
||||||
mach_vm_address_t ptr = reinterpret_cast<mach_vm_address_t>(baseaddr);
|
mach_vm_address_t ptr = reinterpret_cast<mach_vm_address_t>(baseaddr);
|
||||||
@ -617,15 +627,25 @@ std::string MemMap::GetFileMappingName(const char* prefix)
|
|||||||
|
|
||||||
void* MemMap::CreateSharedMemory(const char* name, size_t size, Error* error)
|
void* MemMap::CreateSharedMemory(const char* name, size_t size, Error* error)
|
||||||
{
|
{
|
||||||
|
const bool is_anonymous = (!name || *name == 0);
|
||||||
|
#if defined(__linux__) || defined(__FreeBSD__)
|
||||||
|
const int fd = is_anonymous ? memfd_create("", 0) : shm_open(name, O_CREAT | O_EXCL | O_RDWR, 0600);
|
||||||
|
if (fd < 0)
|
||||||
|
{
|
||||||
|
Error::SetErrno(error, is_anonymous ? "memfd_create() failed: " : "shm_open() failed: ", errno);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
#else
|
||||||
const int fd = shm_open(name, O_CREAT | O_EXCL | O_RDWR, 0600);
|
const int fd = shm_open(name, O_CREAT | O_EXCL | O_RDWR, 0600);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
{
|
{
|
||||||
Error::SetErrno(error, "shm_open failed: ", errno);
|
Error::SetErrno(error, "shm_open() failed: ", errno);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// we're not going to be opening this mapping in other processes, so remove the file
|
// we're not going to be opening this mapping in other processes, so remove the file
|
||||||
shm_unlink(name);
|
shm_unlink(name);
|
||||||
|
#endif
|
||||||
|
|
||||||
// use fallocate() to ensure we don't SIGBUS later on.
|
// use fallocate() to ensure we don't SIGBUS later on.
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
@ -651,6 +671,11 @@ void MemMap::DestroySharedMemory(void* ptr)
|
|||||||
close(static_cast<int>(reinterpret_cast<intptr_t>(ptr)));
|
close(static_cast<int>(reinterpret_cast<intptr_t>(ptr)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MemMap::DeleteSharedMemory(const char* name)
|
||||||
|
{
|
||||||
|
shm_unlink(name);
|
||||||
|
}
|
||||||
|
|
||||||
void* MemMap::MapSharedMemory(void* handle, size_t offset, void* baseaddr, size_t size, PageProtect mode)
|
void* MemMap::MapSharedMemory(void* handle, size_t offset, void* baseaddr, size_t size, PageProtect mode)
|
||||||
{
|
{
|
||||||
const int flags = (baseaddr != nullptr) ? (MAP_SHARED | MAP_FIXED) : MAP_SHARED;
|
const int flags = (baseaddr != nullptr) ? (MAP_SHARED | MAP_FIXED) : MAP_SHARED;
|
||||||
|
@ -53,6 +53,7 @@ class Error;
|
|||||||
namespace MemMap {
|
namespace MemMap {
|
||||||
std::string GetFileMappingName(const char* prefix);
|
std::string GetFileMappingName(const char* prefix);
|
||||||
void* CreateSharedMemory(const char* name, size_t size, Error* error);
|
void* CreateSharedMemory(const char* name, size_t size, Error* error);
|
||||||
|
void DeleteSharedMemory(const char* name);
|
||||||
void DestroySharedMemory(void* ptr);
|
void DestroySharedMemory(void* ptr);
|
||||||
void* MapSharedMemory(void* handle, size_t offset, void* baseaddr, size_t size, PageProtect mode);
|
void* MapSharedMemory(void* handle, size_t offset, void* baseaddr, size_t size, PageProtect mode);
|
||||||
void UnmapSharedMemory(void* baseaddr, size_t size);
|
void UnmapSharedMemory(void* baseaddr, size_t size);
|
||||||
|
123
src/core/bus.cpp
123
src/core/bus.cpp
@ -118,6 +118,7 @@ union RAM_SIZE_REG
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
static void* s_shmem_handle = nullptr;
|
static void* s_shmem_handle = nullptr;
|
||||||
|
static std::string s_shmem_name;
|
||||||
|
|
||||||
std::bitset<RAM_8MB_CODE_PAGE_COUNT> g_ram_code_bits{};
|
std::bitset<RAM_8MB_CODE_PAGE_COUNT> g_ram_code_bits{};
|
||||||
u8* g_ram = nullptr;
|
u8* g_ram = nullptr;
|
||||||
@ -153,6 +154,8 @@ static u8** s_fastmem_lut = nullptr;
|
|||||||
|
|
||||||
static bool s_kernel_initialize_hook_run = false;
|
static bool s_kernel_initialize_hook_run = false;
|
||||||
|
|
||||||
|
static bool AllocateMemoryMap(Error* error);
|
||||||
|
static void ReleaseMemoryMap();
|
||||||
static void SetRAMSize(bool enable_8mb_ram);
|
static void SetRAMSize(bool enable_8mb_ram);
|
||||||
|
|
||||||
static std::tuple<TickCount, TickCount, TickCount> CalculateMemoryTiming(MEMDELAY mem_delay, COMDELAY common_delay);
|
static std::tuple<TickCount, TickCount, TickCount> CalculateMemoryTiming(MEMDELAY mem_delay, COMDELAY common_delay);
|
||||||
@ -194,10 +197,12 @@ static constexpr size_t TOTAL_SIZE = LUT_OFFSET + LUT_SIZE;
|
|||||||
#define FIXUP_WORD_WRITE_VALUE(size, offset, value) \
|
#define FIXUP_WORD_WRITE_VALUE(size, offset, value) \
|
||||||
((size == MemoryAccessSize::Word) ? (value) : ((value) << (((offset) & 3u) * 8)))
|
((size == MemoryAccessSize::Word) ? (value) : ((value) << (((offset) & 3u) * 8)))
|
||||||
|
|
||||||
bool Bus::AllocateMemory(Error* error)
|
bool Bus::AllocateMemoryMap(Error* error)
|
||||||
{
|
{
|
||||||
s_shmem_handle =
|
// This executes super early in process startup, therefore export_shared_memory will always be false.
|
||||||
MemMap::CreateSharedMemory(MemMap::GetFileMappingName("duckstation").c_str(), MemoryMap::TOTAL_SIZE, error);
|
if (g_settings.export_shared_memory)
|
||||||
|
s_shmem_name = MemMap::GetFileMappingName("duckstation");
|
||||||
|
s_shmem_handle = MemMap::CreateSharedMemory(s_shmem_name.c_str(), MemoryMap::TOTAL_SIZE, error);
|
||||||
if (!s_shmem_handle)
|
if (!s_shmem_handle)
|
||||||
{
|
{
|
||||||
#ifndef __linux__
|
#ifndef __linux__
|
||||||
@ -216,7 +221,7 @@ bool Bus::AllocateMemory(Error* error)
|
|||||||
if (!g_ram || !g_unprotected_ram)
|
if (!g_ram || !g_unprotected_ram)
|
||||||
{
|
{
|
||||||
Error::SetStringView(error, "Failed to map memory for RAM");
|
Error::SetStringView(error, "Failed to map memory for RAM");
|
||||||
ReleaseMemory();
|
ReleaseMemoryMap();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,7 +232,7 @@ bool Bus::AllocateMemory(Error* error)
|
|||||||
if (!g_bios)
|
if (!g_bios)
|
||||||
{
|
{
|
||||||
Error::SetStringView(error, "Failed to map memory for BIOS");
|
Error::SetStringView(error, "Failed to map memory for BIOS");
|
||||||
ReleaseMemory();
|
ReleaseMemoryMap();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,7 +243,7 @@ bool Bus::AllocateMemory(Error* error)
|
|||||||
if (!g_memory_handlers)
|
if (!g_memory_handlers)
|
||||||
{
|
{
|
||||||
Error::SetStringView(error, "Failed to map memory for LUTs");
|
Error::SetStringView(error, "Failed to map memory for LUTs");
|
||||||
ReleaseMemory();
|
ReleaseMemoryMap();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -246,17 +251,6 @@ bool Bus::AllocateMemory(Error* error)
|
|||||||
g_memory_handlers_isc = g_memory_handlers + MEMORY_LUT_SLOTS;
|
g_memory_handlers_isc = g_memory_handlers + MEMORY_LUT_SLOTS;
|
||||||
SetHandlers();
|
SetHandlers();
|
||||||
|
|
||||||
#ifdef ENABLE_MMAP_FASTMEM
|
|
||||||
if (!s_fastmem_arena.Create(FASTMEM_ARENA_SIZE))
|
|
||||||
{
|
|
||||||
Error::SetStringView(error, "Failed to create fastmem arena");
|
|
||||||
ReleaseMemory();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
INFO_LOG("Fastmem base: {}", static_cast<void*>(s_fastmem_arena.BasePointer()));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef __ANDROID__
|
#ifndef __ANDROID__
|
||||||
Exports::RAM = reinterpret_cast<uintptr_t>(g_unprotected_ram);
|
Exports::RAM = reinterpret_cast<uintptr_t>(g_unprotected_ram);
|
||||||
#endif
|
#endif
|
||||||
@ -264,7 +258,7 @@ bool Bus::AllocateMemory(Error* error)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bus::ReleaseMemory()
|
void Bus::ReleaseMemoryMap()
|
||||||
{
|
{
|
||||||
#ifndef __ANDROID__
|
#ifndef __ANDROID__
|
||||||
Exports::RAM = 0;
|
Exports::RAM = 0;
|
||||||
@ -272,14 +266,6 @@ void Bus::ReleaseMemory()
|
|||||||
Exports::RAM_MASK = 0;
|
Exports::RAM_MASK = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ENABLE_MMAP_FASTMEM
|
|
||||||
DebugAssert(s_fastmem_ram_views.empty());
|
|
||||||
s_fastmem_arena.Destroy();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
std::free(s_fastmem_lut);
|
|
||||||
s_fastmem_lut = nullptr;
|
|
||||||
|
|
||||||
g_memory_handlers_isc = nullptr;
|
g_memory_handlers_isc = nullptr;
|
||||||
if (g_memory_handlers)
|
if (g_memory_handlers)
|
||||||
{
|
{
|
||||||
@ -309,9 +295,88 @@ void Bus::ReleaseMemory()
|
|||||||
{
|
{
|
||||||
MemMap::DestroySharedMemory(s_shmem_handle);
|
MemMap::DestroySharedMemory(s_shmem_handle);
|
||||||
s_shmem_handle = nullptr;
|
s_shmem_handle = nullptr;
|
||||||
|
|
||||||
|
if (!s_shmem_name.empty())
|
||||||
|
{
|
||||||
|
MemMap::DeleteSharedMemory(s_shmem_name.c_str());
|
||||||
|
s_shmem_name = {};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Bus::AllocateMemory(Error* error)
|
||||||
|
{
|
||||||
|
if (!AllocateMemoryMap(error))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
#ifdef ENABLE_MMAP_FASTMEM
|
||||||
|
if (!s_fastmem_arena.Create(FASTMEM_ARENA_SIZE))
|
||||||
|
{
|
||||||
|
Error::SetStringView(error, "Failed to create fastmem arena");
|
||||||
|
ReleaseMemory();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
INFO_LOG("Fastmem base: {}", static_cast<void*>(s_fastmem_arena.BasePointer()));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bus::ReleaseMemory()
|
||||||
|
{
|
||||||
|
#ifdef ENABLE_MMAP_FASTMEM
|
||||||
|
DebugAssert(s_fastmem_ram_views.empty());
|
||||||
|
s_fastmem_arena.Destroy();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::free(s_fastmem_lut);
|
||||||
|
s_fastmem_lut = nullptr;
|
||||||
|
|
||||||
|
ReleaseMemoryMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Bus::ReallocateMemoryMap(Error* error)
|
||||||
|
{
|
||||||
|
// Need to back up RAM+BIOS.
|
||||||
|
DynamicHeapArray<u8> ram_backup;
|
||||||
|
DynamicHeapArray<u8> bios_backup;
|
||||||
|
|
||||||
|
if (System::IsValid())
|
||||||
|
{
|
||||||
|
CPU::CodeCache::InvalidateAllRAMBlocks();
|
||||||
|
UpdateFastmemViews(CPUFastmemMode::Disabled);
|
||||||
|
|
||||||
|
ram_backup.resize(RAM_8MB_SIZE);
|
||||||
|
std::memcpy(ram_backup.data(), g_unprotected_ram, RAM_8MB_SIZE);
|
||||||
|
bios_backup.resize(BIOS_SIZE);
|
||||||
|
std::memcpy(bios_backup.data(), g_bios, BIOS_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReleaseMemoryMap();
|
||||||
|
if (!AllocateMemoryMap(error)) [[unlikely]]
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (System::IsValid())
|
||||||
|
{
|
||||||
|
UpdateMappedRAMSize();
|
||||||
|
std::memcpy(g_unprotected_ram, ram_backup.data(), RAM_8MB_SIZE);
|
||||||
|
std::memcpy(g_bios, bios_backup.data(), BIOS_SIZE);
|
||||||
|
UpdateFastmemViews(g_settings.cpu_fastmem_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bus::CleanupMemoryMap()
|
||||||
|
{
|
||||||
|
#if !defined(_WIN32) && !defined(__ANDROID__)
|
||||||
|
// This is only needed on Linux.
|
||||||
|
if (!s_shmem_name.empty())
|
||||||
|
MemMap::DeleteSharedMemory(s_shmem_name.c_str());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
bool Bus::Initialize()
|
bool Bus::Initialize()
|
||||||
{
|
{
|
||||||
SetRAMSize(g_settings.enable_8mb_ram);
|
SetRAMSize(g_settings.enable_8mb_ram);
|
||||||
@ -337,12 +402,6 @@ void Bus::Shutdown()
|
|||||||
|
|
||||||
g_ram_mask = 0;
|
g_ram_mask = 0;
|
||||||
g_ram_size = 0;
|
g_ram_size = 0;
|
||||||
|
|
||||||
#ifndef __ANDROID__
|
|
||||||
Exports::RAM = 0;
|
|
||||||
Exports::RAM_SIZE = 0;
|
|
||||||
Exports::RAM_MASK = 0;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bus::Reset()
|
void Bus::Reset()
|
||||||
|
@ -116,6 +116,14 @@ static constexpr size_t FASTMEM_ARENA_SIZE = UINT64_C(0x100000000);
|
|||||||
bool AllocateMemory(Error* error);
|
bool AllocateMemory(Error* error);
|
||||||
void ReleaseMemory();
|
void ReleaseMemory();
|
||||||
|
|
||||||
|
/// Frees and re-allocates the memory map for the process.
|
||||||
|
/// This should be called when shared memory exports are enabled.
|
||||||
|
bool ReallocateMemoryMap(Error* error);
|
||||||
|
|
||||||
|
/// Cleans up/deletes the shared memory object for this process.
|
||||||
|
/// Should be called when the process crashes, to avoid leaking.
|
||||||
|
void CleanupMemoryMap();
|
||||||
|
|
||||||
bool Initialize();
|
bool Initialize();
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
void Reset();
|
void Reset();
|
||||||
|
@ -337,6 +337,7 @@ void Settings::Load(SettingsInterface& si)
|
|||||||
audio_output_muted = si.GetBoolValue("Audio", "OutputMuted", false);
|
audio_output_muted = si.GetBoolValue("Audio", "OutputMuted", false);
|
||||||
|
|
||||||
use_old_mdec_routines = si.GetBoolValue("Hacks", "UseOldMDECRoutines", false);
|
use_old_mdec_routines = si.GetBoolValue("Hacks", "UseOldMDECRoutines", false);
|
||||||
|
export_shared_memory = si.GetBoolValue("Hacks", "ExportSharedMemory", false);
|
||||||
pcdrv_enable = si.GetBoolValue("PCDrv", "Enabled", false);
|
pcdrv_enable = si.GetBoolValue("PCDrv", "Enabled", false);
|
||||||
pcdrv_enable_writes = si.GetBoolValue("PCDrv", "EnableWrites", false);
|
pcdrv_enable_writes = si.GetBoolValue("PCDrv", "EnableWrites", false);
|
||||||
pcdrv_root = si.GetStringValue("PCDrv", "Root");
|
pcdrv_root = si.GetStringValue("PCDrv", "Root");
|
||||||
@ -597,6 +598,7 @@ void Settings::Save(SettingsInterface& si, bool ignore_base) const
|
|||||||
si.SetBoolValue("Audio", "OutputMuted", audio_output_muted);
|
si.SetBoolValue("Audio", "OutputMuted", audio_output_muted);
|
||||||
|
|
||||||
si.SetBoolValue("Hacks", "UseOldMDECRoutines", use_old_mdec_routines);
|
si.SetBoolValue("Hacks", "UseOldMDECRoutines", use_old_mdec_routines);
|
||||||
|
si.SetBoolValue("Hacks", "ExportSharedMemory", export_shared_memory);
|
||||||
|
|
||||||
if (!ignore_base)
|
if (!ignore_base)
|
||||||
{
|
{
|
||||||
|
@ -199,6 +199,7 @@ struct Settings
|
|||||||
|
|
||||||
bool use_old_mdec_routines : 1 = false;
|
bool use_old_mdec_routines : 1 = false;
|
||||||
bool pcdrv_enable : 1 = false;
|
bool pcdrv_enable : 1 = false;
|
||||||
|
bool export_shared_memory : 1 = false;
|
||||||
|
|
||||||
// timing hacks section
|
// timing hacks section
|
||||||
TickCount dma_max_slice_ticks = DEFAULT_DMA_MAX_SLICE_TICKS;
|
TickCount dma_max_slice_ticks = DEFAULT_DMA_MAX_SLICE_TICKS;
|
||||||
|
@ -128,6 +128,9 @@ static bool SaveUndoLoadState();
|
|||||||
static void WarnAboutUnsafeSettings();
|
static void WarnAboutUnsafeSettings();
|
||||||
static void LogUnsafeSettingsToConsole(const SmallStringBase& messages);
|
static void LogUnsafeSettingsToConsole(const SmallStringBase& messages);
|
||||||
|
|
||||||
|
/// Checks for settings changes, std::move() the old settings away for comparing beforehand.
|
||||||
|
static void CheckForSettingsChanges(const Settings& old_settings);
|
||||||
|
|
||||||
/// Throttles the system, i.e. sleeps until it's time to execute the next frame.
|
/// Throttles the system, i.e. sleeps until it's time to execute the next frame.
|
||||||
static void Throttle(Common::Timer::Value current_time);
|
static void Throttle(Common::Timer::Value current_time);
|
||||||
static void UpdatePerformanceCounters();
|
static void UpdatePerformanceCounters();
|
||||||
@ -436,6 +439,13 @@ bool System::Internal::CPUThreadInitialize(Error* error)
|
|||||||
// This will call back to Host::LoadSettings() -> ReloadSources().
|
// This will call back to Host::LoadSettings() -> ReloadSources().
|
||||||
LoadSettings(false);
|
LoadSettings(false);
|
||||||
|
|
||||||
|
// Yuckity yuck. We have to test for memory export explicitly, because the allocation happens before config load.
|
||||||
|
if (g_settings.export_shared_memory && !Bus::ReallocateMemoryMap(error))
|
||||||
|
{
|
||||||
|
Error::AddPrefix(error, "Failed to reallocate memory map:\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_RAINTEGRATION
|
#ifdef ENABLE_RAINTEGRATION
|
||||||
if (Host::GetBaseBoolSettingValue("Cheevos", "UseRAIntegration", false))
|
if (Host::GetBaseBoolSettingValue("Cheevos", "UseRAIntegration", false))
|
||||||
Achievements::SwitchToRAIntegration();
|
Achievements::SwitchToRAIntegration();
|
||||||
@ -996,19 +1006,13 @@ System::GameHash System::GetGameHashFromBuffer(std::string_view exe_name, std::s
|
|||||||
DiscRegion System::GetRegionForSerial(const std::string_view serial)
|
DiscRegion System::GetRegionForSerial(const std::string_view serial)
|
||||||
{
|
{
|
||||||
static constexpr const std::pair<const char*, DiscRegion> region_prefixes[] = {
|
static constexpr const std::pair<const char*, DiscRegion> region_prefixes[] = {
|
||||||
{"sces", DiscRegion::PAL},
|
{"sces", DiscRegion::PAL}, {"sced", DiscRegion::PAL}, {"sles", DiscRegion::PAL},
|
||||||
{"sced", DiscRegion::PAL},
|
|
||||||
{"sles", DiscRegion::PAL},
|
|
||||||
{"sled", DiscRegion::PAL},
|
{"sled", DiscRegion::PAL},
|
||||||
|
|
||||||
{"scps", DiscRegion::NTSC_J},
|
{"scps", DiscRegion::NTSC_J}, {"slps", DiscRegion::NTSC_J}, {"slpm", DiscRegion::NTSC_J},
|
||||||
{"slps", DiscRegion::NTSC_J},
|
{"sczs", DiscRegion::NTSC_J}, {"papx", DiscRegion::NTSC_J},
|
||||||
{"slpm", DiscRegion::NTSC_J},
|
|
||||||
{"sczs", DiscRegion::NTSC_J},
|
|
||||||
{"papx", DiscRegion::NTSC_J},
|
|
||||||
|
|
||||||
{"scus", DiscRegion::NTSC_U},
|
{"scus", DiscRegion::NTSC_U}, {"slus", DiscRegion::NTSC_U},
|
||||||
{"slus", DiscRegion::NTSC_U},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const auto& [prefix, region] : region_prefixes)
|
for (const auto& [prefix, region] : region_prefixes)
|
||||||
@ -4360,6 +4364,16 @@ void System::CheckForSettingsChanges(const Settings& old_settings)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (g_settings.export_shared_memory != old_settings.export_shared_memory) [[unlikely]]
|
||||||
|
{
|
||||||
|
Error error;
|
||||||
|
if (!Bus::ReallocateMemoryMap(&error)) [[unlikely]]
|
||||||
|
{
|
||||||
|
ERROR_LOG(error.GetDescription());
|
||||||
|
Panic("Failed to reallocate memory map. The log may contain more information.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (g_settings.log_level != old_settings.log_level || g_settings.log_filter != old_settings.log_filter ||
|
if (g_settings.log_level != old_settings.log_level || g_settings.log_filter != old_settings.log_filter ||
|
||||||
g_settings.log_timestamps != old_settings.log_timestamps ||
|
g_settings.log_timestamps != old_settings.log_timestamps ||
|
||||||
g_settings.log_to_console != old_settings.log_to_console ||
|
g_settings.log_to_console != old_settings.log_to_console ||
|
||||||
|
@ -341,9 +341,6 @@ void ApplyCheatCode(const CheatCode& code);
|
|||||||
/// Sets or clears the provided cheat list, applying every frame.
|
/// Sets or clears the provided cheat list, applying every frame.
|
||||||
void SetCheatList(std::unique_ptr<CheatList> cheats);
|
void SetCheatList(std::unique_ptr<CheatList> cheats);
|
||||||
|
|
||||||
/// Checks for settings changes, std::move() the old settings away for comparing beforehand.
|
|
||||||
void CheckForSettingsChanges(const Settings& old_settings);
|
|
||||||
|
|
||||||
/// Updates throttler.
|
/// Updates throttler.
|
||||||
void UpdateSpeedLimiterState();
|
void UpdateSpeedLimiterState();
|
||||||
|
|
||||||
|
@ -263,6 +263,8 @@ void AdvancedSettingsWidget::addTweakOptions()
|
|||||||
addBooleanTweakOption(m_dialog, m_ui.tweakOptionTable, tr("Allow Booting Without SBI File"), "CDROM",
|
addBooleanTweakOption(m_dialog, m_ui.tweakOptionTable, tr("Allow Booting Without SBI File"), "CDROM",
|
||||||
"AllowBootingWithoutSBIFile", false);
|
"AllowBootingWithoutSBIFile", false);
|
||||||
|
|
||||||
|
addBooleanTweakOption(m_dialog, m_ui.tweakOptionTable, tr("Export Shared Memory"), "Hacks", "ExportSharedMemory",
|
||||||
|
false);
|
||||||
addBooleanTweakOption(m_dialog, m_ui.tweakOptionTable, tr("Enable PINE"), "PINE", "Enabled", false);
|
addBooleanTweakOption(m_dialog, m_ui.tweakOptionTable, tr("Enable PINE"), "PINE", "Enabled", false);
|
||||||
addIntRangeTweakOption(m_dialog, m_ui.tweakOptionTable, tr("PINE Slot"), "PINE", "Slot", 0, 65535,
|
addIntRangeTweakOption(m_dialog, m_ui.tweakOptionTable, tr("PINE Slot"), "PINE", "Slot", 0, 65535,
|
||||||
Settings::DEFAULT_PINE_SLOT);
|
Settings::DEFAULT_PINE_SLOT);
|
||||||
@ -299,6 +301,7 @@ void AdvancedSettingsWidget::onResetToDefaultClicked()
|
|||||||
Settings::DEFAULT_CDROM_MECHACON_VERSION); // CDROM Mechacon Version
|
Settings::DEFAULT_CDROM_MECHACON_VERSION); // CDROM Mechacon Version
|
||||||
setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // CDROM Region Check
|
setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // CDROM Region Check
|
||||||
setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // Allow booting without SBI file
|
setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // Allow booting without SBI file
|
||||||
|
setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // Export Shared Memory
|
||||||
setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // Enable PINE
|
setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // Enable PINE
|
||||||
setIntRangeTweakOption(m_ui.tweakOptionTable, i++, Settings::DEFAULT_PINE_SLOT); // PINE Slot
|
setIntRangeTweakOption(m_ui.tweakOptionTable, i++, Settings::DEFAULT_PINE_SLOT); // PINE Slot
|
||||||
setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // Enable PCDRV
|
setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // Enable PCDRV
|
||||||
@ -322,6 +325,7 @@ void AdvancedSettingsWidget::onResetToDefaultClicked()
|
|||||||
sif->DeleteValue("Hacks", "DMAHaltTicks");
|
sif->DeleteValue("Hacks", "DMAHaltTicks");
|
||||||
sif->DeleteValue("Hacks", "GPUFIFOSize");
|
sif->DeleteValue("Hacks", "GPUFIFOSize");
|
||||||
sif->DeleteValue("Hacks", "GPUMaxRunAhead");
|
sif->DeleteValue("Hacks", "GPUMaxRunAhead");
|
||||||
|
sif->DeleteValue("Hacks", "ExportSharedMemory");
|
||||||
sif->DeleteValue("CPU", "RecompilerMemoryExceptions");
|
sif->DeleteValue("CPU", "RecompilerMemoryExceptions");
|
||||||
sif->DeleteValue("CPU", "RecompilerBlockLinking");
|
sif->DeleteValue("CPU", "RecompilerBlockLinking");
|
||||||
sif->DeleteValue("CPU", "FastmemMode");
|
sif->DeleteValue("CPU", "FastmemMode");
|
||||||
|
@ -46,6 +46,7 @@
|
|||||||
#include "scmversion/scmversion.h"
|
#include "scmversion/scmversion.h"
|
||||||
|
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
|
#include "core/bus.h"
|
||||||
|
|
||||||
#include <QtCore/QCoreApplication>
|
#include <QtCore/QCoreApplication>
|
||||||
#include <QtCore/QDateTime>
|
#include <QtCore/QDateTime>
|
||||||
@ -2513,7 +2514,7 @@ bool QtHost::RunSetupWizard()
|
|||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
CrashHandler::Install();
|
CrashHandler::Install(&Bus::CleanupMemoryMap);
|
||||||
|
|
||||||
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
|
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
|
||||||
QtHost::RegisterTypes();
|
QtHost::RegisterTypes();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user