memory.cpp 7.6 KB

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