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.

179 lines
4.9 KiB

10 years ago
  1. /* -*- coding: utf-8 -*-
  2. * ----------------------------------------------------------------------
  3. * Copyright © 2012-2013, 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. free(curr);
  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. free(mp);
  87. }
  88. void
  89. cork_mempool_set_callbacks(struct cork_mempool *mp,
  90. void *user_data, cork_free_f free_user_data,
  91. cork_init_f init_object,
  92. cork_done_f done_object)
  93. {
  94. cork_free_user_data(mp);
  95. mp->user_data = user_data;
  96. mp->free_user_data = free_user_data;
  97. mp->init_object = init_object;
  98. mp->done_object = done_object;
  99. }
  100. /* If this function succeeds, then we guarantee that there will be at
  101. * least one object in mp->free_list. */
  102. static void
  103. cork_mempool_new_block(struct cork_mempool *mp)
  104. {
  105. /* Allocate the new block and add it to mp's block list. */
  106. struct cork_mempool_block *block;
  107. void *vblock;
  108. DEBUG("Allocating new %zu-byte block\n", mp->block_size);
  109. block = cork_malloc(mp->block_size);
  110. block->next_block = mp->blocks;
  111. mp->blocks = block;
  112. vblock = block;
  113. /* Divide the block's memory region into a bunch of objects. */
  114. size_t index = sizeof(struct cork_mempool_block);
  115. for (index = sizeof(struct cork_mempool_block);
  116. (index + cork_mempool_object_size(mp)) <= mp->block_size;
  117. index += cork_mempool_object_size(mp)) {
  118. struct cork_mempool_object *obj = vblock + index;
  119. DEBUG(" New object at %p[%p]\n", cork_mempool_get_object(obj), obj);
  120. if (mp->init_object != NULL) {
  121. mp->init_object
  122. (mp->user_data, cork_mempool_get_object(obj));
  123. }
  124. obj->next_free = mp->free_list;
  125. mp->free_list = obj;
  126. }
  127. }
  128. void *
  129. cork_mempool_new_object(struct cork_mempool *mp)
  130. {
  131. struct cork_mempool_object *obj;
  132. void *ptr;
  133. if (CORK_UNLIKELY(mp->free_list == NULL)) {
  134. cork_mempool_new_block(mp);
  135. }
  136. obj = mp->free_list;
  137. mp->free_list = obj->next_free;
  138. mp->allocated_count++;
  139. ptr = cork_mempool_get_object(obj);
  140. return ptr;
  141. }
  142. void
  143. cork_mempool_free_object(struct cork_mempool *mp, void *ptr)
  144. {
  145. struct cork_mempool_object *obj = cork_mempool_get_header(ptr);
  146. DEBUG("Returning %p[%p] to memory pool\n", ptr, obj);
  147. obj->next_free = mp->free_list;
  148. mp->free_list = obj;
  149. mp->allocated_count--;
  150. }