memory_util.cpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  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,
  39. MAP_ANON | MAP_PRIVATE
  40. #if defined(ARCHITECTURE_X64) && defined(MAP_32BIT)
  41. | (low ? MAP_32BIT : 0)
  42. #endif
  43. ,
  44. -1, 0);
  45. #endif /* defined(_WIN32) */
  46. #ifdef _WIN32
  47. if (ptr == nullptr) {
  48. #else
  49. if (ptr == MAP_FAILED) {
  50. ptr = nullptr;
  51. #endif
  52. LOG_ERROR(Common_Memory, "Failed to allocate executable memory");
  53. }
  54. #if !defined(_WIN32) && defined(ARCHITECTURE_X64) && !defined(MAP_32BIT)
  55. else {
  56. if (low) {
  57. map_hint += size;
  58. map_hint = (char*)round_page(map_hint); /* round up to the next page */
  59. }
  60. }
  61. #endif
  62. #if EMU_ARCH_BITS == 64
  63. if ((u64)ptr >= 0x80000000 && low == true)
  64. LOG_ERROR(Common_Memory, "Executable memory ended up above 2GB!");
  65. #endif
  66. return ptr;
  67. }
  68. void* AllocateMemoryPages(size_t size) {
  69. #ifdef _WIN32
  70. void* ptr = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_READWRITE);
  71. #else
  72. void* ptr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
  73. if (ptr == MAP_FAILED)
  74. ptr = nullptr;
  75. #endif
  76. if (ptr == nullptr)
  77. LOG_ERROR(Common_Memory, "Failed to allocate raw memory");
  78. return ptr;
  79. }
  80. void* AllocateAlignedMemory(size_t size, size_t alignment) {
  81. #ifdef _WIN32
  82. void* ptr = _aligned_malloc(size, alignment);
  83. #else
  84. void* ptr = nullptr;
  85. #ifdef ANDROID
  86. ptr = memalign(alignment, size);
  87. #else
  88. if (posix_memalign(&ptr, alignment, size) != 0)
  89. LOG_ERROR(Common_Memory, "Failed to allocate aligned memory");
  90. #endif
  91. #endif
  92. if (ptr == nullptr)
  93. LOG_ERROR(Common_Memory, "Failed to allocate aligned memory");
  94. return ptr;
  95. }
  96. void FreeMemoryPages(void* ptr, size_t size) {
  97. if (ptr) {
  98. #ifdef _WIN32
  99. if (!VirtualFree(ptr, 0, MEM_RELEASE))
  100. LOG_ERROR(Common_Memory, "FreeMemoryPages failed!\n%s", GetLastErrorMsg());
  101. #else
  102. munmap(ptr, size);
  103. #endif
  104. }
  105. }
  106. void FreeAlignedMemory(void* ptr) {
  107. if (ptr) {
  108. #ifdef _WIN32
  109. _aligned_free(ptr);
  110. #else
  111. free(ptr);
  112. #endif
  113. }
  114. }
  115. void WriteProtectMemory(void* ptr, size_t size, bool allowExecute) {
  116. #ifdef _WIN32
  117. DWORD oldValue;
  118. if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READ : PAGE_READONLY, &oldValue))
  119. LOG_ERROR(Common_Memory, "WriteProtectMemory failed!\n%s", GetLastErrorMsg());
  120. #else
  121. mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_EXEC) : PROT_READ);
  122. #endif
  123. }
  124. void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute) {
  125. #ifdef _WIN32
  126. DWORD oldValue;
  127. if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE,
  128. &oldValue))
  129. LOG_ERROR(Common_Memory, "UnWriteProtectMemory failed!\n%s", GetLastErrorMsg());
  130. #else
  131. mprotect(ptr, size,
  132. allowExecute ? (PROT_READ | PROT_WRITE | PROT_EXEC) : PROT_WRITE | PROT_READ);
  133. #endif
  134. }
  135. std::string MemUsage() {
  136. #ifdef _WIN32
  137. #pragma comment(lib, "psapi")
  138. DWORD processID = GetCurrentProcessId();
  139. HANDLE hProcess;
  140. PROCESS_MEMORY_COUNTERS pmc;
  141. std::string Ret;
  142. // Print information about the memory usage of the process.
  143. hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID);
  144. if (nullptr == hProcess)
  145. return "MemUsage Error";
  146. if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc)))
  147. Ret = Common::StringFromFormat(
  148. "%s K", Common::ThousandSeparate(pmc.WorkingSetSize / 1024, 7).c_str());
  149. CloseHandle(hProcess);
  150. return Ret;
  151. #else
  152. return "";
  153. #endif
  154. }