quarantine.c revision 234370
1#include "jemalloc/internal/jemalloc_internal.h" 2 3/******************************************************************************/ 4/* Data. */ 5 6typedef struct quarantine_s quarantine_t; 7 8struct quarantine_s { 9 size_t curbytes; 10 size_t curobjs; 11 size_t first; 12#define LG_MAXOBJS_INIT 10 13 size_t lg_maxobjs; 14 void *objs[1]; /* Dynamically sized ring buffer. */ 15}; 16 17static void quarantine_cleanup(void *arg); 18 19malloc_tsd_data(static, quarantine, quarantine_t *, NULL) 20malloc_tsd_funcs(JEMALLOC_INLINE, quarantine, quarantine_t *, NULL, 21 quarantine_cleanup) 22 23/******************************************************************************/ 24/* Function prototypes for non-inline static functions. */ 25 26static quarantine_t *quarantine_init(size_t lg_maxobjs); 27static quarantine_t *quarantine_grow(quarantine_t *quarantine); 28static void quarantine_drain(quarantine_t *quarantine, size_t upper_bound); 29 30/******************************************************************************/ 31 32static quarantine_t * 33quarantine_init(size_t lg_maxobjs) 34{ 35 quarantine_t *quarantine; 36 37 quarantine = (quarantine_t *)imalloc(offsetof(quarantine_t, objs) + 38 ((ZU(1) << lg_maxobjs) * sizeof(void *))); 39 if (quarantine == NULL) 40 return (NULL); 41 quarantine->curbytes = 0; 42 quarantine->curobjs = 0; 43 quarantine->first = 0; 44 quarantine->lg_maxobjs = lg_maxobjs; 45 46 quarantine_tsd_set(&quarantine); 47 48 return (quarantine); 49} 50 51static quarantine_t * 52quarantine_grow(quarantine_t *quarantine) 53{ 54 quarantine_t *ret; 55 56 ret = quarantine_init(quarantine->lg_maxobjs + 1); 57 if (ret == NULL) 58 return (quarantine); 59 60 ret->curbytes = quarantine->curbytes; 61 if (quarantine->first + quarantine->curobjs < (ZU(1) << 62 quarantine->lg_maxobjs)) { 63 /* objs ring buffer data are contiguous. */ 64 memcpy(ret->objs, &quarantine->objs[quarantine->first], 65 quarantine->curobjs * sizeof(void *)); 66 ret->curobjs = quarantine->curobjs; 67 } else { 68 /* objs ring buffer data wrap around. */ 69 size_t ncopy = (ZU(1) << quarantine->lg_maxobjs) - 70 quarantine->first; 71 memcpy(ret->objs, &quarantine->objs[quarantine->first], ncopy * 72 sizeof(void *)); 73 ret->curobjs = ncopy; 74 if (quarantine->curobjs != 0) { 75 memcpy(&ret->objs[ret->curobjs], quarantine->objs, 76 quarantine->curobjs - ncopy); 77 } 78 } 79 80 return (ret); 81} 82 83static void 84quarantine_drain(quarantine_t *quarantine, size_t upper_bound) 85{ 86 87 while (quarantine->curbytes > upper_bound && quarantine->curobjs > 0) { 88 void *ptr = quarantine->objs[quarantine->first]; 89 size_t usize = isalloc(ptr, config_prof); 90 idalloc(ptr); 91 quarantine->curbytes -= usize; 92 quarantine->curobjs--; 93 quarantine->first = (quarantine->first + 1) & ((ZU(1) << 94 quarantine->lg_maxobjs) - 1); 95 } 96} 97 98void 99quarantine(void *ptr) 100{ 101 quarantine_t *quarantine; 102 size_t usize = isalloc(ptr, config_prof); 103 104 assert(config_fill); 105 assert(opt_quarantine); 106 107 quarantine = *quarantine_tsd_get(); 108 if (quarantine == NULL && (quarantine = 109 quarantine_init(LG_MAXOBJS_INIT)) == NULL) { 110 idalloc(ptr); 111 return; 112 } 113 /* 114 * Drain one or more objects if the quarantine size limit would be 115 * exceeded by appending ptr. 116 */ 117 if (quarantine->curbytes + usize > opt_quarantine) { 118 size_t upper_bound = (opt_quarantine >= usize) ? opt_quarantine 119 - usize : 0; 120 quarantine_drain(quarantine, upper_bound); 121 } 122 /* Grow the quarantine ring buffer if it's full. */ 123 if (quarantine->curobjs == (ZU(1) << quarantine->lg_maxobjs)) 124 quarantine = quarantine_grow(quarantine); 125 /* quarantine_grow() must free a slot if it fails to grow. */ 126 assert(quarantine->curobjs < (ZU(1) << quarantine->lg_maxobjs)); 127 /* Append ptr if its size doesn't exceed the quarantine size. */ 128 if (quarantine->curbytes + usize <= opt_quarantine) { 129 size_t offset = (quarantine->first + quarantine->curobjs) & 130 ((ZU(1) << quarantine->lg_maxobjs) - 1); 131 quarantine->objs[offset] = ptr; 132 quarantine->curbytes += usize; 133 quarantine->curobjs++; 134 if (opt_junk) 135 memset(ptr, 0x5a, usize); 136 } else { 137 assert(quarantine->curbytes == 0); 138 idalloc(ptr); 139 } 140} 141 142static void 143quarantine_cleanup(void *arg) 144{ 145 quarantine_t *quarantine = *(quarantine_t **)arg; 146 147 if (quarantine != NULL) { 148 quarantine_drain(quarantine, 0); 149 idalloc(quarantine); 150 } 151} 152 153bool 154quarantine_boot(void) 155{ 156 157 assert(config_fill); 158 159 if (quarantine_tsd_boot()) 160 return (true); 161 162 return (false); 163} 164