mpool.h 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. #ifndef MPOOL_H_
  2. #define MPOOL_H_
  3. #include <assert.h>
  4. #include <stdint.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include "ctassert.h"
  8. /**
  9. * Memory allocator cache. Memory allocations can be returned to the pool
  10. * and reused by a subsequent allocation without returning all the way to
  11. * free/malloc. In effect, this is an optimization for the case where we
  12. * know we will want another allocation of the same size soon, at the expense
  13. * of keeping memory allocated (and thus preventing any other code from
  14. * allocating the same memory).
  15. */
  16. /* Internal data. */
  17. struct mpool {
  18. size_t stacklen;
  19. size_t allocsize;
  20. void ** allocs;
  21. uint64_t nallocs;
  22. uint64_t nempties;
  23. int state;
  24. void ** allocs_static;
  25. void (* atexitfunc)(void);
  26. };
  27. static inline void
  28. mpool_atexit(struct mpool * M)
  29. {
  30. while (M->stacklen)
  31. free(M->allocs[--M->stacklen]);
  32. if (M->allocs != M->allocs_static)
  33. free(M->allocs);
  34. }
  35. static inline void *
  36. mpool_malloc(struct mpool * M, size_t len)
  37. {
  38. M->nallocs++;
  39. if (M->stacklen)
  40. return (M->allocs[--(M->stacklen)]);
  41. M->nempties++;
  42. if (M->state == 0) {
  43. atexit(M->atexitfunc);
  44. M->state = 1;
  45. }
  46. return (malloc(len));
  47. }
  48. static inline void
  49. mpool_free(struct mpool * M, void * p)
  50. {
  51. void ** allocs_new;
  52. if (p == NULL)
  53. return;
  54. if (M->stacklen < M->allocsize) {
  55. M->allocs[M->stacklen++] = p;
  56. return;
  57. }
  58. if (M->nempties > (M->nallocs >> 8)) {
  59. /* Sanity check. */
  60. assert(M->allocsize > 0);
  61. allocs_new = (void **)malloc(M->allocsize * 2 * sizeof(void *));
  62. if (allocs_new) {
  63. memcpy(allocs_new, M->allocs,
  64. M->allocsize * sizeof(void *));
  65. if (M->allocs != M->allocs_static)
  66. free(M->allocs);
  67. M->allocs = allocs_new;
  68. M->allocsize = M->allocsize * 2;
  69. M->allocs[M->stacklen++] = p;
  70. } else
  71. free(p);
  72. } else
  73. free(p);
  74. M->nempties = 0;
  75. M->nallocs = 0;
  76. }
  77. /**
  78. * MPOOL(name, type, size):
  79. * Define the functions
  80. *
  81. * ${type} * mpool_${name}_malloc(void);
  82. * void mpool_${name}_free(${type} *);
  83. *
  84. * which allocate and free structures of type ${type}. A minimum of ${size}
  85. * such structures are kept cached after _free is called in order to allow
  86. * future _malloc calls to be rapidly serviced; this limit will be autotuned
  87. * upwards depending on the allocation/free pattern.
  88. *
  89. * Cached structures will be freed at program exit time in order to aid
  90. * in the detection of memory leaks.
  91. */
  92. #define MPOOL(name, type, size) \
  93. static void mpool_##name##_atexit(void); \
  94. static void * mpool_##name##_static[size]; \
  95. static struct mpool mpool_##name##_rec = \
  96. {0, size, mpool_##name##_static, 0, 0, 0, \
  97. mpool_##name##_static, mpool_##name##_atexit}; \
  98. \
  99. CTASSERT(size > 0); \
  100. \
  101. static void \
  102. mpool_##name##_atexit(void) \
  103. { \
  104. \
  105. mpool_atexit(&mpool_##name##_rec); \
  106. } \
  107. \
  108. static inline type * \
  109. mpool_##name##_malloc(void) \
  110. { \
  111. \
  112. return (mpool_malloc(&mpool_##name##_rec, sizeof(type))); \
  113. } \
  114. \
  115. static inline void \
  116. mpool_##name##_free(type * p) \
  117. { \
  118. \
  119. mpool_free(&mpool_##name##_rec, p); \
  120. } \
  121. \
  122. static void (* mpool_##name##_dummyptr)(void); \
  123. static inline void \
  124. mpool_##name##_dummyfunc(void) \
  125. { \
  126. \
  127. (void)mpool_##name##_malloc; \
  128. (void)mpool_##name##_free; \
  129. (void)mpool_##name##_dummyptr; \
  130. } \
  131. static void (* mpool_##name##_dummyptr)(void) = mpool_##name##_dummyfunc; \
  132. struct mpool_##name##_dummy
  133. #endif /* !MPOOL_H_ */