globals.cpp 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. /*
  2. * Copyright (c) 2012-2022 Daniele Bartolini et al.
  3. * License: https://github.com/crownengine/crown/blob/master/LICENSE
  4. */
  5. #include "core/error/error.inl"
  6. #include "core/memory/allocator.h"
  7. #include "core/memory/globals.h"
  8. #include "core/memory/memory.inl"
  9. #include "core/thread/scoped_mutex.inl"
  10. #include <stdlib.h> // malloc
  11. #include <string.h> // memcpy
  12. // void* operator new(size_t) throw (std::bad_alloc)
  13. // {
  14. // CE_FATAL("operator new forbidden");
  15. // return NULL;
  16. // }
  17. // void* operator new[](size_t) throw (std::bad_alloc)
  18. // {
  19. // CE_FATAL("operator new[] forbidden");
  20. // return NULL;
  21. // }
  22. // void operator delete(void*) throw ()
  23. // {
  24. // CE_FATAL("operator delete forbidden");
  25. // }
  26. // void operator delete[](void*) throw ()
  27. // {
  28. // CE_FATAL("operator delete[] forbidden");
  29. // }
  30. namespace crown
  31. {
  32. void *Allocator::reallocate(void *data, u32 size, u32 align)
  33. {
  34. CE_UNUSED(data);
  35. CE_UNUSED(size);
  36. CE_UNUSED(align);
  37. CE_FATAL("reallocate() not supported.");
  38. return NULL;
  39. }
  40. namespace memory
  41. {
  42. // Header stored at the beginning of a memory allocation to indicate the
  43. // size of the allocated data.
  44. struct Header
  45. {
  46. u32 size;
  47. };
  48. // If we need to align the memory allocation we pad the header with this
  49. // value after storing the size. That way we can
  50. const u32 HEADER_PAD_VALUE = 0xffffffffu;
  51. // Given a pointer to the header, returns a pointer to the data that follows it.
  52. inline void *data_pointer(Header *header, u32 align)
  53. {
  54. void *p = header + 1;
  55. return memory::align_top(p, align);
  56. }
  57. // Given a pointer to the data, returns a pointer to the header before it.
  58. inline Header *header(const void *data)
  59. {
  60. u32 *p = (u32 *)data;
  61. while (p[-1] == HEADER_PAD_VALUE)
  62. --p;
  63. return (Header *)p - 1;
  64. }
  65. // Stores the size in the header and pads with HEADER_PAD_VALUE up to the
  66. // data pointer.
  67. inline void fill(Header *header, const void *data, u32 size)
  68. {
  69. header->size = size;
  70. u32 *p = (u32 *)(header + 1);
  71. while (p < data)
  72. *p++ = HEADER_PAD_VALUE;
  73. }
  74. inline u32 actual_allocation_size(u32 size, u32 align)
  75. {
  76. return size + align + sizeof(Header);
  77. }
  78. inline void pad(Header *header, const void *data)
  79. {
  80. u32 *p = (u32 *)(header + 1);
  81. while (p != data) {
  82. *p = HEADER_PAD_VALUE;
  83. p++;
  84. }
  85. }
  86. /// Allocator based on C malloc().
  87. struct HeapAllocator : public Allocator
  88. {
  89. Mutex _mutex;
  90. u32 _allocated_size;
  91. u32 _allocation_count;
  92. HeapAllocator()
  93. : _allocated_size(0)
  94. , _allocation_count(0)
  95. {
  96. }
  97. ~HeapAllocator()
  98. {
  99. CE_ASSERT(_allocation_count == 0 && total_allocated() == 0
  100. , "Missing %u deallocations causing a leak of %u bytes"
  101. , _allocation_count
  102. , total_allocated()
  103. );
  104. }
  105. /// @copydoc Allocator::allocate()
  106. void *allocate(u32 size, u32 align = Allocator::DEFAULT_ALIGN) override
  107. {
  108. ScopedMutex sm(_mutex);
  109. u32 actual_size = actual_allocation_size(size, align);
  110. Header *h = (Header *)malloc(actual_size);
  111. h->size = actual_size;
  112. void *data = memory::align_top(h + 1, align);
  113. pad(h, data);
  114. _allocated_size += actual_size;
  115. _allocation_count++;
  116. return data;
  117. }
  118. /// @copydoc Allocator::deallocate()
  119. void deallocate(void *data) override
  120. {
  121. ScopedMutex sm(_mutex);
  122. if (!data)
  123. return;
  124. Header *h = header(data);
  125. _allocated_size -= h->size;
  126. _allocation_count--;
  127. free(h);
  128. }
  129. void *reallocate(void *data, u32 size, u32 align) override
  130. {
  131. if (!data)
  132. return allocate((u32)size, (u32)align == 0 ? 16 : (u32)align);
  133. if (size == 0) {
  134. deallocate(data);
  135. return NULL;
  136. }
  137. // Figure out the size of data.
  138. const Header *data_header = header(data);
  139. const char *data_end = (char *)data_header + data_header->size;
  140. const u32 data_size = u32(data_end - (char *)data);
  141. // Simulate realloc().
  142. void *p = allocate((u32)size, (u32)align == 0 ? 16 : (u32)align);
  143. memcpy(p, data, min(data_size, size));
  144. deallocate(data);
  145. return p;
  146. }
  147. /// @copydoc Allocator::allocated_size()
  148. u32 allocated_size(const void *ptr) override
  149. {
  150. return get_size(ptr);
  151. }
  152. /// @copydoc Allocator::total_allocated()
  153. u32 total_allocated() override
  154. {
  155. ScopedMutex sm(_mutex);
  156. return _allocated_size;
  157. }
  158. /// Returns the size in bytes of the block of memory pointed by @a data
  159. u32 get_size(const void *data)
  160. {
  161. ScopedMutex sm(_mutex);
  162. Header *h = header(data);
  163. return h->size;
  164. }
  165. };
  166. // Copyright (C) 2012 Bitsquid AB
  167. // License: https://bitbucket.org/bitsquid/foundation/src/default/LICENCSE
  168. //
  169. // An allocator used to allocate temporary "scratch" memory. The allocator
  170. // uses a fixed size ring buffer to services the requests.
  171. //
  172. // Memory is always always allocated linearly. An allocation pointer is
  173. // advanced through the buffer as memory is allocated and wraps around at
  174. // the end of the buffer. Similarly, a free pointer is advanced as memory
  175. // is freed.
  176. //
  177. // It is important that the scratch allocator is only used for short-lived
  178. // memory allocations. A long lived allocator will lock the "free" pointer
  179. // and prevent the "allocate" pointer from proceeding past it, which means
  180. // the ring buffer can't be used.
  181. //
  182. // If the ring buffer is exhausted, the scratch allocator will use its backing
  183. // allocator to allocate memory instead.
  184. struct ScratchAllocator : public Allocator
  185. {
  186. Mutex _mutex;
  187. Allocator &_backing;
  188. // Start and end of the ring buffer.
  189. char *_begin, *_end;
  190. // Pointers to where to allocate memory and where to free memory.
  191. char *_allocate, *_free;
  192. /// Creates a ScratchAllocator. The allocator will use the backing
  193. /// allocator to create the ring buffer and to service any requests
  194. /// that don't fit in the ring buffer.
  195. ///
  196. /// size specifies the size of the ring buffer.
  197. ScratchAllocator(Allocator &backing, u32 size)
  198. : _backing(backing)
  199. {
  200. _begin = (char *)_backing.allocate(size);
  201. _end = _begin + size;
  202. _allocate = _begin;
  203. _free = _begin;
  204. }
  205. ~ScratchAllocator()
  206. {
  207. CE_ASSERT(_free == _allocate, "Memory leak");
  208. _backing.deallocate(_begin);
  209. }
  210. bool in_use(void *p)
  211. {
  212. if (_free == _allocate)
  213. return false;
  214. if (_allocate > _free)
  215. return p >= _free && p < _allocate;
  216. return p >= _free || p < _allocate;
  217. }
  218. void *allocate(u32 size, u32 align) override
  219. {
  220. ScopedMutex sm(_mutex);
  221. CE_ASSERT(align % 4 == 0, "Must be 4-byte aligned");
  222. size = ((size + 3)/4)*4;
  223. char *p = _allocate;
  224. Header *h = (Header *)p;
  225. char *data = (char *)data_pointer(h, align);
  226. p = data + size;
  227. // Reached the end of the buffer, wrap around to the beginning.
  228. if (p > _end) {
  229. h->size = u32(_end - (char *)h) | 0x80000000u;
  230. p = _begin;
  231. h = (Header *)p;
  232. data = (char *)data_pointer(h, align);
  233. p = data + size;
  234. }
  235. // If the buffer is exhausted use the backing allocator instead.
  236. if (in_use(p))
  237. return _backing.allocate(size, align);
  238. fill(h, data, u32(p - (char *)h));
  239. _allocate = p;
  240. return data;
  241. }
  242. void deallocate(void *p) override
  243. {
  244. ScopedMutex sm(_mutex);
  245. if (!p)
  246. return;
  247. if (p < _begin || p >= _end) {
  248. _backing.deallocate(p);
  249. return;
  250. }
  251. // Mark this slot as free
  252. Header *h = header(p);
  253. CE_ASSERT((h->size & 0x80000000u) == 0, "Not free");
  254. h->size = h->size | 0x80000000u;
  255. // Advance the free pointer past all free slots.
  256. while (_free != _allocate) {
  257. Header *h = (Header *)_free;
  258. if ((h->size & 0x80000000u) == 0)
  259. break;
  260. _free += h->size & 0x7fffffffu;
  261. if (_free == _end)
  262. _free = _begin;
  263. }
  264. }
  265. u32 allocated_size(const void *p) override
  266. {
  267. ScopedMutex sm(_mutex);
  268. Header *h = header(p);
  269. return h->size - u32((char *)p - (char *)h);
  270. }
  271. u32 total_allocated() override
  272. {
  273. ScopedMutex sm(_mutex);
  274. return u32(_end - _begin);
  275. }
  276. };
  277. } // namespace memory
  278. namespace memory_globals
  279. {
  280. using namespace memory;
  281. static char _buffer[sizeof(HeapAllocator) + sizeof(ScratchAllocator)];
  282. static HeapAllocator *_default_allocator;
  283. static ScratchAllocator *_default_scratch_allocator;
  284. void init()
  285. {
  286. _default_allocator = new (_buffer) HeapAllocator();
  287. _default_scratch_allocator = new (_buffer + sizeof(HeapAllocator)) ScratchAllocator(*_default_allocator, 1024*1024);
  288. }
  289. void shutdown()
  290. {
  291. _default_scratch_allocator->~ScratchAllocator();
  292. _default_allocator->~HeapAllocator();
  293. }
  294. } // namespace memory_globals
  295. Allocator &default_allocator()
  296. {
  297. return *memory_globals::_default_allocator;
  298. }
  299. Allocator &default_scratch_allocator()
  300. {
  301. return *memory_globals::_default_scratch_allocator;
  302. }
  303. } // namespace crown