allocator.hpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. #pragma once
  2. #include <assert.h>
  3. #include <stdint.h>
  4. #include <types/cplusplus.hpp>
  5. #include <types/types.h>
  6. constexpr void* operator new(size_t, void* ptr)
  7. {
  8. return ptr;
  9. }
  10. namespace types {
  11. namespace __allocator {
  12. class brk_memory_allocator {
  13. public:
  14. using byte = uint8_t;
  15. using size_type = size_t;
  16. struct mem_blk_flags {
  17. uint8_t is_free;
  18. uint8_t has_next;
  19. uint8_t _unused2;
  20. uint8_t _unused3;
  21. };
  22. struct mem_blk {
  23. size_t size;
  24. struct mem_blk_flags flags;
  25. // the first byte of the memory space
  26. // the minimal allocated space is 4 bytes
  27. uint8_t data[4];
  28. };
  29. private:
  30. byte* p_start;
  31. byte* p_break;
  32. byte* p_limit;
  33. brk_memory_allocator(void) = delete;
  34. brk_memory_allocator(const brk_memory_allocator&) = delete;
  35. brk_memory_allocator(brk_memory_allocator&&) = delete;
  36. constexpr int brk(byte* addr)
  37. {
  38. if (unlikely(addr >= p_limit))
  39. return GB_FAILED;
  40. p_break = addr;
  41. return GB_OK;
  42. }
  43. // sets errno
  44. inline byte* sbrk(size_type increment)
  45. {
  46. if (unlikely(brk(p_break + increment) != GB_OK))
  47. return nullptr;
  48. else
  49. return p_break;
  50. }
  51. inline mem_blk* _find_next_mem_blk(mem_blk* blk, size_type blk_size)
  52. {
  53. byte* p = (byte*)blk;
  54. p += sizeof(mem_blk);
  55. p += blk_size;
  56. p -= (4 * sizeof(byte));
  57. return (mem_blk*)p;
  58. }
  59. // sets errno
  60. // @param start_pos position where to start finding
  61. // @param size the size of the block we're looking for
  62. // @return found block if suitable block exists, if not, the last block
  63. inline mem_blk* find_blk(mem_blk* start_pos, size_type size)
  64. {
  65. while (1) {
  66. if (start_pos->flags.is_free && start_pos->size >= size) {
  67. return start_pos;
  68. } else {
  69. if (unlikely(!start_pos->flags.has_next))
  70. return start_pos;
  71. start_pos = _find_next_mem_blk(start_pos, start_pos->size);
  72. }
  73. }
  74. }
  75. inline mem_blk* allocate_new_block(mem_blk* blk_before, size_type size)
  76. {
  77. auto ret = sbrk(sizeof(mem_blk) + size - 4 * sizeof(byte));
  78. if (!ret)
  79. return nullptr;
  80. mem_blk* blk = _find_next_mem_blk(blk_before, blk_before->size);
  81. blk_before->flags.has_next = 1;
  82. blk->flags.has_next = 0;
  83. blk->flags.is_free = 1;
  84. blk->size = size;
  85. return blk;
  86. }
  87. inline void split_block(mem_blk* blk, size_type this_size)
  88. {
  89. // block is too small to get split
  90. if (blk->size < sizeof(mem_blk) + this_size) {
  91. return;
  92. }
  93. mem_blk* blk_next = _find_next_mem_blk(blk, this_size);
  94. blk_next->size = blk->size
  95. - this_size
  96. - sizeof(mem_blk)
  97. + 4 * sizeof(byte);
  98. blk_next->flags.has_next = blk->flags.has_next;
  99. blk_next->flags.is_free = 1;
  100. blk->flags.has_next = 1;
  101. blk->size = this_size;
  102. }
  103. public:
  104. inline brk_memory_allocator(byte* start, size_type limit)
  105. : p_start(start)
  106. , p_limit(p_start + limit)
  107. {
  108. brk(p_start);
  109. mem_blk* p_blk = (mem_blk*)sbrk(0);
  110. p_blk->size = 4;
  111. p_blk->flags.has_next = 0;
  112. p_blk->flags.is_free = 1;
  113. }
  114. // sets errno
  115. inline void* alloc(size_type size)
  116. {
  117. struct mem_blk* block_allocated;
  118. block_allocated = find_blk((mem_blk*)p_start, size);
  119. if (!block_allocated->flags.has_next
  120. && (!block_allocated->flags.is_free || block_allocated->size < size)) {
  121. // 'block_allocated' in the argument list is the pointer
  122. // pointing to the last block
  123. block_allocated = allocate_new_block(block_allocated, size);
  124. if (!block_allocated)
  125. return nullptr;
  126. } else {
  127. split_block(block_allocated, size);
  128. }
  129. block_allocated->flags.is_free = 0;
  130. return block_allocated->data;
  131. }
  132. inline void free(void* ptr)
  133. {
  134. mem_blk* blk = (mem_blk*)((byte*)ptr - (sizeof(mem_blk_flags) + sizeof(size_t)));
  135. blk->flags.is_free = 1;
  136. // TODO: fusion free blocks nearby
  137. }
  138. };
  139. }; // namespace __allocator
  140. template <typename T>
  141. concept Allocator = requires(size_t size, typename T::value_type* ptr)
  142. {
  143. typename T::value_type;
  144. {
  145. T::allocate_memory(size)
  146. } -> same_as<typename T::value_type*>;
  147. {
  148. T::deallocate_memory(ptr)
  149. } -> same_as<void>;
  150. };
  151. template <Allocator T>
  152. class allocator_traits;
  153. namespace __allocator {
  154. inline char __ident_heap[0x100000];
  155. inline __allocator::brk_memory_allocator
  156. m_alloc { (uint8_t*)__ident_heap, sizeof(__ident_heap) };
  157. } // namespace __allocator
  158. template <typename T>
  159. class kernel_ident_allocator {
  160. public:
  161. using value_type = T;
  162. static constexpr value_type* allocate_memory(size_t count)
  163. {
  164. return static_cast<value_type*>(__allocator::m_alloc.alloc(count));
  165. }
  166. static constexpr void deallocate_memory(value_type* ptr)
  167. {
  168. __allocator::m_alloc.free(ptr);
  169. }
  170. };
  171. template <template <typename _T> class Allocator, typename T, typename... Args>
  172. constexpr T* _new(Args&&... args)
  173. {
  174. return allocator_traits<Allocator<T>>::allocate_and_construct(forward<Args>(args)...);
  175. }
  176. template <template <typename _T> class Allocator, typename T, typename... Args>
  177. constexpr T* pnew(T* = nullptr, Args&&... args)
  178. {
  179. return _new<Allocator, T, Args...>(forward<Args>(args)...);
  180. }
  181. template <template <typename _T> class Allocator, typename T>
  182. constexpr void pdelete(T* ptr)
  183. {
  184. allocator_traits<Allocator<T>>::deconstruct_and_deallocate(ptr);
  185. }
  186. template <Allocator _allocator>
  187. class allocator_traits {
  188. public:
  189. using value_type = typename _allocator::value_type;
  190. static constexpr value_type* allocate(size_t count)
  191. {
  192. if (count == 0)
  193. return nullptr;
  194. return _allocator::allocate_memory(sizeof(value_type) * count);
  195. }
  196. template <typename... Args>
  197. static constexpr value_type* construct(value_type* ptr, Args&&... args)
  198. {
  199. new (ptr) value_type(forward<Args>(args)...);
  200. return ptr;
  201. }
  202. template <typename... Args>
  203. static constexpr value_type* allocate_and_construct(Args&&... args)
  204. {
  205. auto* ptr = allocate(1);
  206. construct(ptr, forward<Args>(args)...);
  207. return ptr;
  208. }
  209. static constexpr void deconstruct(value_type* ptr)
  210. {
  211. if (!ptr)
  212. return;
  213. ptr->~value_type();
  214. }
  215. static constexpr void deallocate(value_type* ptr)
  216. {
  217. if (!ptr)
  218. return;
  219. _allocator::deallocate_memory(ptr);
  220. }
  221. static constexpr void deconstruct_and_deallocate(value_type* ptr)
  222. {
  223. if (!ptr)
  224. return;
  225. deconstruct(ptr);
  226. deallocate(ptr);
  227. }
  228. };
  229. namespace __allocator {
  230. inline __allocator::brk_memory_allocator* m_palloc;
  231. inline void init_kernel_heap(void* start, size_t sz)
  232. {
  233. m_palloc = pnew<kernel_ident_allocator>(m_palloc, (uint8_t*)start, sz);
  234. }
  235. } // namespace __allocator
  236. template <typename T>
  237. class kernel_allocator {
  238. public:
  239. using value_type = T;
  240. static constexpr value_type* allocate_memory(size_t count)
  241. {
  242. return static_cast<value_type*>(__allocator::m_palloc->alloc(count));
  243. }
  244. static constexpr void deallocate_memory(value_type* ptr)
  245. {
  246. __allocator::m_palloc->free(ptr);
  247. }
  248. };
  249. } // namespace types