CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: hrydgard/ppsspp
Path: blob/master/Core/Instance.cpp
Views: 1401
1
// Copyright (c) 2020 PPSSPP Project.
2
3
// This program is free software: you can redistribute it and/or modify
4
// it under the terms of the GNU General Public License as published by
5
// the Free Software Foundation, version 2.0 or later versions.
6
7
// This program is distributed in the hope that it will be useful,
8
// but WITHOUT ANY WARRANTY; without even the implied warranty of
9
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
// GNU General Public License 2.0 for more details.
11
12
// A copy of the GPL 2.0 should have been included with the program.
13
// If not, see http://www.gnu.org/licenses/
14
15
// Official git repository and contact information can be found at
16
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
17
18
#include "ppsspp_config.h"
19
#include "Core/Instance.h"
20
21
#if !PPSSPP_PLATFORM(WINDOWS) && !PPSSPP_PLATFORM(ANDROID) && !defined(__LIBRETRO__) && !PPSSPP_PLATFORM(SWITCH)
22
#include <unistd.h>
23
#include <sys/types.h>
24
#include <sys/mman.h>
25
#include <sys/stat.h>
26
#include <fcntl.h>
27
#endif
28
29
#if PPSSPP_PLATFORM(WINDOWS)
30
#include "Common/CommonWindows.h"
31
#endif
32
33
#include "Common/Log.h"
34
#include "Common/SysError.h"
35
36
#include <cstdint>
37
38
uint8_t PPSSPP_ID = 0;
39
40
#if PPSSPP_PLATFORM(WINDOWS)
41
static HANDLE hIDMapFile = nullptr;
42
static HANDLE mapLock = nullptr;
43
#else
44
static int hIDMapFile = -1;
45
static long BUF_SIZE = 4096;
46
#endif
47
48
struct InstanceInfo {
49
uint8_t pad[2];
50
uint8_t next;
51
uint8_t total;
52
};
53
54
#define ID_SHM_NAME "/PPSSPP_ID"
55
56
static bool UpdateInstanceCounter(void (*callback)(volatile InstanceInfo *)) {
57
#if PPSSPP_PLATFORM(WINDOWS)
58
if (!hIDMapFile) {
59
return false;
60
}
61
InstanceInfo *buf = (InstanceInfo *)MapViewOfFile(hIDMapFile, // handle to map object
62
FILE_MAP_ALL_ACCESS, // read/write permission
63
0,
64
0,
65
sizeof(InstanceInfo));
66
67
if (!buf) {
68
auto err = GetLastError();
69
ERROR_LOG(Log::sceNet, "Could not map view of file %s, %08x %s", ID_SHM_NAME, (uint32_t)err, GetStringErrorMsg(err).c_str());
70
return false;
71
}
72
73
bool result = false;
74
if (!mapLock || WaitForSingleObject(mapLock, INFINITE) == 0) {
75
callback(buf);
76
if (mapLock) {
77
ReleaseMutex(mapLock);
78
}
79
result = true;
80
}
81
UnmapViewOfFile(buf);
82
83
return result;
84
#elif PPSSPP_PLATFORM(ANDROID) || defined(__LIBRETRO__) || PPSSPP_PLATFORM(SWITCH)
85
// TODO: replace shm_open & shm_unlink with ashmem or android-shmem
86
return false;
87
#else
88
if (hIDMapFile < 0) {
89
return false;
90
}
91
92
InstanceInfo *buf = (InstanceInfo *)mmap(0, BUF_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, hIDMapFile, 0);
93
if (buf == MAP_FAILED) {
94
ERROR_LOG(Log::sceNet, "mmap(%s) failure.", ID_SHM_NAME);
95
return false;
96
}
97
98
bool result = false;
99
if (mlock(buf, BUF_SIZE) == 0) {
100
callback(buf);
101
munlock(buf, BUF_SIZE);
102
result = true;
103
}
104
105
munmap(buf, BUF_SIZE);
106
return result;
107
#endif
108
}
109
110
int GetInstancePeerCount() {
111
static int c = 0;
112
UpdateInstanceCounter([](volatile InstanceInfo *buf) {
113
c = buf->total;
114
});
115
return c;
116
}
117
118
// Get current number of instance of PPSSPP running.
119
// Must be called only once during init.
120
void InitInstanceCounter() {
121
#if PPSSPP_PLATFORM(WINDOWS)
122
uint32_t BUF_SIZE = 4096;
123
SYSTEM_INFO sysInfo;
124
125
GetSystemInfo(&sysInfo);
126
int gran = sysInfo.dwAllocationGranularity ? sysInfo.dwAllocationGranularity : 0x10000;
127
BUF_SIZE = (BUF_SIZE + gran - 1) & ~(gran - 1);
128
129
mapLock = CreateMutex(nullptr, FALSE, L"PPSSPP_ID_mutex");
130
131
hIDMapFile = CreateFileMapping(
132
INVALID_HANDLE_VALUE, // use paging file
133
NULL, // default security
134
PAGE_READWRITE, // read/write access
135
0, // maximum object size (high-order DWORD)
136
BUF_SIZE, // maximum object size (low-order DWORD)
137
TEXT(ID_SHM_NAME)); // name of mapping object
138
139
DWORD lasterr = GetLastError();
140
if (!hIDMapFile) {
141
ERROR_LOG(Log::sceNet, "Could not create %s file mapping object, %08x %s", ID_SHM_NAME, (uint32_t)lasterr, GetStringErrorMsg(lasterr).c_str());
142
PPSSPP_ID = 1;
143
return;
144
}
145
#elif PPSSPP_PLATFORM(ANDROID) || defined(__LIBRETRO__) || PPSSPP_PLATFORM(SWITCH)
146
// TODO : replace shm_open & shm_unlink with ashmem or android-shmem
147
#else
148
// Create shared memory object
149
hIDMapFile = shm_open(ID_SHM_NAME, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
150
BUF_SIZE = (BUF_SIZE < sysconf(_SC_PAGE_SIZE)) ? sysconf(_SC_PAGE_SIZE) : BUF_SIZE;
151
152
if (hIDMapFile < 0 || (ftruncate(hIDMapFile, BUF_SIZE)) == -1) { // Set the size
153
ERROR_LOG(Log::sceNet, "ftruncate(%s) failure.", ID_SHM_NAME);
154
PPSSPP_ID = 1;
155
return;
156
}
157
#endif
158
159
bool success = UpdateInstanceCounter([](volatile InstanceInfo *buf) {
160
PPSSPP_ID = ++buf->next;
161
buf->total++;
162
});
163
if (!success) {
164
PPSSPP_ID = 1;
165
}
166
}
167
168
void ShutdownInstanceCounter() {
169
UpdateInstanceCounter([](volatile InstanceInfo *buf) {
170
buf->total--;
171
});
172
173
#if PPSSPP_PLATFORM(WINDOWS)
174
if (hIDMapFile) {
175
CloseHandle(hIDMapFile); // If program exited(or crashed?) or the last handle reference closed the shared memory object will be deleted.
176
hIDMapFile = nullptr;
177
}
178
if (mapLock) {
179
CloseHandle(mapLock);
180
mapLock = nullptr;
181
}
182
#elif PPSSPP_PLATFORM(ANDROID) || defined(__LIBRETRO__) || PPSSPP_PLATFORM(SWITCH)
183
// Do nothing
184
#else
185
if (hIDMapFile >= 0) {
186
close(hIDMapFile);
187
shm_unlink(ID_SHM_NAME); // If program exited or crashed before unlinked the shared memory object and it's contents will persist.
188
hIDMapFile = -1;
189
}
190
#endif
191
}
192
193