PageRenderTime 56ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/jemalloc-3.0.0/src/quarantine.c

#
C | 210 lines | 147 code | 30 blank | 33 comment | 32 complexity | 7d4297ec21a637586991567d39f4b174 MD5 | raw file
Possible License(s): BSD-2-Clause
  1. #include "jemalloc/internal/jemalloc_internal.h"
  2. /*
  3. * quarantine pointers close to NULL are used to encode state information that
  4. * is used for cleaning up during thread shutdown.
  5. */
  6. #define QUARANTINE_STATE_REINCARNATED ((quarantine_t *)(uintptr_t)1)
  7. #define QUARANTINE_STATE_PURGATORY ((quarantine_t *)(uintptr_t)2)
  8. #define QUARANTINE_STATE_MAX QUARANTINE_STATE_PURGATORY
  9. /******************************************************************************/
  10. /* Data. */
  11. typedef struct quarantine_obj_s quarantine_obj_t;
  12. typedef struct quarantine_s quarantine_t;
  13. struct quarantine_obj_s {
  14. void *ptr;
  15. size_t usize;
  16. };
  17. struct quarantine_s {
  18. size_t curbytes;
  19. size_t curobjs;
  20. size_t first;
  21. #define LG_MAXOBJS_INIT 10
  22. size_t lg_maxobjs;
  23. quarantine_obj_t objs[1]; /* Dynamically sized ring buffer. */
  24. };
  25. static void quarantine_cleanup(void *arg);
  26. malloc_tsd_data(static, quarantine, quarantine_t *, NULL)
  27. malloc_tsd_funcs(JEMALLOC_INLINE, quarantine, quarantine_t *, NULL,
  28. quarantine_cleanup)
  29. /******************************************************************************/
  30. /* Function prototypes for non-inline static functions. */
  31. static quarantine_t *quarantine_init(size_t lg_maxobjs);
  32. static quarantine_t *quarantine_grow(quarantine_t *quarantine);
  33. static void quarantine_drain(quarantine_t *quarantine, size_t upper_bound);
  34. /******************************************************************************/
  35. static quarantine_t *
  36. quarantine_init(size_t lg_maxobjs)
  37. {
  38. quarantine_t *quarantine;
  39. quarantine = (quarantine_t *)imalloc(offsetof(quarantine_t, objs) +
  40. ((ZU(1) << lg_maxobjs) * sizeof(quarantine_obj_t)));
  41. if (quarantine == NULL)
  42. return (NULL);
  43. quarantine->curbytes = 0;
  44. quarantine->curobjs = 0;
  45. quarantine->first = 0;
  46. quarantine->lg_maxobjs = lg_maxobjs;
  47. quarantine_tsd_set(&quarantine);
  48. return (quarantine);
  49. }
  50. static quarantine_t *
  51. quarantine_grow(quarantine_t *quarantine)
  52. {
  53. quarantine_t *ret;
  54. ret = quarantine_init(quarantine->lg_maxobjs + 1);
  55. if (ret == NULL)
  56. return (quarantine);
  57. ret->curbytes = quarantine->curbytes;
  58. ret->curobjs = quarantine->curobjs;
  59. if (quarantine->first + quarantine->curobjs <= (ZU(1) <<
  60. quarantine->lg_maxobjs)) {
  61. /* objs ring buffer data are contiguous. */
  62. memcpy(ret->objs, &quarantine->objs[quarantine->first],
  63. quarantine->curobjs * sizeof(quarantine_obj_t));
  64. } else {
  65. /* objs ring buffer data wrap around. */
  66. size_t ncopy_a = (ZU(1) << quarantine->lg_maxobjs) -
  67. quarantine->first;
  68. size_t ncopy_b = quarantine->curobjs - ncopy_a;
  69. memcpy(ret->objs, &quarantine->objs[quarantine->first], ncopy_a
  70. * sizeof(quarantine_obj_t));
  71. memcpy(&ret->objs[ncopy_a], quarantine->objs, ncopy_b *
  72. sizeof(quarantine_obj_t));
  73. }
  74. return (ret);
  75. }
  76. static void
  77. quarantine_drain(quarantine_t *quarantine, size_t upper_bound)
  78. {
  79. while (quarantine->curbytes > upper_bound && quarantine->curobjs > 0) {
  80. quarantine_obj_t *obj = &quarantine->objs[quarantine->first];
  81. assert(obj->usize == isalloc(obj->ptr, config_prof));
  82. idalloc(obj->ptr);
  83. quarantine->curbytes -= obj->usize;
  84. quarantine->curobjs--;
  85. quarantine->first = (quarantine->first + 1) & ((ZU(1) <<
  86. quarantine->lg_maxobjs) - 1);
  87. }
  88. }
  89. void
  90. quarantine(void *ptr)
  91. {
  92. quarantine_t *quarantine;
  93. size_t usize = isalloc(ptr, config_prof);
  94. cassert(config_fill);
  95. assert(opt_quarantine);
  96. quarantine = *quarantine_tsd_get();
  97. if ((uintptr_t)quarantine <= (uintptr_t)QUARANTINE_STATE_MAX) {
  98. if (quarantine == NULL) {
  99. if ((quarantine = quarantine_init(LG_MAXOBJS_INIT)) ==
  100. NULL) {
  101. idalloc(ptr);
  102. return;
  103. }
  104. } else {
  105. if (quarantine == QUARANTINE_STATE_PURGATORY) {
  106. /*
  107. * Make a note that quarantine() was called
  108. * after quarantine_cleanup() was called.
  109. */
  110. quarantine = QUARANTINE_STATE_REINCARNATED;
  111. quarantine_tsd_set(&quarantine);
  112. }
  113. idalloc(ptr);
  114. return;
  115. }
  116. }
  117. /*
  118. * Drain one or more objects if the quarantine size limit would be
  119. * exceeded by appending ptr.
  120. */
  121. if (quarantine->curbytes + usize > opt_quarantine) {
  122. size_t upper_bound = (opt_quarantine >= usize) ? opt_quarantine
  123. - usize : 0;
  124. quarantine_drain(quarantine, upper_bound);
  125. }
  126. /* Grow the quarantine ring buffer if it's full. */
  127. if (quarantine->curobjs == (ZU(1) << quarantine->lg_maxobjs))
  128. quarantine = quarantine_grow(quarantine);
  129. /* quarantine_grow() must free a slot if it fails to grow. */
  130. assert(quarantine->curobjs < (ZU(1) << quarantine->lg_maxobjs));
  131. /* Append ptr if its size doesn't exceed the quarantine size. */
  132. if (quarantine->curbytes + usize <= opt_quarantine) {
  133. size_t offset = (quarantine->first + quarantine->curobjs) &
  134. ((ZU(1) << quarantine->lg_maxobjs) - 1);
  135. quarantine_obj_t *obj = &quarantine->objs[offset];
  136. obj->ptr = ptr;
  137. obj->usize = usize;
  138. quarantine->curbytes += usize;
  139. quarantine->curobjs++;
  140. if (opt_junk)
  141. memset(ptr, 0x5a, usize);
  142. } else {
  143. assert(quarantine->curbytes == 0);
  144. idalloc(ptr);
  145. }
  146. }
  147. static void
  148. quarantine_cleanup(void *arg)
  149. {
  150. quarantine_t *quarantine = *(quarantine_t **)arg;
  151. if (quarantine == QUARANTINE_STATE_REINCARNATED) {
  152. /*
  153. * Another destructor deallocated memory after this destructor
  154. * was called. Reset quarantine to QUARANTINE_STATE_PURGATORY
  155. * in order to receive another callback.
  156. */
  157. quarantine = QUARANTINE_STATE_PURGATORY;
  158. quarantine_tsd_set(&quarantine);
  159. } else if (quarantine == QUARANTINE_STATE_PURGATORY) {
  160. /*
  161. * The previous time this destructor was called, we set the key
  162. * to QUARANTINE_STATE_PURGATORY so that other destructors
  163. * wouldn't cause re-creation of the quarantine. This time, do
  164. * nothing, so that the destructor will not be called again.
  165. */
  166. } else if (quarantine != NULL) {
  167. quarantine_drain(quarantine, 0);
  168. idalloc(quarantine);
  169. quarantine = QUARANTINE_STATE_PURGATORY;
  170. quarantine_tsd_set(&quarantine);
  171. }
  172. }
  173. bool
  174. quarantine_boot(void)
  175. {
  176. cassert(config_fill);
  177. if (quarantine_tsd_boot())
  178. return (true);
  179. return (false);
  180. }