quarantine.c revision 234543
1234370Sjasone#include "jemalloc/internal/jemalloc_internal.h" 2234370Sjasone 3234370Sjasone/******************************************************************************/ 4234370Sjasone/* Data. */ 5234370Sjasone 6234370Sjasonetypedef struct quarantine_s quarantine_t; 7234370Sjasone 8234370Sjasonestruct quarantine_s { 9234370Sjasone size_t curbytes; 10234370Sjasone size_t curobjs; 11234370Sjasone size_t first; 12234370Sjasone#define LG_MAXOBJS_INIT 10 13234370Sjasone size_t lg_maxobjs; 14234370Sjasone void *objs[1]; /* Dynamically sized ring buffer. */ 15234370Sjasone}; 16234370Sjasone 17234370Sjasonestatic void quarantine_cleanup(void *arg); 18234370Sjasone 19234370Sjasonemalloc_tsd_data(static, quarantine, quarantine_t *, NULL) 20234370Sjasonemalloc_tsd_funcs(JEMALLOC_INLINE, quarantine, quarantine_t *, NULL, 21234370Sjasone quarantine_cleanup) 22234370Sjasone 23234370Sjasone/******************************************************************************/ 24234370Sjasone/* Function prototypes for non-inline static functions. */ 25234370Sjasone 26234370Sjasonestatic quarantine_t *quarantine_init(size_t lg_maxobjs); 27234370Sjasonestatic quarantine_t *quarantine_grow(quarantine_t *quarantine); 28234370Sjasonestatic void quarantine_drain(quarantine_t *quarantine, size_t upper_bound); 29234370Sjasone 30234370Sjasone/******************************************************************************/ 31234370Sjasone 32234370Sjasonestatic quarantine_t * 33234370Sjasonequarantine_init(size_t lg_maxobjs) 34234370Sjasone{ 35234370Sjasone quarantine_t *quarantine; 36234370Sjasone 37234370Sjasone quarantine = (quarantine_t *)imalloc(offsetof(quarantine_t, objs) + 38234370Sjasone ((ZU(1) << lg_maxobjs) * sizeof(void *))); 39234370Sjasone if (quarantine == NULL) 40234370Sjasone return (NULL); 41234370Sjasone quarantine->curbytes = 0; 42234370Sjasone quarantine->curobjs = 0; 43234370Sjasone quarantine->first = 0; 44234370Sjasone quarantine->lg_maxobjs = lg_maxobjs; 45234370Sjasone 46234370Sjasone quarantine_tsd_set(&quarantine); 47234370Sjasone 48234370Sjasone return (quarantine); 49234370Sjasone} 50234370Sjasone 51234370Sjasonestatic quarantine_t * 52234370Sjasonequarantine_grow(quarantine_t *quarantine) 53234370Sjasone{ 54234370Sjasone quarantine_t *ret; 55234370Sjasone 56234370Sjasone ret = quarantine_init(quarantine->lg_maxobjs + 1); 57234370Sjasone if (ret == NULL) 58234370Sjasone return (quarantine); 59234370Sjasone 60234370Sjasone ret->curbytes = quarantine->curbytes; 61234370Sjasone if (quarantine->first + quarantine->curobjs < (ZU(1) << 62234370Sjasone quarantine->lg_maxobjs)) { 63234370Sjasone /* objs ring buffer data are contiguous. */ 64234370Sjasone memcpy(ret->objs, &quarantine->objs[quarantine->first], 65234370Sjasone quarantine->curobjs * sizeof(void *)); 66234370Sjasone ret->curobjs = quarantine->curobjs; 67234370Sjasone } else { 68234370Sjasone /* objs ring buffer data wrap around. */ 69234370Sjasone size_t ncopy = (ZU(1) << quarantine->lg_maxobjs) - 70234370Sjasone quarantine->first; 71234370Sjasone memcpy(ret->objs, &quarantine->objs[quarantine->first], ncopy * 72234370Sjasone sizeof(void *)); 73234370Sjasone ret->curobjs = ncopy; 74234370Sjasone if (quarantine->curobjs != 0) { 75234370Sjasone memcpy(&ret->objs[ret->curobjs], quarantine->objs, 76234370Sjasone quarantine->curobjs - ncopy); 77234370Sjasone } 78234370Sjasone } 79234370Sjasone 80234370Sjasone return (ret); 81234370Sjasone} 82234370Sjasone 83234370Sjasonestatic void 84234370Sjasonequarantine_drain(quarantine_t *quarantine, size_t upper_bound) 85234370Sjasone{ 86234370Sjasone 87234370Sjasone while (quarantine->curbytes > upper_bound && quarantine->curobjs > 0) { 88234370Sjasone void *ptr = quarantine->objs[quarantine->first]; 89234370Sjasone size_t usize = isalloc(ptr, config_prof); 90234370Sjasone idalloc(ptr); 91234370Sjasone quarantine->curbytes -= usize; 92234370Sjasone quarantine->curobjs--; 93234370Sjasone quarantine->first = (quarantine->first + 1) & ((ZU(1) << 94234370Sjasone quarantine->lg_maxobjs) - 1); 95234370Sjasone } 96234370Sjasone} 97234370Sjasone 98234370Sjasonevoid 99234370Sjasonequarantine(void *ptr) 100234370Sjasone{ 101234370Sjasone quarantine_t *quarantine; 102234370Sjasone size_t usize = isalloc(ptr, config_prof); 103234370Sjasone 104234543Sjasone cassert(config_fill); 105234370Sjasone assert(opt_quarantine); 106234370Sjasone 107234370Sjasone quarantine = *quarantine_tsd_get(); 108234370Sjasone if (quarantine == NULL && (quarantine = 109234370Sjasone quarantine_init(LG_MAXOBJS_INIT)) == NULL) { 110234370Sjasone idalloc(ptr); 111234370Sjasone return; 112234370Sjasone } 113234370Sjasone /* 114234370Sjasone * Drain one or more objects if the quarantine size limit would be 115234370Sjasone * exceeded by appending ptr. 116234370Sjasone */ 117234370Sjasone if (quarantine->curbytes + usize > opt_quarantine) { 118234370Sjasone size_t upper_bound = (opt_quarantine >= usize) ? opt_quarantine 119234370Sjasone - usize : 0; 120234370Sjasone quarantine_drain(quarantine, upper_bound); 121234370Sjasone } 122234370Sjasone /* Grow the quarantine ring buffer if it's full. */ 123234370Sjasone if (quarantine->curobjs == (ZU(1) << quarantine->lg_maxobjs)) 124234370Sjasone quarantine = quarantine_grow(quarantine); 125234370Sjasone /* quarantine_grow() must free a slot if it fails to grow. */ 126234370Sjasone assert(quarantine->curobjs < (ZU(1) << quarantine->lg_maxobjs)); 127234370Sjasone /* Append ptr if its size doesn't exceed the quarantine size. */ 128234370Sjasone if (quarantine->curbytes + usize <= opt_quarantine) { 129234370Sjasone size_t offset = (quarantine->first + quarantine->curobjs) & 130234370Sjasone ((ZU(1) << quarantine->lg_maxobjs) - 1); 131234370Sjasone quarantine->objs[offset] = ptr; 132234370Sjasone quarantine->curbytes += usize; 133234370Sjasone quarantine->curobjs++; 134234370Sjasone if (opt_junk) 135234370Sjasone memset(ptr, 0x5a, usize); 136234370Sjasone } else { 137234370Sjasone assert(quarantine->curbytes == 0); 138234370Sjasone idalloc(ptr); 139234370Sjasone } 140234370Sjasone} 141234370Sjasone 142234370Sjasonestatic void 143234370Sjasonequarantine_cleanup(void *arg) 144234370Sjasone{ 145234370Sjasone quarantine_t *quarantine = *(quarantine_t **)arg; 146234370Sjasone 147234370Sjasone if (quarantine != NULL) { 148234370Sjasone quarantine_drain(quarantine, 0); 149234370Sjasone idalloc(quarantine); 150234370Sjasone } 151234370Sjasone} 152234370Sjasone 153234370Sjasonebool 154234370Sjasonequarantine_boot(void) 155234370Sjasone{ 156234370Sjasone 157234543Sjasone cassert(config_fill); 158234370Sjasone 159234370Sjasone if (quarantine_tsd_boot()) 160234370Sjasone return (true); 161234370Sjasone 162234370Sjasone return (false); 163234370Sjasone} 164