mempool.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. // Public Domain
  2. #include <stdlib.h>
  3. #include <stdio.h>
  4. #include <errno.h>
  5. #include <string.h>
  6. #include <sys/mman.h>
  7. #include "mempool.h"
  8. MemPool* MemPool_alloc(size_t itemSize, size_t maxItems) {
  9. MemPool* mp;
  10. mp = calloc(1, sizeof(*mp));
  11. MemPool_init(mp, itemSize, maxItems);
  12. return mp;
  13. }
  14. void MemPool_init(MemPool* mp, size_t itemSize, size_t maxItems) {
  15. size_t allocSize;
  16. mp->itemSize = itemSize < sizeof(size_t) ? sizeof(size_t) : itemSize;
  17. mp->maxItems = maxItems;
  18. mp->fill = 0;
  19. mp->firstFree = 1; // first free is 1-based
  20. allocSize = mp->itemSize * mp->maxItems;
  21. int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE;
  22. mp->pool = mmap(NULL, allocSize, PROT_READ | PROT_WRITE, flags, 0, 0);
  23. if(mp->pool == MAP_FAILED) {
  24. fprintf(stderr, "mmap failed in %s: %s\n", __func__, strerror(errno));
  25. exit(1);
  26. }
  27. }
  28. void MemPoolT_destroy(MemPoolT* mp) {
  29. free(mp->bitfield);
  30. munmap(mp->pool, mp->itemSize * mp->maxItems);
  31. mp->maxItems = 0;
  32. mp->fill = 0;
  33. mp->firstFree = 0;
  34. }
  35. void* MemPool_malloc(MemPool* mp) {
  36. if(mp->fill >= mp->maxItems) {
  37. fprintf(stderr, "MemPool overflowed max items %ld\n", mp->maxItems);
  38. return NULL;
  39. }
  40. size_t off = mp->itemSize * (mp->firstFree - 1);
  41. size_t next = *(size_t*)((char*)mp->pool + off);
  42. if(next == 0) next = mp->firstFree + 1;
  43. mp->firstFree = next;
  44. // not used in operation
  45. mp->fill++;
  46. return (char*)mp->pool + off;
  47. }
  48. void* MemPool_calloc(MemPool* mp) {
  49. void* p = MemPool_malloc(mp);
  50. memset(p, 0, mp->itemSize);
  51. return p;
  52. }
  53. void MemPool_free(MemPool* mp, void* ptr) {
  54. size_t ooff = mp->itemSize * (mp->firstFree - 1);
  55. size_t noff = ((char*)ptr - (char*)mp->pool) / mp->itemSize;
  56. *(size_t*)((char*)mp->pool + ooff) = noff + 1;
  57. // not used in operation
  58. mp->fill--;
  59. }
  60. // -------------------------------------------
  61. // tracked mempool
  62. MemPoolT* MemPoolT_alloc(size_t itemSize, size_t maxItems) {
  63. MemPoolT* mp;
  64. mp = calloc(1, sizeof(*mp));
  65. MemPoolT_init(mp, itemSize, maxItems);
  66. return mp;
  67. }
  68. void MemPoolT_init(MemPoolT* mp, size_t itemSize, size_t maxItems) {
  69. size_t allocSize;
  70. mp->itemSize = itemSize < sizeof(size_t) ? sizeof(size_t) : itemSize;
  71. mp->maxItems = maxItems;
  72. mp->fill = 0;
  73. mp->firstFree = 1; // first free is 1-based
  74. mp->highestUsed = 0;
  75. mp->bitfieldAlloc = 0;
  76. mp->bitfield = NULL;
  77. allocSize = mp->itemSize * mp->maxItems;
  78. int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE;
  79. mp->pool = mmap(NULL, allocSize, PROT_READ | PROT_WRITE, flags, 0, 0);
  80. if(!mp->pool || mp->pool == MAP_FAILED) {
  81. fprintf(stderr, "mmap failed in %s: %s\n", __func__, strerror(errno));
  82. exit(1);
  83. }
  84. }
  85. static inline void mpt_check_bitfield(MemPoolT* mp) {
  86. if((mp->fill / 64) + ((mp->fill % 64) > 0) >= mp->bitfieldAlloc) {
  87. mp->bitfieldAlloc = mp->bitfieldAlloc < 8 ? 8 : mp->bitfieldAlloc * 2;
  88. mp->bitfield = realloc(mp->bitfield, sizeof(*mp->bitfield) * mp->bitfieldAlloc);
  89. }
  90. }
  91. static inline size_t mpt_get_bf_index(MemPoolT* mp, size_t index) {
  92. (void)mp;
  93. return ((index - 1) / 64);
  94. }
  95. static inline int mpt_get_bf_bit(MemPoolT* mp, size_t index) {
  96. (void)mp;
  97. return ((index - 1) % 64);
  98. }
  99. static inline uint64_t mpt_get_bf_mask(MemPoolT* mp, size_t index) {
  100. return ((uint64_t)1) << mpt_get_bf_bit(mp, index);
  101. }
  102. static inline void mpt_set_bit(MemPoolT* mp, size_t index) {
  103. uint64_t mask = mpt_get_bf_mask(mp, index);
  104. int i = mpt_get_bf_index(mp, index);
  105. mp->bitfield[i] |= mask;
  106. }
  107. static inline void mpt_clear_bit(MemPoolT* mp, size_t index) {
  108. mp->bitfield[mpt_get_bf_index(mp, index)] &= ~mpt_get_bf_mask(mp, index);
  109. }
  110. static inline int mpt_get_bit(MemPoolT* mp, size_t index) {
  111. return 0 != (mp->bitfield[mpt_get_bf_index(mp, index)] & mpt_get_bf_mask(mp, index));
  112. }
  113. void* MemPoolT_malloc(MemPoolT* mp) {
  114. if(mp->fill >= mp->maxItems) {
  115. fprintf(stderr, "MemPool overflowed max items %ld\n", mp->maxItems);
  116. return NULL;
  117. }
  118. mpt_check_bitfield(mp);
  119. size_t off = mp->itemSize * (mp->firstFree - 1);
  120. size_t next = *(size_t*)((char*)mp->pool + off);
  121. if(next == 0) next = mp->firstFree + 1;
  122. mpt_set_bit(mp, mp->firstFree);
  123. mp->firstFree = next;
  124. mp->highestUsed = next > mp->highestUsed ? next : mp->highestUsed;
  125. mp->fill++;
  126. return (char*)mp->pool + off;
  127. }
  128. void MemPoolT_free(MemPoolT* mp, void* ptr) {
  129. size_t ooff = mp->itemSize * (mp->firstFree - 1);
  130. size_t noff = ((char*)ptr - (char*)mp->pool) / mp->itemSize;
  131. if(mpt_get_bit(mp, noff + 1)) {
  132. mpt_clear_bit(mp, noff + 1);
  133. *(size_t*)((char*)mp->pool + ooff) = noff + 1;
  134. mp->fill--;
  135. }
  136. }
  137. // these are 0-based indices used for iteration
  138. int MemPoolT_isSlotUsed(MemPoolT* mp, size_t index) {
  139. return mpt_get_bit(mp, index + 1);
  140. }
  141. void* MemPoolT_getNextUsedIndex(MemPoolT* mp, size_t* index) {
  142. if(mp->fill <= 0) return NULL;
  143. while(!mpt_get_bit(mp, *index + 1)) {
  144. (*index)++;
  145. if(*index >= mp->highestUsed - 1) {
  146. return NULL;
  147. }
  148. }
  149. if(*index >= mp->highestUsed - 1) return NULL;
  150. return (char*)mp->pool + ((*index) * mp->itemSize);
  151. }
  152. int MemPoolT_ownsPointer(MemPoolT* mp, void* ptr) {
  153. return ptr >= mp->pool && (char*)ptr < (char*)mp->pool + (mp->itemSize * mp->maxItems);
  154. }