Utility.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. #include "core/Utility.h"
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <threads.h>
  6. #include <time.h>
  7. #include "ErrorSimulator.h"
  8. #include "core/Logger.h"
  9. extern inline size_t maxSize(size_t a, size_t b);
  10. extern inline size_t minSize(size_t a, size_t b);
  11. static ExitHandler exitHandler = nullptr;
  12. static void* exitData = nullptr;
  13. static OutOfMemoryHandler outOfMemoryHandler = nullptr;
  14. static void* outOfMemoryData = nullptr;
  15. size_t popCount(u64 u) {
  16. static const u64 map[16] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4};
  17. size_t sum = 0;
  18. for(size_t i = 0; i < sizeof(u64) * 8; i += 4) {
  19. sum += map[(u >> i) & 0xF];
  20. }
  21. return sum;
  22. }
  23. [[noreturn]] void exitWithHandler(const char* file, int line, int value) {
  24. if(value != 0) {
  25. file = getShortFileName(file);
  26. LOG_ERROR("Exit from %s:%d with value %d", file, line, value);
  27. }
  28. if(exitHandler != nullptr) {
  29. exitHandler(value, exitData);
  30. }
  31. exit(value);
  32. }
  33. void setExitHandler(ExitHandler eh, void* data) {
  34. exitHandler = eh;
  35. exitData = data;
  36. }
  37. void setOutOfMemoryHandler(OutOfMemoryHandler h, void* data) {
  38. outOfMemoryHandler = h;
  39. outOfMemoryData = data;
  40. }
  41. static void* exitOnNull(void* p, size_t n) {
  42. if(p == nullptr) {
  43. LOG_ERROR("Out of memory, requested '%zu' bytes", n);
  44. EXIT(1);
  45. }
  46. return p;
  47. }
  48. static void* RealAllocate(size_t n) {
  49. void* p = malloc(n);
  50. while(p == nullptr && outOfMemoryHandler != nullptr) {
  51. outOfMemoryHandler(outOfMemoryData);
  52. p = malloc(n);
  53. }
  54. return exitOnNull(p, n);
  55. }
  56. static void* RealReallocate(void* oldP, size_t n) {
  57. if(n <= 0) {
  58. free(oldP);
  59. return nullptr;
  60. }
  61. void* p = realloc(oldP, n);
  62. if(p == nullptr) {
  63. while(p == nullptr && outOfMemoryHandler != nullptr) {
  64. outOfMemoryHandler(outOfMemoryData);
  65. p = realloc(oldP, n);
  66. }
  67. }
  68. return exitOnNull(p, n);
  69. }
  70. static void RealFree(void* p) {
  71. free(p);
  72. }
  73. #ifdef CHECK_MEMORY
  74. static const u8 CANARY[16] = {0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF,
  75. 0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF};
  76. struct MemoryInfo;
  77. typedef struct MemoryInfo MemoryInfo;
  78. struct MemoryInfo {
  79. MemoryInfo* next;
  80. MemoryInfo* previous;
  81. size_t size;
  82. int line;
  83. char buffer[64 - 2 * sizeof(void*) - sizeof(size_t) - sizeof(int)];
  84. char canary[sizeof(CANARY)];
  85. };
  86. static_assert(sizeof(MemoryInfo) == 80, "memory info has invalid size");
  87. static MemoryInfo* headMemoryInfo = nullptr;
  88. static void addMemoryInfo(
  89. MemoryInfo* info, const char* file, int line, size_t n) {
  90. info->next = nullptr;
  91. info->previous = nullptr;
  92. info->size = n;
  93. info->line = line;
  94. snprintf(info->buffer, sizeof(info->buffer), "%s", getShortFileName(file));
  95. memcpy(info->canary, CANARY, sizeof(CANARY));
  96. memcpy((char*)info + n - sizeof(CANARY), CANARY, sizeof(CANARY));
  97. if(headMemoryInfo == nullptr) {
  98. headMemoryInfo = info;
  99. } else {
  100. headMemoryInfo->previous = info;
  101. info->next = headMemoryInfo;
  102. headMemoryInfo = info;
  103. }
  104. }
  105. static void removeMemoryInfo(MemoryInfo* info) {
  106. if(info->previous == nullptr) {
  107. if(info->next == nullptr) {
  108. headMemoryInfo = nullptr;
  109. } else {
  110. headMemoryInfo = info->next;
  111. info->next->previous = nullptr;
  112. }
  113. } else {
  114. if(info->next == nullptr) {
  115. info->previous->next = nullptr;
  116. } else {
  117. info->previous->next = info->next;
  118. info->next->previous = info->previous;
  119. }
  120. }
  121. }
  122. void* coreDebugAllocate(const char* file, int line, size_t n) {
  123. n += sizeof(MemoryInfo) + sizeof(CANARY);
  124. void* p = RealAllocate(n + sizeof(CANARY));
  125. addMemoryInfo(p, file, line, n);
  126. return (char*)p + sizeof(MemoryInfo);
  127. }
  128. void* coreDebugZeroAllocate(const char* file, int line, size_t n) {
  129. void* p = coreDebugAllocate(file, line, n);
  130. memset(p, 0, n);
  131. return p;
  132. }
  133. void* coreDebugReallocate(const char* file, int line, void* p, size_t n) {
  134. if(n > 0) {
  135. n += sizeof(MemoryInfo) + sizeof(CANARY);
  136. }
  137. void* rp = (void*)p;
  138. if(rp != nullptr) {
  139. rp = (char*)rp - sizeof(MemoryInfo);
  140. removeMemoryInfo(rp);
  141. }
  142. void* np = RealReallocate(rp, n);
  143. if(np == nullptr) {
  144. return nullptr;
  145. }
  146. addMemoryInfo(np, file, line, n);
  147. return (char*)np + sizeof(MemoryInfo);
  148. }
  149. static bool checkCanary(void* p) {
  150. return memcmp(p, CANARY, sizeof(CANARY)) != 0;
  151. }
  152. void coreFreeDebug(const char* file, int line, void* p) {
  153. if(p == nullptr) {
  154. return;
  155. }
  156. void* w = (char*)p - sizeof(MemoryInfo);
  157. MemoryInfo* rp = w;
  158. if(checkCanary(rp->canary)) {
  159. file = getShortFileName(file);
  160. LOG_ERROR("Free at %s:%d violated pre canary", file, line);
  161. EXIT(1);
  162. } else if(checkCanary((char*)rp + rp->size - sizeof(CANARY))) {
  163. file = getShortFileName(file);
  164. LOG_ERROR("Free at %s:%d violated post canary", file, line);
  165. EXIT(1);
  166. }
  167. removeMemoryInfo(rp);
  168. RealFree(rp);
  169. }
  170. void printMemoryReport() {
  171. for(MemoryInfo* i = headMemoryInfo; i != nullptr; i = i->next) {
  172. LOG_ERROR("%s:%d was not freed", i->buffer, i->line);
  173. }
  174. }
  175. #else
  176. void* coreAllocate(size_t n) {
  177. return RealAllocate(n);
  178. }
  179. void* coreZeroAllocate(size_t n) {
  180. void* p = coreAllocate(n);
  181. memset(p, 0, n);
  182. return p;
  183. }
  184. void* coreReallocate(void* p, size_t n) {
  185. return RealReallocate(p, n);
  186. }
  187. void coreFree(void* p) {
  188. RealFree(p);
  189. }
  190. #endif
  191. bool sleepNanos(i64 nanos) {
  192. struct timespec t;
  193. t.tv_nsec = nanos % 1'000'000'000;
  194. t.tv_sec = nanos / 1'000'000'000;
  195. return thrd_sleep(&t, nullptr) != 0;
  196. }
  197. i64 getNanos(void) {
  198. struct timespec ts;
  199. if(timespec_get(&ts, TIME_UTC) == 0 || TIME_GET_FAIL) {
  200. return -1;
  201. }
  202. return (i64)ts.tv_sec * 1'000'000'000L + (i64)ts.tv_nsec;
  203. }