Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for a shared memory mapping on Kernel & User Memory #1468

Merged
merged 7 commits into from
Nov 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/core/psxemulator.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ class Emulator {
Settings<SettingMcd1, SettingMcd2, SettingBios, SettingPpfDir, SettingPsxExe,
SettingXa, SettingSpuIrq, SettingBnWMdec, SettingScaler, SettingAutoVideo, SettingVideo, SettingFastBoot,
SettingDebugSettings, SettingRCntFix, SettingIsoPath, SettingLocale, SettingMcd1Inserted,
SettingMcd2Inserted, SettingDynarec, Setting8MB, SettingGUITheme, SettingDither, SettingCachedDithering,
SettingMcd2Inserted, SettingDynarec, Setting8MB,SettingGUITheme, SettingDither, SettingCachedDithering,
SettingGLErrorReporting, SettingGLErrorReportingSeverity, SettingFullCaching, SettingHardwareRenderer,
SettingShownAutoUpdateConfig, SettingAutoUpdate, SettingMSAA, SettingLinearFiltering, SettingKioskMode,
SettingMcd1Pocketstation, SettingMcd2Pocketstation, SettingBiosBrowsePath, SettingEXP1Filepath,
Expand Down
7 changes: 5 additions & 2 deletions src/core/psxmem.cc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/***************************************************************************

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

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (main)

ℹ Getting worse: Overall Code Complexity

The mean cyclomatic complexity increases from 8.95 to 9.00, threshold = 4. This file has many conditional statements (e.g. if, for, while) across its implementation, leading to lower code health. Avoid adding more conditionals.
* Copyright (C) 2023 PCSX-Redux authors *
* *
* This program is free software; you can redistribute it and/or modify *
Expand Down Expand Up @@ -89,7 +89,11 @@
m_readLUT = (uint8_t **)calloc(0x10000, sizeof(void *));
m_writeLUT = (uint8_t **)calloc(0x10000, sizeof(void *));

m_wram = (uint8_t *)calloc(0x00800000, 1);
// Init all memory as named mappings
bool success = m_wramShared.init("wram", 0x00800000, true);
if (success) g_system->message(_("SharedMem failed to share memory for wram, falling back to memory alloc\n"));
m_wram = m_wramShared.getPtr();

Check notice on line 96 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 10, 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_exp1 = (uint8_t *)calloc(0x00800000, 1);
m_hard = (uint8_t *)calloc(0x00010000, 1);
m_bios = (uint8_t *)calloc(0x00080000, 1);
Expand Down Expand Up @@ -239,7 +243,6 @@
}

void PCSX::Memory::shutdown() {
free(m_wram);
free(m_exp1);
free(m_hard);
free(m_bios);
Expand Down
5 changes: 5 additions & 0 deletions 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 @@ -186,8 +187,12 @@ class Memory {
int m_writeok = 1;
uint32_t m_biosCRC = 0;

// Shared memory wrappers, pointers below point to these where appropriate
SharedMem m_wramShared;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably keep it private for now.


// hopefully this should become private eventually, with only certain classes having direct access.
public:

uint8_t *m_wram = nullptr; // 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)
Expand Down
3 changes: 2 additions & 1 deletion src/gui/widgets/memory_observer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@
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 + addressValuePair.address - 0x80000000,
&addressValuePair.frozenValue,

Check warning on line 41 in src/gui/widgets/memory_observer.cc

View check run for this annotation

Codecov / codecov/patch

src/gui/widgets/memory_observer.cc#L40-L41

Added lines #L40 - L41 were not covered by tests
dataSize);
}
}
Expand Down
95 changes: 95 additions & 0 deletions src/support/sharedmem-unix.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*

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.

*/

#if !defined(_WIN32) && !defined(_WIN64)

#include "support/sharedmem.h"

#include <assert.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>

#include <sys/mman.h>
#include <sys/stat.h>

bool PCSX::SharedMem::init(const char* id, size_t size, bool initToZero) {
assert(m_mem == nullptr);
bool doRawAlloc = true;
m_size = size;
// Try to create a shared memory mapping, if an ID is provided
if (id != nullptr) {
// Build the full name to share as
m_sharedName = getSharedName(id, static_cast<uint32_t>(getpid()));
// Try to create a shared memory mapping, if a name is provided
m_fd = shm_open(m_sharedName.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
if (m_fd >= 0) {
// fd is ready, reserve the memory we need
int result = ftruncate(m_fd, static_cast<off_t>(size));
if (result < 0) {
shm_unlink(m_sharedName.c_str());
close(m_fd);
m_fd = -1;

Check warning on line 55 in src/support/sharedmem-unix.cc

View check run for this annotation

Codecov / codecov/patch

src/support/sharedmem-unix.cc#L53-L55

Added lines #L53 - L55 were not covered by tests
} else {
// ftruncate completed, now map the memory at 0 offset
void* basePointer = mmap(nullptr, 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);
// Initialise memory to zero, if requested
if (initToZero) {
memset(m_mem, 0, size);
}
} else {
shm_unlink(m_sharedName.c_str());
close(m_fd);
m_fd = -1;

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

View check run for this annotation

Codecov / codecov/patch

src/support/sharedmem-unix.cc#L68-L70

Added lines #L68 - L70 were not covered by tests
}
}
}
}
// Alloc memory directly if we opted out or had problems creating the memory map
if (doRawAlloc) {
// calloc will automatically init memory to zero
m_mem = (uint8_t*)calloc(size, 1);

Check warning on line 78 in src/support/sharedmem-unix.cc

View check run for this annotation

Codecov / codecov/patch

src/support/sharedmem-unix.cc#L78

Added line #L78 was not covered by tests
}

// Return false if we had to fall back to a raw alloc
return !(doRawAlloc && id != nullptr);
}

Check warning on line 83 in src/support/sharedmem-unix.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.

Check warning on line 83 in src/support/sharedmem-unix.cc

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (main)

❌ New issue: Deep, Nested Complexity

PCSX::SharedMem::init has a nested complexity depth of 5, threshold = 4. This function contains deeply nested logic such as if statements and/or loops. The deeper the nesting, the lower the code health.

PCSX::SharedMem::~SharedMem() {
if (m_fd == -1) {
free(m_mem);

Check warning on line 87 in src/support/sharedmem-unix.cc

View check run for this annotation

Codecov / codecov/patch

src/support/sharedmem-unix.cc#L87

Added line #L87 was not covered by tests
} else {
munmap(m_mem, m_size);
shm_unlink(m_sharedName.c_str());
close(m_fd);
}
}

#endif
83 changes: 83 additions & 0 deletions src/support/sharedmem-windows.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*

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.

*/
#if defined(_WIN32) || defined(_WIN64)

#include "support/sharedmem.h"
#include "support/windowswrapper.h"

#include <assert.h>

bool PCSX::SharedMem::init(const char* id, size_t size, bool initToZero) {
assert(m_mem == nullptr);
bool doRawAlloc = true;
m_size = size;
// Try to create a shared memory mapping, if an id is provided
if (id != nullptr) {
// Build the full name to share as
std::string fullname = getSharedName(id, static_cast<uint32_t>(GetCurrentProcessId()));
// Create the memory mapping handle
m_fileHandle = CreateFileMappingA(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE,
static_cast<uint32_t>(size >> 32), static_cast<uint32_t>(size), fullname.c_str());
if (m_fileHandle != INVALID_HANDLE_VALUE) {
// Create a view of the memory mapping at 0 offset
void* basePointer = MapViewOfFileEx(m_fileHandle, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, size, nullptr);
// Validate success and assign the view to m_mem
if (basePointer != nullptr) {
doRawAlloc = false;
m_mem = static_cast<uint8_t *>(basePointer);
// Initialise memory to zero, if requested
if (initToZero) {
memset(m_mem, 0, size);
}
} else {
CloseHandle(m_fileHandle);
m_fileHandle = nullptr;
}
} else {
m_fileHandle = nullptr;
}
}
// Alloc memory directly if we opted out or had problems creating the memory map
if (doRawAlloc) {
// calloc will automatically init memory to zero
m_mem = (uint8_t *)calloc(size, 1);
}
// Return false if we had to fall back to a raw alloc
return !(doRawAlloc && id != nullptr);
}

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

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (main)

❌ New issue: Deep, Nested Complexity

PCSX::SharedMem::init has a nested complexity depth of 4, threshold = 4. This function contains deeply nested logic such as if statements and/or loops. The deeper the nesting, the lower the code health.

PCSX::SharedMem::~SharedMem() {
if (m_fileHandle != nullptr) {
UnmapViewOfFile(m_mem);
m_mem = nullptr;
CloseHandle(m_fileHandle);
m_fileHandle = nullptr;
} else {
free(m_mem);
}
}

#endif
33 changes: 33 additions & 0 deletions src/support/sharedmem.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*

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.

*/

#include "support/sharedmem.h"
#include "fmt/format.h"

std::string PCSX::SharedMem::getSharedName(const char* id, uint32_t pid) {
// Example name: pcsx-redux-wram-37045
return fmt::format("pcsx-redux-{}-{}", id, pid);
}
63 changes: 63 additions & 0 deletions src/support/sharedmem.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*

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.

*/

#pragma once

#include <stdint.h>
#include <string>

namespace PCSX {

class SharedMem {
public:
SharedMem() {}
~SharedMem();

/**
* Returns true if:
* - the memory was sucessfully shared with the given ID, or
* - no ID was given and a raw alloc was performed
* Returns false if:
* - the memory failed to successfully share and defaulted to a raw alloc
*/
bool init(const char* id, size_t size, bool initToZero);

uint8_t* getPtr() { return m_mem; }
size_t getSize() { return m_size; }

private:
std::string getSharedName(const char* id, uint32_t pid);

private:
uint8_t* m_mem = nullptr;
size_t m_size = 0;

void* m_fileHandle = nullptr;
std::string m_sharedName;
int m_fd = -1;
};

} // namespace PCSX
4 changes: 4 additions & 0 deletions vsprojects/support/support.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,7 @@
<ClInclude Include="..\..\src\support\strings-helpers.h" />
<ClInclude Include="..\..\src\support\protobuf.h" />
<ClInclude Include="..\..\src\support\settings.h" />
<ClInclude Include="..\..\src\support\sharedmem.h" />
<ClInclude Include="..\..\src\support\sjis_conv.h" />
<ClInclude Include="..\..\src\support\slice.h" />
<ClInclude Include="..\..\src\support\ssize_t.h" />
Expand Down Expand Up @@ -337,6 +338,9 @@
<ClCompile Include="..\..\src\support\file.cc" />
<ClCompile Include="..\..\src\support\md5.cc" />
<ClCompile Include="..\..\src\support\mem4g.cc" />
<ClCompile Include="..\..\src\support\sharedmem-unix.cc" />
<ClCompile Include="..\..\src\support\sharedmem-windows.cc" />
<ClCompile Include="..\..\src\support\sharedmem.cc" />
<ClCompile Include="..\..\src\support\sjis_conv.cc" />
<ClCompile Include="..\..\src\support\uvfile.cc" />
<ClCompile Include="..\..\src\support\version-linux.cc" />
Expand Down
12 changes: 12 additions & 0 deletions vsprojects/support/support.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,9 @@
<ClInclude Include="..\..\src\support\mem4g.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\src\support\sharedmem.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\src\support\file.cc">
Expand Down Expand Up @@ -209,6 +212,15 @@
<ClCompile Include="..\..\src\support\mem4g.cc">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\src\support\sharedmem-windows.cc">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\src\support\sharedmem-unix.cc">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\src\support\sharedmem.cc">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
Expand Down
Loading