allocator.hpp 8.1 KB

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