summaryrefslogtreecommitdiff
path: root/src/common/mem_arena.cpp
diff options
context:
space:
mode:
authorGravatar Yuri Kunde Schlesner2015-05-07 16:18:03 -0700
committerGravatar Yuri Kunde Schlesner2015-05-07 16:18:03 -0700
commit4560178f6619b6550ee08220de05e917a01cda1e (patch)
tree9a8ad21e178b73b45edbd1d6f467f3a86cdf0f38 /src/common/mem_arena.cpp
parentMerge pull request #723 from lioncash/commonstr (diff)
parentCommon: Remove mem_arena.cpp/h (diff)
downloadyuzu-4560178f6619b6550ee08220de05e917a01cda1e.tar.gz
yuzu-4560178f6619b6550ee08220de05e917a01cda1e.tar.xz
yuzu-4560178f6619b6550ee08220de05e917a01cda1e.zip
Merge pull request #725 from yuriks/remove-common-crap
Remove unused hash and mem_arena from common
Diffstat (limited to 'src/common/mem_arena.cpp')
-rw-r--r--src/common/mem_arena.cpp394
1 files changed, 0 insertions, 394 deletions
diff --git a/src/common/mem_arena.cpp b/src/common/mem_arena.cpp
deleted file mode 100644
index 689fdb92b..000000000
--- a/src/common/mem_arena.cpp
+++ /dev/null
@@ -1,394 +0,0 @@
1// Copyright (C) 2003 Dolphin 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 SVN repository and contact information can be found at
16// http://code.google.com/p/dolphin-emu/
17
18#include <string>
19
20#include "common/logging/log.h"
21#include "common/mem_arena.h"
22#include "common/memory_util.h"
23#include "common/platform.h"
24#include "common/string_util.h"
25
26#ifndef _WIN32
27#include <fcntl.h>
28#include <string.h>
29#include <unistd.h>
30
31#ifdef ANDROID
32#include <sys/ioctl.h>
33#include <linux/ashmem.h>
34#endif
35#endif
36
37#ifdef ANDROID
38
39// Hopefully this ABI will never change...
40
41
42#define ASHMEM_DEVICE "/dev/ashmem"
43
44/*
45* ashmem_create_region - creates a new ashmem region and returns the file
46* descriptor, or <0 on error
47*
48* `name' is an optional label to give the region (visible in /proc/pid/maps)
49* `size' is the size of the region, in page-aligned bytes
50*/
51int ashmem_create_region(const char *name, size_t size)
52{
53 int fd, ret;
54
55 fd = open(ASHMEM_DEVICE, O_RDWR);
56 if (fd < 0)
57 return fd;
58
59 if (name) {
60 char buf[ASHMEM_NAME_LEN];
61
62 strncpy(buf, name, sizeof(buf));
63 ret = ioctl(fd, ASHMEM_SET_NAME, buf);
64 if (ret < 0)
65 goto error;
66 }
67
68 ret = ioctl(fd, ASHMEM_SET_SIZE, size);
69 if (ret < 0)
70 goto error;
71
72 return fd;
73
74error:
75 LOG_ERROR(Common_Memory, "NASTY ASHMEM ERROR: ret = %08x", ret);
76 close(fd);
77 return ret;
78}
79
80int ashmem_set_prot_region(int fd, int prot)
81{
82 return ioctl(fd, ASHMEM_SET_PROT_MASK, prot);
83}
84
85int ashmem_pin_region(int fd, size_t offset, size_t len)
86{
87 struct ashmem_pin pin = { offset, len };
88 return ioctl(fd, ASHMEM_PIN, &pin);
89}
90
91int ashmem_unpin_region(int fd, size_t offset, size_t len)
92{
93 struct ashmem_pin pin = { offset, len };
94 return ioctl(fd, ASHMEM_UNPIN, &pin);
95}
96#endif // Android
97
98
99#if defined(_WIN32)
100SYSTEM_INFO sysInfo;
101#endif
102
103
104// Windows mappings need to be on 64K boundaries, due to Alpha legacy.
105#ifdef _WIN32
106size_t roundup(size_t x) {
107 int gran = sysInfo.dwAllocationGranularity ? sysInfo.dwAllocationGranularity : 0x10000;
108 return (x + gran - 1) & ~(gran - 1);
109}
110#else
111size_t roundup(size_t x) {
112 return x;
113}
114#endif
115
116
117void MemArena::GrabLowMemSpace(size_t size)
118{
119#ifdef _WIN32
120 hMemoryMapping = CreateFileMapping(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0, (DWORD)(size), nullptr);
121 GetSystemInfo(&sysInfo);
122#elif defined(ANDROID)
123 // Use ashmem so we don't have to allocate a file on disk!
124 fd = ashmem_create_region("Citra_RAM", size);
125 // Note that it appears that ashmem is pinned by default, so no need to pin.
126 if (fd < 0)
127 {
128 LOG_ERROR(Common_Memory, "Failed to grab ashmem space of size: %08x errno: %d", (int)size, (int)(errno));
129 return;
130 }
131#else
132 // Try to find a non-existing filename for our shared memory.
133 // In most cases the first one will be available, but it's nicer to search
134 // a bit more.
135 for (int i = 0; i < 10000; i++)
136 {
137 std::string file_name = Common::StringFromFormat("/citramem.%d", i);
138 fd = shm_open(file_name.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600);
139 if (fd != -1)
140 {
141 shm_unlink(file_name.c_str());
142 break;
143 }
144 else if (errno != EEXIST)
145 {
146 LOG_ERROR(Common_Memory, "shm_open failed: %s", strerror(errno));
147 return;
148 }
149 }
150 if (ftruncate(fd, size) < 0)
151 LOG_ERROR(Common_Memory, "Failed to allocate low memory space");
152#endif
153}
154
155
156void MemArena::ReleaseSpace()
157{
158#ifdef _WIN32
159 CloseHandle(hMemoryMapping);
160 hMemoryMapping = 0;
161#else
162 close(fd);
163#endif
164}
165
166
167void *MemArena::CreateView(s64 offset, size_t size, void *base)
168{
169#ifdef _WIN32
170 size = roundup(size);
171 void *ptr = MapViewOfFileEx(hMemoryMapping, FILE_MAP_ALL_ACCESS, 0, (DWORD)((u64)offset), size, base);
172 return ptr;
173#else
174 void *retval = mmap(base, size, PROT_READ | PROT_WRITE, MAP_SHARED |
175 // Do not sync memory to underlying file. Linux has this by default.
176#ifdef __FreeBSD__
177 MAP_NOSYNC |
178#endif
179 ((base == nullptr) ? 0 : MAP_FIXED), fd, offset);
180
181 if (retval == MAP_FAILED)
182 {
183 LOG_ERROR(Common_Memory, "mmap failed");
184 return nullptr;
185 }
186 return retval;
187#endif
188}
189
190
191void MemArena::ReleaseView(void* view, size_t size)
192{
193#ifdef _WIN32
194 UnmapViewOfFile(view);
195#else
196 munmap(view, size);
197#endif
198}
199
200u8* MemArena::Find4GBBase()
201{
202#if EMU_ARCH_BITS == 64
203#ifdef _WIN32
204 // 64 bit
205 u8* base = (u8*)VirtualAlloc(0, 0xE1000000, MEM_RESERVE, PAGE_READWRITE);
206 VirtualFree(base, 0, MEM_RELEASE);
207 return base;
208#else
209 // Very precarious - mmap cannot return an error when trying to map already used pages.
210 // This makes the Windows approach above unusable on Linux, so we will simply pray...
211 return reinterpret_cast<u8*>(0x2300000000ULL);
212#endif
213
214#else // 32 bit
215
216#ifdef _WIN32
217 u8* base = (u8*)VirtualAlloc(0, 0x10000000, MEM_RESERVE, PAGE_READWRITE);
218 if (base) {
219 VirtualFree(base, 0, MEM_RELEASE);
220 }
221 return base;
222#else
223 void* base = mmap(0, 0x10000000, PROT_READ | PROT_WRITE,
224 MAP_ANON | MAP_SHARED, -1, 0);
225 if (base == MAP_FAILED) {
226 LOG_ERROR(Common_Memory, "Failed to map 256 MB of memory space: %s", strerror(errno));
227 return 0;
228 }
229 munmap(base, 0x10000000);
230 return static_cast<u8*>(base);
231#endif
232#endif
233}
234
235
236// yeah, this could also be done in like two bitwise ops...
237#define SKIP(a_flags, b_flags)
238//if (!(a_flags & MV_WII_ONLY) && (b_flags & MV_WII_ONLY))
239// continue;
240//if (!(a_flags & MV_FAKE_VMEM) && (b_flags & MV_FAKE_VMEM))
241// continue;
242
243static bool Memory_TryBase(u8 *base, const MemoryView *views, int num_views, u32 flags, MemArena *arena) {
244 // OK, we know where to find free space. Now grab it!
245 // We just mimic the popular BAT setup.
246 size_t position = 0;
247 size_t last_position = 0;
248
249 // Zero all the pointers to be sure.
250 for (int i = 0; i < num_views; i++)
251 {
252 if (views[i].out_ptr_low)
253 *views[i].out_ptr_low = 0;
254 if (views[i].out_ptr)
255 *views[i].out_ptr = 0;
256 }
257
258 int i;
259 for (i = 0; i < num_views; i++)
260 {
261 const MemoryView &view = views[i];
262 if (view.size == 0)
263 continue;
264 SKIP(flags, view.flags);
265 if (view.flags & MV_MIRROR_PREVIOUS) {
266 position = last_position;
267 }
268 else {
269 *(view.out_ptr_low) = (u8*)arena->CreateView(position, view.size);
270 if (!*view.out_ptr_low)
271 goto bail;
272 }
273#if EMU_ARCH_BITS == 64
274 *view.out_ptr = (u8*)arena->CreateView(
275 position, view.size, base + view.virtual_address);
276#else
277 if (view.flags & MV_MIRROR_PREVIOUS) { // TODO: should check if the two & 0x3FFFFFFF are identical.
278 // No need to create multiple identical views.
279 *view.out_ptr = *views[i - 1].out_ptr;
280 }
281 else {
282 *view.out_ptr = (u8*)arena->CreateView(
283 position, view.size, base + (view.virtual_address & 0x3FFFFFFF));
284 if (!*view.out_ptr)
285 goto bail;
286 }
287#endif
288
289 last_position = position;
290 position += roundup(view.size);
291 }
292
293 return true;
294
295bail:
296 // Argh! ERROR! Free what we grabbed so far so we can try again.
297 for (int j = 0; j <= i; j++)
298 {
299 if (views[i].size == 0)
300 continue;
301 SKIP(flags, views[i].flags);
302 if (views[j].out_ptr_low && *views[j].out_ptr_low)
303 {
304 arena->ReleaseView(*views[j].out_ptr_low, views[j].size);
305 *views[j].out_ptr_low = nullptr;
306 }
307 if (*views[j].out_ptr)
308 {
309#if EMU_ARCH_BITS == 64
310 arena->ReleaseView(*views[j].out_ptr, views[j].size);
311#else
312 if (!(views[j].flags & MV_MIRROR_PREVIOUS))
313 {
314 arena->ReleaseView(*views[j].out_ptr, views[j].size);
315 }
316#endif
317 *views[j].out_ptr = nullptr;
318 }
319 }
320 return false;
321}
322
323u8 *MemoryMap_Setup(const MemoryView *views, int num_views, u32 flags, MemArena *arena)
324{
325 size_t total_mem = 0;
326 int base_attempts = 0;
327
328 for (int i = 0; i < num_views; i++)
329 {
330 if (views[i].size == 0)
331 continue;
332 SKIP(flags, views[i].flags);
333 if ((views[i].flags & MV_MIRROR_PREVIOUS) == 0)
334 total_mem += roundup(views[i].size);
335 }
336 // Grab some pagefile backed memory out of the void ...
337 arena->GrabLowMemSpace(total_mem);
338
339 // Now, create views in high memory where there's plenty of space.
340#if EMU_ARCH_BITS == 64
341 u8 *base = MemArena::Find4GBBase();
342 // This really shouldn't fail - in 64-bit, there will always be enough
343 // address space.
344 if (!Memory_TryBase(base, views, num_views, flags, arena))
345 {
346 LOG_ERROR(Common_Memory, "MemoryMap_Setup: Failed finding a memory base.");
347 return 0;
348 }
349#elif defined(_WIN32)
350 // Try a whole range of possible bases. Return once we got a valid one.
351 u32 max_base_addr = 0x7FFF0000 - 0x10000000;
352 u8 *base = nullptr;
353
354 for (u32 base_addr = 0x01000000; base_addr < max_base_addr; base_addr += 0x400000)
355 {
356 base_attempts++;
357 base = (u8 *)base_addr;
358 if (Memory_TryBase(base, views, num_views, flags, arena))
359 {
360 LOG_DEBUG(Common_Memory, "Found valid memory base at %p after %i tries.", base, base_attempts);
361 base_attempts = 0;
362 break;
363 }
364 }
365#else
366 // Linux32 is fine with the x64 method, although limited to 32-bit with no automirrors.
367 u8 *base = MemArena::Find4GBBase();
368 if (!Memory_TryBase(base, views, num_views, flags, arena))
369 {
370 LOG_ERROR(Common_Memory, "MemoryMap_Setup: Failed finding a memory base.");
371 return 0;
372 }
373#endif
374 if (base_attempts)
375 LOG_ERROR(Common_Memory, "No possible memory base pointer found!");
376 return base;
377}
378
379void MemoryMap_Shutdown(const MemoryView *views, int num_views, u32 flags, MemArena *arena)
380{
381 for (int i = 0; i < num_views; i++)
382 {
383 if (views[i].size == 0)
384 continue;
385 SKIP(flags, views[i].flags);
386 if (views[i].out_ptr_low && *views[i].out_ptr_low)
387 arena->ReleaseView(*views[i].out_ptr_low, views[i].size);
388 if (*views[i].out_ptr && (views[i].out_ptr_low && *views[i].out_ptr != *views[i].out_ptr_low))
389 arena->ReleaseView(*views[i].out_ptr, views[i].size);
390 *views[i].out_ptr = nullptr;
391 if (views[i].out_ptr_low)
392 *views[i].out_ptr_low = nullptr;
393 }
394}