memory_util.cpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. // Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include "common/logging/log.h"
  5. #include "common/memory_util.h"
  6. #ifdef _WIN32
  7. #include <windows.h>
  8. // Windows.h needs to be included before psapi.h
  9. #include <psapi.h>
  10. #include "common/common_funcs.h"
  11. #include "common/string_util.h"
  12. #else
  13. #include <cstdlib>
  14. #include <sys/mman.h>
  15. #endif
  16. #if !defined(_WIN32) && defined(ARCHITECTURE_X64) && !defined(MAP_32BIT)
  17. #include <unistd.h>
  18. #define PAGE_MASK (getpagesize() - 1)
  19. #define round_page(x) ((((unsigned long)(x)) + PAGE_MASK) & ~(PAGE_MASK))
  20. #endif
  21. // This is purposely not a full wrapper for virtualalloc/mmap, but it
  22. // provides exactly the primitive operations that Dolphin needs.
  23. void* AllocateExecutableMemory(size_t size, bool low) {
  24. #if defined(_WIN32)
  25. void* ptr = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
  26. #else
  27. static char* map_hint = nullptr;
  28. #if defined(ARCHITECTURE_X64) && !defined(MAP_32BIT)
  29. // This OS has no flag to enforce allocation below the 4 GB boundary,
  30. // but if we hint that we want a low address it is very likely we will
  31. // get one.
  32. // An older version of this code used MAP_FIXED, but that has the side
  33. // effect of discarding already mapped pages that happen to be in the
  34. // requested virtual memory range (such as the emulated RAM, sometimes).
  35. if (low && (!map_hint))
  36. map_hint = (char*)round_page(512 * 1024 * 1024); /* 0.5 GB rounded up to the next page */
  37. #endif
  38. void* ptr = mmap(map_hint, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON | MAP_PRIVATE
  39. #if defined(ARCHITECTURE_X64) && defined(MAP_32BIT)
  40. | (low ? MAP_32BIT : 0)
  41. #endif
  42. ,
  43. -1, 0);
  44. #endif /* defined(_WIN32) */
  45. #ifdef _WIN32
  46. if (ptr == nullptr) {
  47. #else
  48. if (ptr == MAP_FAILED) {
  49. ptr = nullptr;
  50. #endif
  51. LOG_ERROR(Common_Memory, "Failed to allocate executable memory");
  52. }
  53. #if !defined(_WIN32) && defined(ARCHITECTURE_X64) && !defined(MAP_32BIT)
  54. else {
  55. if (low) {
  56. map_hint += size;
  57. map_hint = (char*)round_page(map_hint); /* round up to the next page */
  58. }
  59. }
  60. #endif
  61. #if EMU_ARCH_BITS == 64
  62. if ((u64)ptr >= 0x80000000 && low == true)
  63. LOG_ERROR(Common_Memory, "Executable memory ended up above 2GB!");
  64. #endif
  65. return ptr;
  66. }
  67. void* AllocateMemoryPages(size_t size) {
  68. #ifdef _WIN32
  69. void* ptr = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_READWRITE);
  70. #else
  71. void* ptr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
  72. if (ptr == MAP_FAILED)
  73. ptr = nullptr;
  74. #endif
  75. if (ptr == nullptr)
  76. LOG_ERROR(Common_Memory, "Failed to allocate raw memory");
  77. return ptr;
  78. }
  79. void* AllocateAlignedMemory(size_t size, size_t alignment) {
  80. #ifdef _WIN32
  81. void* ptr = _aligned_malloc(size, alignment);
  82. #else
  83. void* ptr = nullptr;
  84. #ifdef ANDROID
  85. ptr = memalign(alignment, size);
  86. #else
  87. if (posix_memalign(&ptr, alignment, size) != 0)
  88. LOG_ERROR(Common_Memory, "Failed to allocate aligned memory");
  89. #endif
  90. #endif
  91. if (ptr == nullptr)
  92. LOG_ERROR(Common_Memory, "Failed to allocate aligned memory");
  93. return ptr;
  94. }
  95. void FreeMemoryPages(void* ptr, size_t size) {
  96. if (ptr) {
  97. #ifdef _WIN32
  98. if (!VirtualFree(ptr, 0, MEM_RELEASE))
  99. LOG_ERROR(Common_Memory, "FreeMemoryPages failed!\n%s", GetLastErrorMsg());
  100. #else
  101. munmap(ptr, size);
  102. #endif
  103. }
  104. }
  105. void FreeAlignedMemory(void* ptr) {
  106. if (ptr) {
  107. #ifdef _WIN32
  108. _aligned_free(ptr);
  109. #else
  110. free(ptr);
  111. #endif
  112. }
  113. }
  114. void WriteProtectMemory(void* ptr, size_t size, bool allowExecute) {
  115. #ifdef _WIN32
  116. DWORD oldValue;
  117. if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READ : PAGE_READONLY, &oldValue))
  118. LOG_ERROR(Common_Memory, "WriteProtectMemory failed!\n%s", GetLastErrorMsg());
  119. #else
  120. mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_EXEC) : PROT_READ);
  121. #endif
  122. }
  123. void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute) {
  124. #ifdef _WIN32
  125. DWORD oldValue;
  126. if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE,
  127. &oldValue))
  128. LOG_ERROR(Common_Memory, "UnWriteProtectMemory failed!\n%s", GetLastErrorMsg());
  129. #else
  130. mprotect(ptr, size,
  131. allowExecute ? (PROT_READ | PROT_WRITE | PROT_EXEC) : PROT_WRITE | PROT_READ);
  132. #endif
  133. }
  134. std::string MemUsage() {
  135. #ifdef _WIN32
  136. #pragma comment(lib, "psapi")
  137. DWORD processID = GetCurrentProcessId();
  138. HANDLE hProcess;
  139. PROCESS_MEMORY_COUNTERS pmc;
  140. std::string Ret;
  141. // Print information about the memory usage of the process.
  142. hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID);
  143. if (nullptr == hProcess)
  144. return "MemUsage Error";
  145. if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc)))
  146. Ret = Common::StringFromFormat(
  147. "%s K", Common::ThousandSeparate(pmc.WorkingSetSize / 1024, 7).c_str());
  148. CloseHandle(hProcess);
  149. return Ret;
  150. #else
  151. return "";
  152. #endif
  153. }