diff --git a/CMakeLists.txt b/CMakeLists.txt index 28d99b3fb8..0dc6e2114d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1449,6 +1449,8 @@ add_library(${CoreLibName} ${CoreLinkType} Core/CwCheat.h Core/HDRemaster.cpp Core/HDRemaster.h + Core/Instance.cpp + Core/Instance.h Core/ThreadEventQueue.h Core/WebServer.cpp Core/WebServer.h diff --git a/Core/Config.cpp b/Core/Config.cpp index 892482ca42..5ef4f6c26b 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -42,6 +42,7 @@ #include "Core/ConfigValues.h" #include "Core/Loaders.h" #include "Core/HLE/sceUtility.h" +#include "Core/Instance.h" #include "GPU/Common/FramebufferCommon.h" // TODO: Find a better place for this. @@ -1107,8 +1108,13 @@ static void IterateSettings(IniFile &iniFile, std::function> GetLangValuesMapping() { std::map> langValuesMapping; @@ -1290,9 +1296,18 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) { jitForcedOff = true; g_Config.iCpuCore = (int)CPUCore::INTERPRETER; } + + INFO_LOG(LOADER, "Config loaded: '%s'", iniFilename_.c_str()); } void Config::Save(const char *saveReason) { + if (!IsFirstInstance()) { + // TODO: Should we allow saving config if started from a different directory? + // How do we tell? + WARN_LOG(LOADER, "Not saving config - secondary instances don't."); + return; + } + if (jitForcedOff) { // if JIT has been forced off, we don't want to screw up the user's ppsspp.ini g_Config.iCpuCore = (int)CPUCore::JIT; diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index 6679ddbf34..6ad9a0c3c0 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -388,6 +388,7 @@ + @@ -918,6 +919,7 @@ + diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index 5cfb4de0f5..b99fc00e07 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -746,6 +746,9 @@ Core + + Core + @@ -1385,6 +1388,9 @@ Core + + Core + diff --git a/Core/HLE/proAdhoc.cpp b/Core/HLE/proAdhoc.cpp index a7619de4a9..7059b8eda3 100644 --- a/Core/HLE/proAdhoc.cpp +++ b/Core/HLE/proAdhoc.cpp @@ -32,6 +32,7 @@ #include "Core/HLE/sceKernelInterrupt.h" #include "Core/HLE/sceKernelThread.h" #include "Core/HLE/sceKernelMemory.h" +#include "Core/Instance.h" #include "proAdhoc.h" #include "i18n/i18n.h" @@ -68,7 +69,6 @@ bool updateChatScreen = false; int newChat = 0; bool isLocalServer = false; -uint8_t PPSSPP_ID = 0; sockaddr localIP; // This might serves the same purpose with existing "localip" above, but since this is copied from my old code so here it is (too lazy to rewrite the code) int isLocalMAC(const SceNetEtherAddr * addr) { diff --git a/Core/HLE/proAdhoc.h b/Core/HLE/proAdhoc.h index 21470fc7a3..2a7ee49132 100644 --- a/Core/HLE/proAdhoc.h +++ b/Core/HLE/proAdhoc.h @@ -798,7 +798,6 @@ extern std::map adhocctlHandlers; extern uint16_t portOffset; extern bool isLocalServer; -extern uint8_t PPSSPP_ID; extern sockaddr localIP; extern uint32_t fakePoolSize; extern SceNetAdhocMatchingContext * contexts; diff --git a/Core/HLE/sceNet.cpp b/Core/HLE/sceNet.cpp index dacb2904a8..e9996c464e 100644 --- a/Core/HLE/sceNet.cpp +++ b/Core/HLE/sceNet.cpp @@ -42,6 +42,7 @@ #include "Core/HLE/sceNetAdhoc.h" #include "Core/HLE/sceNet.h" #include "Core/Reporting.h" +#include "Core/Instance.h" static bool netInited; static bool netInetInited; @@ -56,124 +57,6 @@ static struct SceNetMallocStat netMallocStat; static std::map apctlHandlers; -#ifdef _WIN32 -static HANDLE hIDMapFile = NULL; -#elif __linux__ || __APPLE__ -static int hIDMapFile = 0; -#endif -static int32_t* pIDBuf = NULL; -#define ID_SHM_NAME "/PPSSPP_ID" - -// Get current number of instance of PPSSPP running. -// Must be called only once during init. -static uint8_t getPPSSPPInstanceNumber() { -#ifdef _WIN32 - uint32_t BUF_SIZE = 4096; - SYSTEM_INFO sysInfo; - - GetSystemInfo(&sysInfo); - int gran = sysInfo.dwAllocationGranularity ? sysInfo.dwAllocationGranularity : 0x10000; - BUF_SIZE = (BUF_SIZE + gran - 1) & ~(gran - 1); - - hIDMapFile = CreateFileMapping( - INVALID_HANDLE_VALUE, // use paging file - NULL, // default security - PAGE_READWRITE, // read/write access - 0, // maximum object size (high-order DWORD) - BUF_SIZE, // maximum object size (low-order DWORD) - TEXT(ID_SHM_NAME)); // name of mapping object - - DWORD lasterr = GetLastError(); - if (hIDMapFile == NULL) - { - ERROR_LOG(SCENET, "Could not create %s file mapping object (%d).", ID_SHM_NAME, lasterr); - return 1; - } - pIDBuf = (int32_t*)MapViewOfFile(hIDMapFile, // handle to map object - FILE_MAP_ALL_ACCESS, // read/write permission - 0, - 0, - sizeof(int32_t)); //BUF_SIZE - - if (pIDBuf == NULL) - { - ERROR_LOG(SCENET, "Could not map view of file %s (%d).", ID_SHM_NAME, GetLastError()); - //CloseHandle(hIDMapFile); - return 1; - } - - (*pIDBuf)++; - int id = *pIDBuf; - UnmapViewOfFile(pIDBuf); - //CloseHandle(hIDMapFile); //Should be called when program exits - //hIDMapFile = NULL; - - return id; -#elif __ANDROID__ - // TODO : replace shm_open & shm_unlink with ashmem or android-shmem - return 1; -#elif __linux__ || __APPLE__ - long BUF_SIZE = 4096; - //caddr_t pIDBuf; - int status; - - // Create shared memory object - - hIDMapFile = shm_open(ID_SHM_NAME, O_CREAT | O_RDWR, 0); - BUF_SIZE = (BUF_SIZE < sysconf(_SC_PAGE_SIZE)) ? sysconf(_SC_PAGE_SIZE) : BUF_SIZE; - - if ((ftruncate(hIDMapFile, BUF_SIZE)) == -1) { // Set the size - ERROR_LOG(SCENET, "ftruncate(%s) failure.", ID_SHM_NAME); - return 1; - } - - pIDBuf = (int32_t*)mmap(0, BUF_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, hIDMapFile, 0); - if (pIDBuf == MAP_FAILED) { // Set the size - ERROR_LOG(SCENET, "mmap(%s) failure.", ID_SHM_NAME); - pIDBuf = NULL; - return 1; - } - - int id = 1; - if (mlock(pIDBuf, BUF_SIZE) == 0) { - (*pIDBuf)++; - id = *pIDBuf; - munlock(pIDBuf, BUF_SIZE); - } - - status = munmap(pIDBuf, BUF_SIZE); // Unmap the page - //status = close(hIDMapFile); // Close file, should be called when program exits? - //status = shm_unlink(ID_SHM_NAME); // Unlink [& delete] shared-memory object, should be called when program exits - - return id; -#else - return 1; -#endif -} - -static void PPSSPPIDCleanup() { -#ifdef _WIN32 - if (hIDMapFile != NULL) { - CloseHandle(hIDMapFile); // If program exited(or crashed?) or the last handle reference closed the shared memory object will be deleted. - hIDMapFile = NULL; - } -#elif __ANDROID__ - if (hIDMapFile != 0) { - close(hIDMapFile); - // TODO : replace shm_unlink with ashmem or android-shmem - //shm_unlink(ID_SHM_NAME); // If program exited or crashed before unlinked the shared memory object and it's contents will persist. - hIDMapFile = 0; - } -#elif __linux__ || __APPLE__ - // TODO : This unlink should be called when program exits instead of everytime the game reset. - if (hIDMapFile != 0) { - close(hIDMapFile); - shm_unlink(ID_SHM_NAME); // If program exited or crashed before unlinked the shared memory object and it's contents will persist. - hIDMapFile = 0; - } -#endif -} - static int InitLocalIP() { // find local IP addrinfo* localAddr; @@ -232,10 +115,6 @@ static void __ResetInitNetLib() { void __NetInit() { portOffset = g_Config.iPortOffset; - if (PPSSPP_ID == 0) // For persistent ID/IP, New instances may have a possibility to have the same ID/IP if PPSSPPIDCleanup() being called on every reset - { - PPSSPP_ID = getPPSSPPInstanceNumber(); // This should be called when program started instead of when the game started/reseted - } net::Init(); InitLocalIP(); diff --git a/Core/Instance.cpp b/Core/Instance.cpp new file mode 100644 index 0000000000..93d4002492 --- /dev/null +++ b/Core/Instance.cpp @@ -0,0 +1,151 @@ +// Copyright (c) 2020 PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#include "Instance.h" + +#if __linux__ || __APPLE__ +#include +#include +#include +#include +#endif + +#include "Common/Log.h" + +#if PPSSPP_PLATFORM(WINDOWS) + +#include "Common/CommonWindows.h" + +#endif + +#include + +uint8_t PPSSPP_ID = 0; + +#if PPSSPP_PLATFORM(WINDOWS) +static HANDLE hIDMapFile = NULL; +#else +static int hIDMapFile = 0; +#endif + +static int32_t* pIDBuf = NULL; +#define ID_SHM_NAME "/PPSSPP_ID" + +// Get current number of instance of PPSSPP running. +// Must be called only once during init. +void InitInstanceCounter() { +#if PPSSPP_PLATFORM(WINDOWS) + uint32_t BUF_SIZE = 4096; + SYSTEM_INFO sysInfo; + + GetSystemInfo(&sysInfo); + int gran = sysInfo.dwAllocationGranularity ? sysInfo.dwAllocationGranularity : 0x10000; + BUF_SIZE = (BUF_SIZE + gran - 1) & ~(gran - 1); + + hIDMapFile = CreateFileMapping( + INVALID_HANDLE_VALUE, // use paging file + NULL, // default security + PAGE_READWRITE, // read/write access + 0, // maximum object size (high-order DWORD) + BUF_SIZE, // maximum object size (low-order DWORD) + TEXT(ID_SHM_NAME)); // name of mapping object + + DWORD lasterr = GetLastError(); + if (hIDMapFile == NULL) + { + ERROR_LOG(SCENET, "Could not create %s file mapping object (%d).", ID_SHM_NAME, lasterr); + PPSSPP_ID = 1; + return; + } + + pIDBuf = (int32_t*)MapViewOfFile(hIDMapFile, // handle to map object + FILE_MAP_ALL_ACCESS, // read/write permission + 0, + 0, + sizeof(int32_t)); //BUF_SIZE + + if (pIDBuf == NULL) { + ERROR_LOG(SCENET, "Could not map view of file %s (%d).", ID_SHM_NAME, GetLastError()); + //CloseHandle(hIDMapFile); + PPSSPP_ID = 1; + return; + } + + (*pIDBuf)++; + int id = *pIDBuf; + UnmapViewOfFile(pIDBuf); + //CloseHandle(hIDMapFile); //Should be called when program exits + //hIDMapFile = NULL; + + PPSSPP_ID = id; +#elif PPSSPP_PLATFORM(ANDROID) + // TODO : replace shm_open & shm_unlink with ashmem or android-shmem + PPSSPP_ID = 1; +#else + long BUF_SIZE = 4096; + //caddr_t pIDBuf; + int status; + + // Create shared memory object + + hIDMapFile = shm_open(ID_SHM_NAME, O_CREAT | O_RDWR, 0); + BUF_SIZE = (BUF_SIZE < sysconf(_SC_PAGE_SIZE)) ? sysconf(_SC_PAGE_SIZE) : BUF_SIZE; + + if ((ftruncate(hIDMapFile, BUF_SIZE)) == -1) { // Set the size + ERROR_LOG(SCENET, "ftruncate(%s) failure.", ID_SHM_NAME); + return 1; + } + + pIDBuf = (int32_t*)mmap(0, BUF_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, hIDMapFile, 0); + if (pIDBuf == MAP_FAILED) { // Set the size + ERROR_LOG(SCENET, "mmap(%s) failure.", ID_SHM_NAME); + pIDBuf = NULL; + return 1; + } + + int id = 1; + if (mlock(pIDBuf, BUF_SIZE) == 0) { + (*pIDBuf)++; + id = *pIDBuf; + munlock(pIDBuf, BUF_SIZE); + } + + status = munmap(pIDBuf, BUF_SIZE); // Unmap the page + //status = close(hIDMapFile); // Close file, should be called when program exits? + //status = shm_unlink(ID_SHM_NAME); // Unlink [& delete] shared-memory object, should be called when program exits + + return id; +#endif +} + +void ShutdownInstanceCounter() { +#if PPSSPP_PLATFORM(WINDOWS) + if (hIDMapFile != NULL) { + CloseHandle(hIDMapFile); // If program exited(or crashed?) or the last handle reference closed the shared memory object will be deleted. + hIDMapFile = NULL; + } +#elif PPSSPP_PLATFORM(ANDROID) + // Do nothing +#else + // TODO : This unlink should be called when program exits instead of everytime the game reset. + if (hIDMapFile != 0) { + close(hIDMapFile); + shm_unlink(ID_SHM_NAME); // If program exited or crashed before unlinked the shared memory object and it's contents will persist. + hIDMapFile = 0; + } +#endif +} diff --git a/Core/Instance.h b/Core/Instance.h new file mode 100644 index 0000000000..5fdfd8106c --- /dev/null +++ b/Core/Instance.h @@ -0,0 +1,31 @@ +// Copyright (c) 2020 PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#pragma once + +#include "ppsspp_config.h" + +#include + +extern uint8_t PPSSPP_ID; + +void InitInstanceCounter(); +void ShutdownInstanceCounter(); + +inline bool IsFirstInstance() { + return PPSSPP_ID == 1; +} diff --git a/UWP/CoreUWP/CoreUWP.vcxproj b/UWP/CoreUWP/CoreUWP.vcxproj index 900df8f61a..80830c4cc3 100644 --- a/UWP/CoreUWP/CoreUWP.vcxproj +++ b/UWP/CoreUWP/CoreUWP.vcxproj @@ -432,6 +432,7 @@ + @@ -648,6 +649,7 @@ + diff --git a/UWP/CoreUWP/CoreUWP.vcxproj.filters b/UWP/CoreUWP/CoreUWP.vcxproj.filters index 8055a958ff..5e9b91ec56 100644 --- a/UWP/CoreUWP/CoreUWP.vcxproj.filters +++ b/UWP/CoreUWP/CoreUWP.vcxproj.filters @@ -80,6 +80,7 @@ + @@ -718,6 +719,7 @@ + diff --git a/Windows/WindowsHost.cpp b/Windows/WindowsHost.cpp index 84d09875bd..f0735eb202 100644 --- a/Windows/WindowsHost.cpp +++ b/Windows/WindowsHost.cpp @@ -46,6 +46,8 @@ #include "Core/CoreParameter.h" #include "Core/System.h" #include "Core/Debugger/SymbolMap.h" +#include "Core/Instance.h" + #include "Windows/EmuThread.h" #include "Windows/WindowsAudio.h" #include "Windows/WindowsHost.h" @@ -101,8 +103,9 @@ WindowsHost::WindowsHost(HINSTANCE hInstance, HWND mainWindow, HWND displayWindo void WindowsHost::SetConsolePosition() { HWND console = GetConsoleWindow(); - if (console != NULL && g_Config.iConsoleWindowX != -1 && g_Config.iConsoleWindowY != -1) + if (console != NULL && g_Config.iConsoleWindowX != -1 && g_Config.iConsoleWindowY != -1) { SetWindowPos(console, NULL, g_Config.iConsoleWindowX, g_Config.iConsoleWindowY, 0, 0, SWP_NOSIZE | SWP_NOZORDER); + } } void WindowsHost::UpdateConsolePosition() { @@ -167,6 +170,9 @@ void WindowsHost::SetWindowTitle(const char *message) { #ifdef _DEBUG winTitle.append(L" (debug)"); #endif + if (PPSSPP_ID >= 1) { + winTitle.append(ConvertUTF8ToWString(StringFromFormat(" (instance: %d)", (int)PPSSPP_ID))); + } MainWindow::SetWindowTitle(winTitle.c_str()); PostMessage(mainWindow_, MainWindow::WM_USER_WINDOW_TITLE_CHANGED, 0, 0); @@ -280,7 +286,7 @@ static std::string SymbolMapFilename(const char *currentFilename, const char* ex return result + ".ppsspp-symbols" + ext; } else { - size_t dot = result.rfind('.'); + const size_t dot = result.rfind('.'); if (dot == result.npos) return result + ext; @@ -360,8 +366,8 @@ bool WindowsHost::CreateDesktopShortcut(std::string argumentPath, std::string ga // Sanitize the game title for banned characters. const char bannedChars[] = "<>:\"/\\|?*"; for (size_t i = 0; i < gameTitle.size(); i++) { - for (size_t c = 0; c < strlen(bannedChars); c++) { - if (gameTitle[i] == bannedChars[c]) { + for (char c : bannedChars) { + if (gameTitle[i] == c) { gameTitle[i] = '_'; break; } diff --git a/android/jni/Android.mk b/android/jni/Android.mk index 5a08665464..7aa1cd2d4a 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -291,6 +291,7 @@ EXEC_AND_LIB_FILES := \ $(SRC)/Core/CoreTiming.cpp \ $(SRC)/Core/CwCheat.cpp \ $(SRC)/Core/HDRemaster.cpp \ + $(SRC)/Core/Instance.cpp \ $(SRC)/Core/Host.cpp \ $(SRC)/Core/Loaders.cpp \ $(SRC)/Core/PSPLoaders.cpp \ diff --git a/libretro/Makefile.common b/libretro/Makefile.common index 3b12a0ba07..b9fe4993bc 100644 --- a/libretro/Makefile.common +++ b/libretro/Makefile.common @@ -342,6 +342,7 @@ SOURCES_CXX += $(NATIVEDIR)/math/dataconv.cpp \ $(COREDIR)/CoreTiming.cpp \ $(COREDIR)/CwCheat.cpp \ $(COREDIR)/HDRemaster.cpp \ + $(COREDIR)/Instance.cpp \ $(COREDIR)/Debugger/Breakpoints.cpp \ $(COREDIR)/Debugger/SymbolMap.cpp \ $(COREDIR)/Dialog/PSPDialog.cpp \