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.

198 lines
5.4 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. /* -*- coding: utf-8 -*-
  2. * ----------------------------------------------------------------------
  3. * Copyright © 2012-2015, RedJack, LLC.
  4. * All rights reserved.
  5. *
  6. * Please see the COPYING file in this distribution for license details.
  7. * ----------------------------------------------------------------------
  8. */
  9. #include <assert.h>
  10. #include <stdlib.h>
  11. #include "libcork/core/callbacks.h"
  12. #include "libcork/core/mempool.h"
  13. #include "libcork/core/types.h"
  14. #include "libcork/helpers/errors.h"
  15. #if !defined(CORK_DEBUG_MEMPOOL)
  16. #define CORK_DEBUG_MEMPOOL 0
  17. #endif
  18. #if CORK_DEBUG_MEMPOOL
  19. #include <stdio.h>
  20. #define DEBUG(...) fprintf(stderr, __VA_ARGS__)
  21. #else
  22. #define DEBUG(...) /* no debug messages */
  23. #endif
  24. struct cork_mempool {
  25. size_t element_size;
  26. size_t block_size;
  27. struct cork_mempool_object *free_list;
  28. /* The number of objects that have been given out by
  29. * cork_mempool_new but not returned via cork_mempool_free. */
  30. size_t allocated_count;
  31. struct cork_mempool_block *blocks;
  32. void *user_data;
  33. cork_free_f free_user_data;
  34. cork_init_f init_object;
  35. cork_done_f done_object;
  36. };
  37. struct cork_mempool_object {
  38. /* When this object is unclaimed, it will be in the cork_mempool
  39. * object's free_list using this pointer. */
  40. struct cork_mempool_object *next_free;
  41. };
  42. struct cork_mempool_block {
  43. struct cork_mempool_block *next_block;
  44. };
  45. #define cork_mempool_object_size(mp) \
  46. (sizeof(struct cork_mempool_object) + (mp)->element_size)
  47. #define cork_mempool_get_header(obj) \
  48. (((struct cork_mempool_object *) (obj)) - 1)
  49. #define cork_mempool_get_object(hdr) \
  50. ((void *) (((struct cork_mempool_object *) (hdr)) + 1))
  51. struct cork_mempool *
  52. cork_mempool_new_size_ex(size_t element_size, size_t block_size)
  53. {
  54. struct cork_mempool *mp = cork_new(struct cork_mempool);
  55. mp->element_size = element_size;
  56. mp->block_size = block_size;
  57. mp->free_list = NULL;
  58. mp->allocated_count = 0;
  59. mp->blocks = NULL;
  60. mp->user_data = NULL;
  61. mp->free_user_data = NULL;
  62. mp->init_object = NULL;
  63. mp->done_object = NULL;
  64. return mp;
  65. }
  66. void
  67. cork_mempool_free(struct cork_mempool *mp)
  68. {
  69. struct cork_mempool_block *curr;
  70. assert(mp->allocated_count == 0);
  71. if (mp->done_object != NULL) {
  72. struct cork_mempool_object *obj;
  73. for (obj = mp->free_list; obj != NULL; obj = obj->next_free) {
  74. mp->done_object
  75. (mp->user_data, cork_mempool_get_object(obj));
  76. }
  77. }
  78. for (curr = mp->blocks; curr != NULL; ) {
  79. struct cork_mempool_block *next = curr->next_block;
  80. cork_free(curr, mp->block_size);
  81. /* Do this here instead of in the for statement to avoid
  82. * accessing the just-freed block. */
  83. curr = next;
  84. }
  85. cork_free_user_data(mp);
  86. cork_delete(struct cork_mempool, mp);
  87. }
  88. void
  89. cork_mempool_set_user_data(struct cork_mempool *mp,
  90. void *user_data, cork_free_f free_user_data)
  91. {
  92. cork_free_user_data(mp);
  93. mp->user_data = user_data;
  94. mp->free_user_data = free_user_data;
  95. }
  96. void
  97. cork_mempool_set_init_object(struct cork_mempool *mp, cork_init_f init_object)
  98. {
  99. mp->init_object = init_object;
  100. }
  101. void
  102. cork_mempool_set_done_object(struct cork_mempool *mp, cork_done_f done_object)
  103. {
  104. mp->done_object = done_object;
  105. }
  106. void
  107. cork_mempool_set_callbacks(struct cork_mempool *mp,
  108. void *user_data, cork_free_f free_user_data,
  109. cork_init_f init_object,
  110. cork_done_f done_object)
  111. {
  112. cork_mempool_set_user_data(mp, user_data, free_user_data);
  113. cork_mempool_set_init_object(mp, init_object);
  114. cork_mempool_set_done_object(mp, done_object);
  115. }
  116. /* If this function succeeds, then we guarantee that there will be at
  117. * least one object in mp->free_list. */
  118. static void
  119. cork_mempool_new_block(struct cork_mempool *mp)
  120. {
  121. /* Allocate the new block and add it to mp's block list. */
  122. struct cork_mempool_block *block;
  123. void *vblock;
  124. DEBUG("Allocating new %zu-byte block\n", mp->block_size);
  125. block = cork_malloc(mp->block_size);
  126. block->next_block = mp->blocks;
  127. mp->blocks = block;
  128. vblock = block;
  129. /* Divide the block's memory region into a bunch of objects. */
  130. size_t index = sizeof(struct cork_mempool_block);
  131. for (index = sizeof(struct cork_mempool_block);
  132. (index + cork_mempool_object_size(mp)) <= mp->block_size;
  133. index += cork_mempool_object_size(mp)) {
  134. struct cork_mempool_object *obj = vblock + index;
  135. DEBUG(" New object at %p[%p]\n", cork_mempool_get_object(obj), obj);
  136. if (mp->init_object != NULL) {
  137. mp->init_object
  138. (mp->user_data, cork_mempool_get_object(obj));
  139. }
  140. obj->next_free = mp->free_list;
  141. mp->free_list = obj;
  142. }
  143. }
  144. void *
  145. cork_mempool_new_object(struct cork_mempool *mp)
  146. {
  147. struct cork_mempool_object *obj;
  148. void *ptr;
  149. if (CORK_UNLIKELY(mp->free_list == NULL)) {
  150. cork_mempool_new_block(mp);
  151. }
  152. obj = mp->free_list;
  153. mp->free_list = obj->next_free;
  154. mp->allocated_count++;
  155. ptr = cork_mempool_get_object(obj);
  156. return ptr;
  157. }
  158. void
  159. cork_mempool_free_object(struct cork_mempool *mp, void *ptr)
  160. {
  161. struct cork_mempool_object *obj = cork_mempool_get_header(ptr);
  162. DEBUG("Returning %p[%p] to memory pool\n", ptr, obj);
  163. obj->next_free = mp->free_list;
  164. mp->free_list = obj;
  165. mp->allocated_count--;
  166. }