| 
									
										
										
										
											2015-05-24 06:55:12 +02:00
										 |  |  | // Copyright 2008 Dolphin Emulator Project
 | 
					
						
							| 
									
										
										
										
											2015-05-18 01:08:10 +02:00
										 |  |  | // Licensed under GPLv2+
 | 
					
						
							| 
									
										
										
										
											2013-04-17 23:09:55 -04:00
										 |  |  | // Refer to the license.txt file included.
 | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-20 04:11:52 +01:00
										 |  |  | #include <cstddef>
 | 
					
						
							|  |  |  | #include <cstdlib>
 | 
					
						
							| 
									
										
										
										
											2013-10-19 18:58:02 -04:00
										 |  |  | #include <set>
 | 
					
						
							| 
									
										
										
										
											2014-02-20 04:11:52 +01:00
										 |  |  | #include <string>
 | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-07 20:06:58 -05:00
										 |  |  | #include "Common/CommonTypes.h"
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | #include "Common/Logging/Log.h"
 | 
					
						
							| 
									
										
										
										
											2014-02-17 05:18:15 -05:00
										 |  |  | #include "Common/MemArena.h"
 | 
					
						
							| 
									
										
										
										
											2015-09-26 17:13:07 -04:00
										 |  |  | #include "Common/MsgHandler.h"
 | 
					
						
							| 
									
										
										
										
											2014-02-17 05:18:15 -05:00
										 |  |  | #include "Common/StringUtil.h"
 | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-16 02:58:34 +00:00
										 |  |  | #ifdef _WIN32
 | 
					
						
							|  |  |  | #include <windows.h>
 | 
					
						
							|  |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | #include <cerrno>
 | 
					
						
							|  |  |  | #include <cstring>
 | 
					
						
							| 
									
										
										
										
											2014-02-20 04:11:52 +01:00
										 |  |  | #include <fcntl.h>
 | 
					
						
							|  |  |  | #include <sys/mman.h>
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | #include <unistd.h>
 | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | #ifdef ANDROID
 | 
					
						
							|  |  |  | #include <linux/ashmem.h>
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | #include <sys/ioctl.h>
 | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | #ifdef ANDROID
 | 
					
						
							|  |  |  | #define ASHMEM_DEVICE "/dev/ashmem"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-21 20:46:25 +01:00
										 |  |  | static int AshmemCreateFileMapping(const char* name, size_t size) | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   int fd, ret; | 
					
						
							|  |  |  |   fd = open(ASHMEM_DEVICE, O_RDWR); | 
					
						
							|  |  |  |   if (fd < 0) | 
					
						
							|  |  |  |     return fd; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // We don't really care if we can't set the name, it is optional
 | 
					
						
							|  |  |  |   ioctl(fd, ASHMEM_SET_NAME, name); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ret = ioctl(fd, ASHMEM_SET_SIZE, size); | 
					
						
							|  |  |  |   if (ret < 0) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     close(fd); | 
					
						
							|  |  |  |     NOTICE_LOG(MEMMAP, "Ashmem returned error: 0x%08x", ret); | 
					
						
							|  |  |  |     return ret; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return fd; | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | } | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-01 13:30:14 -07:00
										 |  |  | void MemArena::GrabSHMSegment(size_t size) | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | { | 
					
						
							|  |  |  | #ifdef _WIN32
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   hMemoryMapping = | 
					
						
							|  |  |  |       CreateFileMapping(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0, (DWORD)(size), nullptr); | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | #elif defined(ANDROID)
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   fd = AshmemCreateFileMapping("Dolphin-emu", size); | 
					
						
							|  |  |  |   if (fd < 0) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     NOTICE_LOG(MEMMAP, "Ashmem allocation failed"); | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   for (int i = 0; i < 10000; i++) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     std::string file_name = StringFromFormat("/dolphinmem.%d", i); | 
					
						
							|  |  |  |     fd = shm_open(file_name.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600); | 
					
						
							|  |  |  |     if (fd != -1) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       shm_unlink(file_name.c_str()); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (errno != EEXIST) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       ERROR_LOG(MEMMAP, "shm_open failed: %s", strerror(errno)); | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (ftruncate(fd, size) < 0) | 
					
						
							|  |  |  |     ERROR_LOG(MEMMAP, "Failed to allocate low memory space"); | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-01 13:30:14 -07:00
										 |  |  | void MemArena::ReleaseSHMSegment() | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | { | 
					
						
							|  |  |  | #ifdef _WIN32
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   CloseHandle(hMemoryMapping); | 
					
						
							|  |  |  |   hMemoryMapping = 0; | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   close(fd); | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-21 21:16:51 +01:00
										 |  |  | void* MemArena::CreateView(s64 offset, size_t size, void* base) | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | { | 
					
						
							|  |  |  | #ifdef _WIN32
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return MapViewOfFileEx(hMemoryMapping, FILE_MAP_ALL_ACCESS, 0, (DWORD)((u64)offset), size, base); | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   void* retval = mmap(base, size, PROT_READ | PROT_WRITE, | 
					
						
							|  |  |  |                       MAP_SHARED | ((base == nullptr) ? 0 : MAP_FIXED), fd, offset); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (retval == MAP_FAILED) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     NOTICE_LOG(MEMMAP, "mmap failed"); | 
					
						
							|  |  |  |     return nullptr; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     return retval; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void MemArena::ReleaseView(void* view, size_t size) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | #ifdef _WIN32
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   UnmapViewOfFile(view); | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   munmap(view, size); | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-17 13:17:36 -08:00
										 |  |  | u8* MemArena::FindMemoryBase() | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-03-02 05:21:50 -06:00
										 |  |  | #if _ARCH_64
 | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | #ifdef _WIN32
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   // 64 bit
 | 
					
						
							|  |  |  |   u8* base = (u8*)VirtualAlloc(0, 0x400000000, MEM_RESERVE, PAGE_READWRITE); | 
					
						
							|  |  |  |   VirtualFree(base, 0, MEM_RELEASE); | 
					
						
							|  |  |  |   return base; | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   // Very precarious - mmap cannot return an error when trying to map already used pages.
 | 
					
						
							|  |  |  |   // This makes the Windows approach above unusable on Linux, so we will simply pray...
 | 
					
						
							|  |  |  |   return reinterpret_cast<u8*>(0x2300000000ULL); | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | #else  // 32 bit
 | 
					
						
							| 
									
										
										
										
											2013-03-24 21:06:34 -05:00
										 |  |  | #ifdef ANDROID
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   // Android 4.3 changed how mmap works.
 | 
					
						
							|  |  |  |   // if we map it private and then munmap it, we can't use the base returned.
 | 
					
						
							|  |  |  |   // This may be due to changes in them support a full SELinux implementation.
 | 
					
						
							|  |  |  |   const int flags = MAP_ANON | MAP_SHARED; | 
					
						
							| 
									
										
										
										
											2013-03-24 21:06:34 -05:00
										 |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   const int flags = MAP_ANON | MAP_PRIVATE; | 
					
						
							| 
									
										
										
										
											2013-03-24 21:06:34 -05:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   const u32 MemSize = 0x31000000; | 
					
						
							|  |  |  |   void* base = mmap(0, MemSize, PROT_NONE, flags, -1, 0); | 
					
						
							|  |  |  |   if (base == MAP_FAILED) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     PanicAlert("Failed to map 1 GB of memory space: %s", strerror(errno)); | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   munmap(base, MemSize); | 
					
						
							|  |  |  |   return static_cast<u8*>(base); | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2009-11-07 18:53:10 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | // yeah, this could also be done in like two bitwise ops...
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | #define SKIP(a_flags, b_flags)                                                                     \
 | 
					
						
							|  |  |  |   if (!(a_flags & MV_WII_ONLY) && (b_flags & MV_WII_ONLY))                                         \ | 
					
						
							|  |  |  |     continue;                                                                                      \ | 
					
						
							|  |  |  |   if (!(a_flags & MV_FAKE_VMEM) && (b_flags & MV_FAKE_VMEM))                                       \ | 
					
						
							|  |  |  |     continue; | 
					
						
							| 
									
										
										
										
											2009-11-07 18:53:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-21 21:16:51 +01:00
										 |  |  | static bool Memory_TryBase(u8* base, MemoryView* views, int num_views, u32 flags, MemArena* arena) | 
					
						
							| 
									
										
										
										
											2014-08-30 16:14:56 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   // OK, we know where to find free space. Now grab it!
 | 
					
						
							|  |  |  |   // We just mimic the popular BAT setup.
 | 
					
						
							| 
									
										
										
										
											2009-11-07 18:53:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   int i; | 
					
						
							|  |  |  |   for (i = 0; i < num_views; i++) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     MemoryView* view = &views[i]; | 
					
						
							|  |  |  |     void* view_base; | 
					
						
							|  |  |  |     bool use_sw_mirror; | 
					
						
							| 
									
										
										
										
											2014-10-28 04:02:12 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     SKIP(flags, view->flags); | 
					
						
							| 
									
										
										
										
											2014-10-28 04:02:12 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-02 05:21:50 -06:00
										 |  |  | #if _ARCH_64
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     // On 64-bit, we map the same file position multiple times, so we
 | 
					
						
							|  |  |  |     // don't need the software fallback for the mirrors.
 | 
					
						
							|  |  |  |     view_base = base + view->virtual_address; | 
					
						
							|  |  |  |     use_sw_mirror = false; | 
					
						
							| 
									
										
										
										
											2009-11-07 18:53:10 +00:00
										 |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     // On 32-bit, we don't have the actual address space to store all
 | 
					
						
							|  |  |  |     // the mirrors, so we just map the fallbacks somewhere in our address
 | 
					
						
							|  |  |  |     // space and use the software fallbacks for mirroring.
 | 
					
						
							|  |  |  |     view_base = base + (view->virtual_address & 0x3FFFFFFF); | 
					
						
							|  |  |  |     use_sw_mirror = true; | 
					
						
							| 
									
										
										
										
											2014-10-28 04:44:59 -07:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     if (use_sw_mirror && (view->flags & MV_MIRROR_PREVIOUS)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       view->view_ptr = views[i - 1].view_ptr; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       view->mapped_ptr = arena->CreateView(view->shm_position, view->size, view_base); | 
					
						
							|  |  |  |       view->view_ptr = view->mapped_ptr; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!view->view_ptr) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       // Argh! ERROR! Free what we grabbed so far so we can try again.
 | 
					
						
							|  |  |  |       MemoryMap_Shutdown(views, i + 1, flags, arena); | 
					
						
							|  |  |  |       return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (view->out_ptr) | 
					
						
							|  |  |  |       *(view->out_ptr) = (u8*)view->view_ptr; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return true; | 
					
						
							| 
									
										
										
										
											2009-11-07 18:53:10 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-21 21:16:51 +01:00
										 |  |  | static u32 MemoryMap_InitializeViews(MemoryView* views, int num_views, u32 flags) | 
					
						
							| 
									
										
										
										
											2009-11-07 18:53:10 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   u32 shm_position = 0; | 
					
						
							|  |  |  |   u32 last_position = 0; | 
					
						
							| 
									
										
										
										
											2010-01-08 22:56:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   for (int i = 0; i < num_views; i++) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     // Zero all the pointers to be sure.
 | 
					
						
							|  |  |  |     views[i].mapped_ptr = nullptr; | 
					
						
							| 
									
										
										
										
											2014-11-02 19:24:21 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     SKIP(flags, views[i].flags); | 
					
						
							| 
									
										
										
										
											2014-11-02 19:24:21 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     if (views[i].flags & MV_MIRROR_PREVIOUS) | 
					
						
							|  |  |  |       shm_position = last_position; | 
					
						
							|  |  |  |     views[i].shm_position = shm_position; | 
					
						
							|  |  |  |     last_position = shm_position; | 
					
						
							|  |  |  |     shm_position += views[i].size; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-11-03 10:04:50 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return shm_position; | 
					
						
							| 
									
										
										
										
											2014-11-02 19:24:21 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-21 21:16:51 +01:00
										 |  |  | u8* MemoryMap_Setup(MemoryView* views, int num_views, u32 flags, MemArena* arena) | 
					
						
							| 
									
										
										
										
											2014-11-02 19:24:21 -08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   u32 total_mem = MemoryMap_InitializeViews(views, num_views, flags); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   arena->GrabSHMSegment(total_mem); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Now, create views in high memory where there's plenty of space.
 | 
					
						
							|  |  |  |   u8* base = MemArena::FindMemoryBase(); | 
					
						
							|  |  |  |   // This really shouldn't fail - in 64-bit, there will always be enough
 | 
					
						
							|  |  |  |   // address space.
 | 
					
						
							|  |  |  |   if (!Memory_TryBase(base, views, num_views, flags, arena)) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     PanicAlert("MemoryMap_Setup: Failed finding a memory base."); | 
					
						
							|  |  |  |     exit(0); | 
					
						
							|  |  |  |     return nullptr; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return base; | 
					
						
							| 
									
										
										
										
											2009-11-07 18:53:10 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-21 21:16:51 +01:00
										 |  |  | void MemoryMap_Shutdown(MemoryView* views, int num_views, u32 flags, MemArena* arena) | 
					
						
							| 
									
										
										
										
											2009-11-07 18:53:10 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   std::set<void*> freeset; | 
					
						
							|  |  |  |   for (int i = 0; i < num_views; i++) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     MemoryView* view = &views[i]; | 
					
						
							|  |  |  |     if (view->mapped_ptr && !freeset.count(view->mapped_ptr)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       arena->ReleaseView(view->mapped_ptr, view->size); | 
					
						
							|  |  |  |       freeset.insert(view->mapped_ptr); | 
					
						
							|  |  |  |       view->mapped_ptr = nullptr; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2009-11-15 22:26:39 +00:00
										 |  |  | } |