You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

364 lines
6.0 KiB

  1. /*
  2. ISC License
  3. Copyright (c) 2021, Antonio SJ Musumeci <trapexit@spawn.link>
  4. Permission to use, copy, modify, and/or distribute this software for any
  5. purpose with or without fee is hereby granted, provided that the above
  6. copyright notice and this permission notice appear in all copies.
  7. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  8. WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  9. MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  10. ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  11. WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  12. ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  13. OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  14. */
  15. #pragma once
  16. #include "kvec.h"
  17. #include <errno.h>
  18. #include <stdint.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <sys/mman.h>
  22. #include <unistd.h>
  23. #define ROUND_UP(N,S) ((((N) + (S) - 1) / (S)) * (S))
  24. typedef kvec_t(void*) slab_kvec_t;
  25. typedef struct mem_stack_t mem_stack_t;
  26. struct mem_stack_t
  27. {
  28. mem_stack_t *next;
  29. };
  30. typedef struct fmp_t fmp_t;
  31. struct fmp_t
  32. {
  33. mem_stack_t *objs;
  34. slab_kvec_t slabs;
  35. uint64_t avail_objs;
  36. uint64_t obj_size;
  37. uint64_t page_size;
  38. uint64_t slab_size;
  39. };
  40. static
  41. inline
  42. uint64_t
  43. fmp_page_size()
  44. {
  45. return sysconf(_SC_PAGESIZE);
  46. }
  47. static
  48. inline
  49. void
  50. fmp_init(fmp_t *fmp_,
  51. const uint64_t obj_size_,
  52. const uint64_t page_multiple_)
  53. {
  54. kv_init(fmp_->slabs);
  55. fmp_->objs = NULL;
  56. fmp_->avail_objs = 0;
  57. fmp_->obj_size = ROUND_UP(obj_size_,sizeof(void*));
  58. fmp_->page_size = fmp_page_size();
  59. fmp_->slab_size = (fmp_->page_size * page_multiple_);
  60. }
  61. static
  62. inline
  63. uint64_t
  64. fmp_slab_count(fmp_t *fmp_)
  65. {
  66. return kv_size(fmp_->slabs);
  67. }
  68. static
  69. inline
  70. void*
  71. fmp_slab_alloc_posix_memalign(fmp_t *fmp_)
  72. {
  73. int rv;
  74. void *mem;
  75. const size_t alignment = fmp_->page_size;
  76. const size_t size = fmp_->slab_size;
  77. rv = posix_memalign(&mem,alignment,size);
  78. if(rv != 0)
  79. return NULL;
  80. return NULL;
  81. }
  82. static
  83. inline
  84. void*
  85. fmp_slab_alloc_mmap(fmp_t *fmp_)
  86. {
  87. void *mem;
  88. void *address = NULL;
  89. const size_t length = fmp_->slab_size;
  90. const int protect = PROT_READ|PROT_WRITE;
  91. const int flags = MAP_PRIVATE|MAP_ANONYMOUS;
  92. const int filedes = -1;
  93. const off_t offset = 0;
  94. mem = mmap(address,length,protect,flags,filedes,offset);
  95. if(mem == MAP_FAILED)
  96. return NULL;
  97. return mem;
  98. }
  99. static
  100. inline
  101. void
  102. fmp_slab_free_posix_memalign(fmp_t* fmp_,
  103. void *mem_)
  104. {
  105. (void)fmp_;
  106. free(mem_);
  107. }
  108. static
  109. inline
  110. void
  111. fmp_slab_free_mmap(fmp_t* fmp_,
  112. void *mem_)
  113. {
  114. void *addr = mem_;
  115. size_t length = fmp_->slab_size;
  116. (void)munmap(addr,length);
  117. }
  118. static
  119. inline
  120. int
  121. fmp_slab_alloc(fmp_t *fmp_)
  122. {
  123. char *i;
  124. void *mem;
  125. mem = fmp_slab_alloc_mmap(fmp_);
  126. if(mem == NULL)
  127. return -ENOMEM;
  128. kv_push(void*,fmp_->slabs,mem);
  129. i = ((char*)mem + fmp_->slab_size - fmp_->obj_size);
  130. while(i >= (char*)mem)
  131. {
  132. mem_stack_t *obj = (mem_stack_t*)i;
  133. obj->next = fmp_->objs;
  134. fmp_->objs = obj;
  135. fmp_->avail_objs++;
  136. i -= fmp_->obj_size;
  137. }
  138. return 0;
  139. }
  140. static
  141. inline
  142. void*
  143. fmp_alloc(fmp_t *fmp_)
  144. {
  145. void *rv;
  146. if(fmp_->objs == NULL)
  147. fmp_slab_alloc(fmp_);
  148. if(fmp_->objs == NULL)
  149. return NULL;
  150. rv = fmp_->objs;
  151. fmp_->objs = fmp_->objs->next;
  152. fmp_->avail_objs--;
  153. return rv;
  154. }
  155. static
  156. inline
  157. void*
  158. fmp_calloc(fmp_t *fmp_)
  159. {
  160. void *obj;
  161. obj = fmp_alloc(fmp_);
  162. if(obj == NULL)
  163. return NULL;
  164. memset(obj,0,fmp_->obj_size);
  165. return obj;
  166. }
  167. static
  168. inline
  169. void
  170. fmp_free(fmp_t *fmp_,
  171. void *obj_)
  172. {
  173. mem_stack_t *obj = (mem_stack_t*)obj_;
  174. obj->next = fmp_->objs;
  175. fmp_->objs = obj;
  176. fmp_->avail_objs++;
  177. }
  178. static
  179. inline
  180. void
  181. fmp_clear(fmp_t *fmp_)
  182. {
  183. while(kv_size(fmp_->slabs))
  184. {
  185. void *slab = kv_pop(fmp_->slabs);
  186. fmp_slab_free_mmap(fmp_,slab);
  187. }
  188. fmp_->objs = NULL;
  189. fmp_->avail_objs = 0;
  190. }
  191. static
  192. inline
  193. void
  194. fmp_destroy(fmp_t *fmp_)
  195. {
  196. fmp_clear(fmp_);
  197. kv_destroy(fmp_->slabs);
  198. }
  199. static
  200. inline
  201. uint64_t
  202. fmp_avail_objs(fmp_t *fmp_)
  203. {
  204. return fmp_->avail_objs;
  205. }
  206. static
  207. inline
  208. uint64_t
  209. fmp_objs_in_slab(fmp_t *fmp_,
  210. void *slab_)
  211. {
  212. char *slab;
  213. uint64_t objs_in_slab;
  214. objs_in_slab = 0;
  215. slab = (char*)slab_;
  216. for(mem_stack_t *stack = fmp_->objs; stack != NULL; stack = stack->next)
  217. {
  218. char *obj = (char*)stack;
  219. if((obj >= slab) && (obj < (slab + fmp_->slab_size)))
  220. objs_in_slab++;
  221. }
  222. return objs_in_slab;
  223. }
  224. static
  225. inline
  226. void
  227. fmp_remove_objs_in_slab(fmp_t *fmp_,
  228. void *slab_)
  229. {
  230. char *slab = (char*)slab_;
  231. mem_stack_t **p = &fmp_->objs;
  232. while((*p) != NULL)
  233. {
  234. char *obj = (char*)*p;
  235. if((obj >= slab) && (obj < (slab + fmp_->slab_size)))
  236. {
  237. *p = (*p)->next;
  238. fmp_->avail_objs--;
  239. continue;
  240. }
  241. p = &(*p)->next;
  242. }
  243. }
  244. static
  245. inline
  246. int
  247. fmp_gc(fmp_t *fmp_)
  248. {
  249. int i;
  250. int freed_slabs;
  251. uint64_t objs_per_slab;
  252. objs_per_slab = (fmp_->slab_size / fmp_->obj_size);
  253. i = 0;
  254. freed_slabs = 0;
  255. while(i < kv_size(fmp_->slabs))
  256. {
  257. char *slab;
  258. uint64_t objs_in_slab;
  259. slab = kv_A(fmp_->slabs,i);
  260. objs_in_slab = fmp_objs_in_slab(fmp_,slab);
  261. if(objs_in_slab != objs_per_slab)
  262. {
  263. i++;
  264. continue;
  265. }
  266. fmp_remove_objs_in_slab(fmp_,slab);
  267. kv_delete(fmp_->slabs,i);
  268. fmp_slab_free_mmap(fmp_,slab);
  269. freed_slabs++;
  270. }
  271. return freed_slabs;
  272. }
  273. static
  274. inline
  275. uint64_t
  276. fmp_objs_per_slab(fmp_t *fmp_)
  277. {
  278. return (fmp_->slab_size / fmp_->obj_size);
  279. }
  280. static
  281. inline
  282. double
  283. fmp_slab_usage_ratio(fmp_t *fmp_)
  284. {
  285. double rv;
  286. uint64_t objs_per_slab;
  287. objs_per_slab = fmp_objs_per_slab(fmp_);
  288. rv = ((double)fmp_->avail_objs / (double)objs_per_slab);
  289. return rv;
  290. }
  291. static
  292. inline
  293. uint64_t
  294. fmp_total_allocated_memory(fmp_t *fmp_)
  295. {
  296. return (fmp_->slab_size * kv_size(fmp_->slabs));
  297. }