mempool.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. #include <ell/mempool.h>
  2. #include <assert.h>
  3. #include <stdio.h>
  4. #include <string.h>
  5. #ifndef ELL_MEMPOOL_DEFAULT_RESERVE
  6. #define ELL_MEMPOOL_DEFAULT_RESERVE 0
  7. #endif
  8. #ifndef ELL_MEMPOOL_DEFAULT_CHUNK_SIZE
  9. #define ELL_MEMPOOL_DEFAULT_CHUNK_SIZE 1024
  10. #endif
  11. #if ELL_MEMPOOL_DEFAULT_RESERVE < 0
  12. #error "negative ELL_MEMPOOL_DEFAULT_RESERVE"
  13. #endif
  14. #if ELL_MEMPOOL_DEFAULT_CHUNK_SIZE <= 0
  15. #error "non-positive ELL_MEMPOOL_DEFAULT_CHUNK_SIZE"
  16. #endif
  17. struct ell__mempool_chunk {
  18. struct ell__mempool_chunk* next_chunk;
  19. size_t chunk_size;
  20. void* data;
  21. };
  22. static void ell__mempool_add_chunk(struct ell_mempool* pool)
  23. {
  24. struct ell__mempool_chunk* chunk = malloc(sizeof(struct ell__mempool_chunk));
  25. chunk->data = malloc(pool->element_size * pool->chunk_size);
  26. chunk->next_chunk = pool->chunks;
  27. chunk->chunk_size = pool->chunk_size;
  28. pool->capacity += pool->chunk_size;
  29. pool->chunks = chunk;
  30. pool->size += pool->chunk_size;
  31. for (unsigned int i = 0; i < pool->chunk_size; i++) {
  32. ell_mempool_ret(pool, chunk->data + i * pool->element_size);
  33. }
  34. }
  35. /* Interface implementation */
  36. void ell_mempool_init(struct ell_mempool* pool, size_t element_size)
  37. {
  38. ell_mempool_init3(
  39. pool, element_size, ELL_MEMPOOL_DEFAULT_RESERVE, ELL_MEMPOOL_DEFAULT_CHUNK_SIZE);
  40. }
  41. void ell_mempool_init2(struct ell_mempool* pool, size_t element_size, size_t reserve)
  42. {
  43. ell_mempool_init3(pool, element_size, reserve, ELL_MEMPOOL_DEFAULT_CHUNK_SIZE);
  44. }
  45. void ell_mempool_init3(struct ell_mempool* pool,
  46. size_t element_size,
  47. size_t reserve,
  48. size_t chunk_size)
  49. {
  50. if (pool == NULL) {
  51. return;
  52. }
  53. /*
  54. * Leaky implementation detail:
  55. * The freelist is composed of pointers stored in element locations,
  56. * therefore an element must at least be able to hold one pointer.
  57. */
  58. if (element_size < sizeof(void*)) {
  59. fprintf(stderr,
  60. "%s: illegal ELEMENT SIZE of %ld, at least size of %ld required\n",
  61. __func__,
  62. element_size,
  63. sizeof(void*));
  64. abort();
  65. }
  66. memset(pool, 0, sizeof(*pool));
  67. pool->element_size = element_size;
  68. pool->chunk_size = chunk_size;
  69. pool->num_chunks = 0;
  70. pool->capacity = 0;
  71. pool->size = 0;
  72. pool->chunks = NULL;
  73. pool->next_free = NULL;
  74. /* allocate initial chunks */
  75. ell_mempool_reserve(pool, reserve);
  76. }
  77. void ell_mempool_free(struct ell_mempool* pool)
  78. {
  79. assert(pool != NULL);
  80. struct ell__mempool_chunk* chunk = pool->chunks;
  81. struct ell__mempool_chunk* tmp;
  82. while (chunk != NULL) {
  83. tmp = chunk->next_chunk;
  84. free(chunk->data);
  85. free(chunk);
  86. chunk = tmp;
  87. }
  88. }
  89. void ell_mempool_reserve(struct ell_mempool* pool, size_t reserve)
  90. {
  91. assert(pool != NULL);
  92. if (pool->capacity >= reserve) {
  93. return;
  94. }
  95. size_t required = reserve - pool->capacity;
  96. size_t required_chunks = required / pool->chunk_size + (required % pool->chunk_size ? 1 : 0);
  97. for (size_t i = 0; i < required_chunks; i++) {
  98. ell__mempool_add_chunk(pool);
  99. }
  100. }
  101. /* Memory management */
  102. void* ell_mempool_get(struct ell_mempool* pool)
  103. {
  104. assert(pool != NULL);
  105. while (pool->capacity <= pool->size) {
  106. ell__mempool_add_chunk(pool);
  107. }
  108. void* ptr = pool->next_free;
  109. pool->next_free = *((void**)ptr);
  110. pool->size++;
  111. return ptr;
  112. }
  113. void ell_mempool_ret(struct ell_mempool* pool, void* ptr)
  114. {
  115. assert(pool != NULL);
  116. *((void**)ptr) = pool->next_free;
  117. pool->next_free = ptr;
  118. pool->size--;
  119. }
  120. /* Queries */
  121. size_t ell_mempool_size(const struct ell_mempool* pool)
  122. {
  123. assert(pool != NULL);
  124. return pool->size;
  125. }
  126. size_t ell_mempool_capacity(const struct ell_mempool* pool)
  127. {
  128. assert(pool != NULL);
  129. return pool->capacity;
  130. }