Skip to content

Commit

Permalink
Refactored named shared memory handling into SharedMem class, with pl…
Browse files Browse the repository at this point in the history
…atform-specific implementations for Windows and Linux (not OSX), removed toggle to enable named shared memory
  • Loading branch information
Ken Murdock committed Nov 24, 2023
1 parent e0ee5f4 commit d79f5f3
Show file tree
Hide file tree
Showing 19 changed files with 308 additions and 90 deletions.
2 changes: 1 addition & 1 deletion src/core/gpu.cc
Original file line number Diff line number Diff line change
Expand Up @@ -525,7 +525,7 @@ void PCSX::GPU::dma(uint32_t madr, uint32_t bcr, uint32_t chcr) { // GPU
PSXDMA_LOG("*** DMA 2 - GPU dma chain *** %8.8lx addr = %lx size = %lx\n", chcr, madr, bcr);

size = gpuDmaChainSize(madr);
chainedDMAWrite((uint32_t *)PCSX::g_emulator->m_mem->m_wram, madr & 0x1fffff);
chainedDMAWrite((uint32_t *)PCSX::g_emulator->m_mem->m_wram.m_mem, madr & 0x1fffff);

// Tekken 3 = use 1.0 only (not 1.5x)

Expand Down
2 changes: 1 addition & 1 deletion src/core/mdec.cc
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ void PCSX::MDEC::init(void) {
memset(&mdec, 0, sizeof(mdec));
memset(iq_y, 0, sizeof(iq_y));
memset(iq_uv, 0, sizeof(iq_uv));
mdec.rl = (uint16_t *)&PCSX::g_emulator->m_mem->m_wram[0x100000];
mdec.rl = (uint16_t *)&PCSX::g_emulator->m_mem->m_wram.m_mem[0x100000];
}

// command register
Expand Down
2 changes: 1 addition & 1 deletion src/core/pcsxlua.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ struct LuaBreakpoint {
PCSX::Debug::BreakpointUserListType wrapper;
};

void* getMemPtr() { return PCSX::g_emulator->m_mem->m_wram; }
void* getMemPtr() { return PCSX::g_emulator->m_mem->m_wram.m_mem; }
void* getParPtr() { return PCSX::g_emulator->m_mem->m_exp1; }
void* getRomPtr() { return PCSX::g_emulator->m_mem->m_bios; }
void* getScratchPtr() { return PCSX::g_emulator->m_mem->m_hard; }
Expand Down
5 changes: 2 additions & 3 deletions src/core/psxemulator.h
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,6 @@ class Emulator {
typedef Setting<bool, TYPESTRING("Mcd2Inserted"), true> SettingMcd2Inserted;
typedef Setting<bool, TYPESTRING("Dynarec"), true> SettingDynarec;
typedef Setting<bool, TYPESTRING("8Megs"), false> Setting8MB;
typedef Setting<bool, TYPESTRING("SharedMemoryMap"), false> SettingSharedMemoryMap;
typedef Setting<int, TYPESTRING("GUITheme"), 0> SettingGUITheme;
typedef Setting<int, TYPESTRING("Dither"), 1> SettingDither;
typedef Setting<bool, TYPESTRING("UseCachedDithering"), false> SettingCachedDithering;
Expand All @@ -189,8 +188,8 @@ class Emulator {

Settings<SettingMcd1, SettingMcd2, SettingBios, SettingPpfDir, SettingPsxExe,
SettingXa, SettingSpuIrq, SettingBnWMdec, SettingScaler, SettingAutoVideo, SettingVideo, SettingFastBoot,
SettingDebugSettings, SettingRCntFix, SettingIsoPath, SettingLocale, SettingMcd1Inserted, SettingMcd2Inserted,
SettingDynarec, Setting8MB, SettingSharedMemoryMap,SettingGUITheme, SettingDither, SettingCachedDithering,
SettingDebugSettings, SettingRCntFix, SettingIsoPath, SettingLocale, SettingMcd1Inserted,
SettingMcd2Inserted, SettingDynarec, Setting8MB,SettingGUITheme, SettingDither, SettingCachedDithering,
SettingGLErrorReporting, SettingGLErrorReportingSeverity, SettingFullCaching, SettingHardwareRenderer,
SettingShownAutoUpdateConfig, SettingAutoUpdate, SettingMSAA, SettingLinearFiltering, SettingKioskMode,
SettingMcd1Pocketstation, SettingMcd2Pocketstation, SettingBiosBrowsePath, SettingEXP1Filepath,
Expand Down
67 changes: 11 additions & 56 deletions src/core/psxmem.cc
Original file line number Diff line number Diff line change
Expand Up @@ -89,51 +89,21 @@ int PCSX::Memory::init() {
m_readLUT = (uint8_t **)calloc(0x10000, sizeof(void *));
m_writeLUT = (uint8_t **)calloc(0x10000, sizeof(void *));

#ifdef _WIN32
size_t wramSize = 0x00800000;
bool doFallbackAlloc = true;

// Try to create a shared memory mapping, if enabled
const bool memoryMappingEnabled = PCSX::g_emulator->settings.get<PCSX::Emulator::SettingSharedMemoryMap>();
if (memoryMappingEnabled) {
// Create the name of our memory mapping handle which we can search for externally
auto handleName = fmt::format("pcsx-redux-{}", GetCurrentProcessId());
// Create the memory mapping handle
m_wramFileHandle = CreateFileMappingA(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0,
static_cast<uint32_t>(wramSize), handleName.c_str());
if (m_wramFileHandle != INVALID_HANDLE_VALUE) {
// Create a view of the memory mapping
void *base_pointer = MapViewOfFileEx(m_wramFileHandle, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0,
static_cast<uint32_t>(wramSize), nullptr);
// Validate success and assign the view to m_wram
if (base_pointer != nullptr) {
doFallbackAlloc = false;
m_wram = (uint8_t *)base_pointer;
} else {
CloseHandle(m_wramFileHandle);
m_wramFileHandle = nullptr;
g_system->message("MapViewOfFileEx failed, falling back to memory alloc, last error: %d\n",
(int)GetLastError());
}
} else {
m_wramFileHandle = nullptr;
g_system->message("CreateFileMappingA failed, falling back to memory alloc, last error: %d\n",
(int)GetLastError());
}
}

if (doFallbackAlloc) {
m_wram = (uint8_t *)calloc(wramSize, 1);
}
#else
m_wram = (uint8_t *)calloc(0x00800000, 1);
uint32_t pid = 0;
#if defined(_WIN32) || defined(_WIN64)
pid = static_cast<uint32_t>(GetCurrentProcessId());
#elif defined(__linux__) || (defined(__APPLE__) && defined(__MACH__))
pid = static_cast<uint32_t>(getpid());
#endif

// Init all memory as named mappings
m_wram.init(fmt::format("pcsx-redux-wram-{}", pid).c_str(), 0x00800000);

m_exp1 = (uint8_t *)calloc(0x00800000, 1);
m_hard = (uint8_t *)calloc(0x00010000, 1);
m_bios = (uint8_t *)calloc(0x00080000, 1);

if (m_readLUT == NULL || m_writeLUT == NULL || m_wram == NULL || m_exp1 == NULL || m_bios == NULL ||
if (m_readLUT == NULL || m_writeLUT == NULL || m_wram.m_mem == NULL || m_exp1 == NULL || m_bios == NULL ||

Check notice on line 106 in src/core/psxmem.cc

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (main)

ℹ Getting worse: Complex Method

PCSX::Memory::init increases in cyclomatic complexity from 9 to 12, threshold = 9. This function has many conditional statements (e.g. if, for, while), leading to lower code health. Avoid adding more conditionals and code to it without refactoring.
m_hard == NULL) {
g_system->message("%s", _("Error allocating memory!"));
return -1;
Expand Down Expand Up @@ -194,7 +164,7 @@ bool PCSX::Memory::loadEXP1FromFile(std::filesystem::path rom_path) {
void PCSX::Memory::reset() {
const uint32_t bios_size = 0x00080000;
const uint32_t exp1_size = 0x00040000;
memset(m_wram, 0, 0x00800000);
memset(m_wram.m_mem, 0, 0x00800000);
memset(m_exp1, 0xff, exp1_size);
memset(m_bios, 0, bios_size);
static const uint32_t nobios[6] = {
Expand Down Expand Up @@ -278,21 +248,6 @@ The distributed OpenBIOS.bin file can be an appropriate BIOS replacement.
}

void PCSX::Memory::shutdown() {
#ifdef _WIN32
if (m_wramFileHandle != nullptr) {
bool result = static_cast<bool>(UnmapViewOfFile(m_wram));
if (!result) {
g_system->printf("Failed to unmap view of Kernel & User Memory.\n");
}
m_wram = nullptr;
CloseHandle(m_wramFileHandle);
m_wramFileHandle = nullptr;
} else {
free(m_wram);
}
#else
free(m_wram);
#endif
free(m_exp1);
free(m_hard);
free(m_bios);
Expand Down Expand Up @@ -701,7 +656,7 @@ const void *PCSX::Memory::pointerWrite(uint32_t address, int size) {
void PCSX::Memory::setLuts() {
int max = (m_hard[0x1061] & 0x1) ? 0x80 : 0x20;
if (!g_emulator->settings.get<Emulator::Setting8MB>()) max = 0x20;
for (int i = 0; i < 0x80; i++) m_readLUT[i + 0x0000] = (uint8_t *)&m_wram[(i & (max - 1)) << 16];
for (int i = 0; i < 0x80; i++) m_readLUT[i + 0x0000] = (uint8_t *)&m_wram.m_mem[(i & (max - 1)) << 16];
memcpy(m_readLUT + 0x8000, m_readLUT, 0x80 * sizeof(void *));
memcpy(m_readLUT + 0xa000, m_readLUT, 0x80 * sizeof(void *));
if (m_writeok) {
Expand Down
3 changes: 2 additions & 1 deletion src/core/psxmem.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <vector>

#include "core/psxemulator.h"
#include "support/sharedmem.h"

#if defined(__BIGENDIAN__)

Expand Down Expand Up @@ -193,7 +194,7 @@ class Memory {

// hopefully this should become private eventually, with only certain classes having direct access.
public:
uint8_t *m_wram = nullptr; // Kernel & User Memory (8 Meg)
SharedMem m_wram; // Kernel & User Memory (8 Meg)
uint8_t *m_exp1 = nullptr; // Expansion Region 1 (ROM/RAM) / Parallel Port (512K)
uint8_t *m_bios = nullptr; // BIOS ROM (512K)
uint8_t *m_hard = nullptr; // Scratch Pad (1K) & Hardware Registers (8K)
Expand Down
6 changes: 3 additions & 3 deletions src/core/sstate.cc
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ PCSX::SaveStates::SaveState PCSX::SaveStates::constructSaveState() {
},
Thumbnail {},
Memory {
RAM { g_emulator->m_mem->m_wram },
RAM { g_emulator->m_mem->m_wram.m_mem },
ROM { g_emulator->m_mem->m_bios },
EXP1 { g_emulator->m_mem->m_exp1 },
HardwareMemory { g_emulator->m_mem->m_hard },
Expand Down Expand Up @@ -242,7 +242,7 @@ void PCSX::GPU::serialize(SaveStateWrapper* w) {

void PCSX::MDEC::serialize(SaveStateWrapper* w) {
using namespace SaveStates;
uint8_t* base = (uint8_t*)&PCSX::g_emulator->m_mem->m_wram[0x100000];
uint8_t* base = (uint8_t*)&PCSX::g_emulator->m_mem->m_wram.m_mem[0x100000];
auto& mdecSave = w->state.get<MDECField>();

mdecSave.get<MDECReg0>().value = mdec.reg0;
Expand Down Expand Up @@ -402,7 +402,7 @@ void PCSX::GPU::deserialize(const SaveStateWrapper* w) {

void PCSX::MDEC::deserialize(const SaveStateWrapper* w) {
using namespace SaveStates;
uint8_t* base = (uint8_t*)&g_emulator->m_mem->m_wram[0x100000];
uint8_t* base = (uint8_t*)&g_emulator->m_mem->m_wram.m_mem[0x100000];
auto& mdecSave = w->state.get<MDECField>();

mdec.reg0 = mdecSave.get<MDECReg0>().value;
Expand Down
4 changes: 2 additions & 2 deletions src/core/web-server.cc
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ class RamExecutor : public PCSX::WebExecutor {
}
uint32_t size = 1024 * 1024 * (ram8M ? 8 : 2);
uint8_t* data = (uint8_t*)malloc(size);
memcpy(data, PCSX::g_emulator->m_mem->m_wram, size);
memcpy(data, PCSX::g_emulator->m_mem->m_wram.m_mem, size);
PCSX::Slice slice;
slice.acquire(data, size);
client->write(std::move(slice));
Expand All @@ -132,7 +132,7 @@ class RamExecutor : public PCSX::WebExecutor {
return true;
}

memcpy(PCSX::g_emulator->m_mem->m_wram + offset, request.body.data<uint8_t>(), size);
memcpy(PCSX::g_emulator->m_mem->m_wram.m_mem + offset, request.body.data<uint8_t>(), size);
client->write("HTTP/1.1 200 OK\r\n\r\n");
return true;
}
Expand Down
10 changes: 2 additions & 8 deletions src/gui/gui.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1395,7 +1395,7 @@ in Configuration->Emulation, restart PCSX-Redux, then try again.)"));
m_events.draw(g_emulator->m_mem->getMemoryAsFile(), _("Kernel events"));
}
if (m_handlers.m_show) {
m_handlers.draw(reinterpret_cast<const uint32_t*>(g_emulator->m_mem->m_wram), _("Kernel handlers"));
m_handlers.draw(reinterpret_cast<const uint32_t*>(g_emulator->m_mem->m_wram.m_mem), _("Kernel handlers"));
}
if (m_kernelLog.m_show) {
changed |= m_kernelLog.draw(g_emulator->m_cpu.get(), _("Kernel Calls"));
Expand All @@ -1410,7 +1410,7 @@ in Configuration->Emulation, restart PCSX-Redux, then try again.)"));
if (editor.m_show) {
ImGui::SetNextWindowPos(ImVec2(520, 30 + 10 * counter), ImGuiCond_FirstUseEver);
ImGui::SetNextWindowSize(ImVec2(484, 480), ImGuiCond_FirstUseEver);
editor.draw(g_emulator->m_mem->m_wram, 8 * 1024 * 1024);
editor.draw(g_emulator->m_mem->m_wram.m_mem, 8 * 1024 * 1024);
}
counter++;
}
Expand Down Expand Up @@ -1900,12 +1900,6 @@ this setting may not have any effect for you.)"));
ImGuiHelpers::ShowHelpMarker(_(R"(Emulates an installed 8MB system,
instead of the normal 2MB. Useful for working
with development binaries and games.)"));
changed |= ImGui::Checkbox(_("Shared Memory Map"), &settings.get<Emulator::SettingSharedMemoryMap>().value);
ImGuiHelpers::ShowHelpMarker(_(R"(Wraps kernel & user memory in a named memory mapping,
allowing it to be modified from external processes.
Available on Windows platforms only, and requires a restart of the emulator to take effect.
The mapping name is 'pcsx-redux-[process ID]', e.g. 'pcsx-redux-36722'.
See Win32 app documentation for 'Creating Named Shared Memory' for more information.)"));
changed |=
ImGui::Checkbox(_("OpenGL GPU *ALPHA STATE*"), &settings.get<Emulator::SettingHardwareRenderer>().value);
ImGuiHelpers::ShowHelpMarker(_(R"(Enables the OpenGL GPU renderer.
Expand Down
4 changes: 2 additions & 2 deletions src/gui/widgets/assembly.cc
Original file line number Diff line number Diff line change
Expand Up @@ -573,9 +573,9 @@ settings, otherwise debugging features may not work.)");
const char* section = "UNK";
if (addr < 0x00800000) {
section = "RAM";
code = *reinterpret_cast<uint32_t*>(m_memory->m_wram + addr);
code = *reinterpret_cast<uint32_t*>(m_memory->m_wram.m_mem + addr);
if (addr <= 0x007ffff8) {
nextCode = *reinterpret_cast<uint32_t*>(m_memory->m_wram + addr + 4);
nextCode = *reinterpret_cast<uint32_t*>(m_memory->m_wram.m_mem + addr + 4);
}
base = m_ramBase;
} else if (addr < 0x00810000) {
Expand Down
5 changes: 3 additions & 2 deletions src/gui/widgets/memory_observer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ PCSX::Widgets::MemoryObserver::MemoryObserver(bool& show) : m_show(show), m_list
for (const auto& addressValuePair : m_addressValuePairs) {
if (addressValuePair.frozen) {
const auto dataSize = getStrideFromValueType(m_scanValueType);
memcpy(g_emulator->m_mem->m_wram + addressValuePair.address - 0x80000000, &addressValuePair.frozenValue,
memcpy(g_emulator->m_mem->m_wram.m_mem + addressValuePair.address - 0x80000000,
&addressValuePair.frozenValue,
dataSize);
}
}
Expand Down Expand Up @@ -86,7 +87,7 @@ void PCSX::Widgets::MemoryObserver::draw(const char* title) {
}

if (ImGui::BeginTabBar("SearchTabBar")) {
const uint8_t* const memData = g_emulator->m_mem->m_wram;
const uint8_t* const memData = g_emulator->m_mem->m_wram.m_mem;
const uint32_t memSize = 1024 * 1024 * (g_emulator->settings.get<PCSX::Emulator::Setting8MB>() ? 8 : 2);
constexpr uint32_t memBase = 0x80000000;

Expand Down
6 changes: 3 additions & 3 deletions src/gui/widgets/typed_debugger.cc
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ PCSX::Widgets::TypedDebugger::TypedDebugger(bool& show) : m_show(show), m_listen
m_listener.listen<PCSX::Events::ExecutionFlow::SaveStateLoaded>([this](const auto& event) {
// When loading a savestate, ensure instructions and functions that have been toggled off are disabled, just in
// case they weren't when the savestate was created.
uint8_t* const memData = g_emulator->m_mem->m_wram;
uint8_t* const memData = g_emulator->m_mem->m_wram.m_mem;
constexpr uint32_t memBase = 0x80000000;

for (const auto& disabledInstruction : m_disabledInstructions) {
Expand Down Expand Up @@ -222,7 +222,7 @@ static bool isInRAM(uint32_t address) {
static uint8_t* getMemoryPointerFor(uint32_t address, uint32_t& outMemBase) {
if (isInRAM(address)) {
outMemBase = 0x80000000;
return PCSX::g_emulator->m_mem->m_wram;
return PCSX::g_emulator->m_mem->m_wram.m_mem;
}

const uint32_t memBase = 0x1f800000;
Expand Down Expand Up @@ -763,7 +763,7 @@ void PCSX::Widgets::TypedDebugger::draw(const char* title, GUI* gui) {
ImGui::SameLine();
showReimportButton(_("Reimport functions from updated file"), m_functionsFile, ImportType::Functions);

uint8_t* const memData = g_emulator->m_mem->m_wram;
uint8_t* const memData = g_emulator->m_mem->m_wram.m_mem;
const uint32_t memSize = 1024 * 1024 * (g_emulator->settings.get<PCSX::Emulator::Setting8MB>() ? 8 : 2);
constexpr uint32_t memBase = 0x80000000;

Expand Down
7 changes: 0 additions & 7 deletions src/main/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -266,13 +266,6 @@ int pcsxMain(int argc, char **argv) {
emuSettings.get<PCSX::Emulator::Setting8MB>() = false;
}

if (args.get<bool>("sharedmemorymap")) {
emuSettings.get<PCSX::Emulator::SettingSharedMemoryMap>() = true;
}
if (args.get<bool>("no-sharedmemorymap")) {
emuSettings.get<PCSX::Emulator::SettingSharedMemoryMap>() = false;
}

if (args.get<bool>("fastboot")) {
emuSettings.get<PCSX::Emulator::SettingFastBoot>() = true;
}
Expand Down
82 changes: 82 additions & 0 deletions src/support/sharedmem-linux.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
MIT License
Copyright (c) 2022 PCSX-Redux authors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

#ifdef __linux__

#include "support/sharedmem.h"
#include "core/system.h"

#include <assert.h>

void PCSX::SharedMem::init(const char* name, size_t size) {
assert(m_mem == nullptr);
bool doRawAlloc = true;
// Try to create a shared memory mapping, if a name is provided
m_fd = shm_open(name, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
if (m_fd < 0) {
g_system->message("shm_open failed, falling back to memory alloc, size: %zu\n", m_size);
} else {
// fd is ready, reserve the memory we need
int result = ftruncate(m_fd, static_cast<off_t>(size));
if (result < 0) {
shm_unlink(name);
close(m_fd);
m_fd = -1;
g_system->message("ftruncate failed, falling back to memory alloc, size: %zu\n", m_size);
} else {
// ftruncate completed, now map the memory at 0 offset
void* basePointer = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, m_fd, 0);
// Validate success and assign the view to m_mem
if (basePointer != MAP_FAILED) {
doRawAlloc = false;
m_mem = static_cast<uint8_t *>(basePointer);
} else {
shm_unlink(name);
close(m_fd);
m_fd = -1;
g_system->message("mmap failed, falling back to memory alloc, size: %zu\n", m_size);
}
}
}
m_name = std::string(name);
m_size = size;
// Alloc memory directly if we opted out or had problems creating the memory map
if (doRawAlloc) {
m_mem = (uint8_t*)calloc(size, 1);
}
}

Check warning on line 70 in src/support/sharedmem-linux.cc

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (main)

❌ New issue: Bumpy Road Ahead

PCSX::SharedMem::init has 2 blocks with nested conditional logic. Any nesting of 2 or deeper is considered. Threshold is one single, nested block per function. The Bumpy Road code smell is a function that contains multiple chunks of nested conditional logic. The deeper the nesting and the more bumps, the lower the code health.

PCSX::SharedMem::~SharedMem() {
if (m_fd == -1) {
free(m_mem);
} else {
munmap(m_mem, m_size);
shm_unlink(m_name.c_str());
close(m_fd);
}
}

#endif
Loading

0 comments on commit d79f5f3

Please sign in to comment.