1*8e33eff8Schristos #ifndef JEMALLOC_INTERNAL_TCACHE_INLINES_H 2*8e33eff8Schristos #define JEMALLOC_INTERNAL_TCACHE_INLINES_H 3*8e33eff8Schristos 4*8e33eff8Schristos #include "jemalloc/internal/bin.h" 5*8e33eff8Schristos #include "jemalloc/internal/jemalloc_internal_types.h" 6*8e33eff8Schristos #include "jemalloc/internal/size_classes.h" 7*8e33eff8Schristos #include "jemalloc/internal/sz.h" 8*8e33eff8Schristos #include "jemalloc/internal/ticker.h" 9*8e33eff8Schristos #include "jemalloc/internal/util.h" 10*8e33eff8Schristos 11*8e33eff8Schristos static inline bool 12*8e33eff8Schristos tcache_enabled_get(tsd_t *tsd) { 13*8e33eff8Schristos return tsd_tcache_enabled_get(tsd); 14*8e33eff8Schristos } 15*8e33eff8Schristos 16*8e33eff8Schristos static inline void 17*8e33eff8Schristos tcache_enabled_set(tsd_t *tsd, bool enabled) { 18*8e33eff8Schristos bool was_enabled = tsd_tcache_enabled_get(tsd); 19*8e33eff8Schristos 20*8e33eff8Schristos if (!was_enabled && enabled) { 21*8e33eff8Schristos tsd_tcache_data_init(tsd); 22*8e33eff8Schristos } else if (was_enabled && !enabled) { 23*8e33eff8Schristos tcache_cleanup(tsd); 24*8e33eff8Schristos } 25*8e33eff8Schristos /* Commit the state last. Above calls check current state. */ 26*8e33eff8Schristos tsd_tcache_enabled_set(tsd, enabled); 27*8e33eff8Schristos tsd_slow_update(tsd); 28*8e33eff8Schristos } 29*8e33eff8Schristos 30*8e33eff8Schristos JEMALLOC_ALWAYS_INLINE void 31*8e33eff8Schristos tcache_event(tsd_t *tsd, tcache_t *tcache) { 32*8e33eff8Schristos if (TCACHE_GC_INCR == 0) { 33*8e33eff8Schristos return; 34*8e33eff8Schristos } 35*8e33eff8Schristos 36*8e33eff8Schristos if (unlikely(ticker_tick(&tcache->gc_ticker))) { 37*8e33eff8Schristos tcache_event_hard(tsd, tcache); 38*8e33eff8Schristos } 39*8e33eff8Schristos } 40*8e33eff8Schristos 41*8e33eff8Schristos JEMALLOC_ALWAYS_INLINE void * 42*8e33eff8Schristos tcache_alloc_small(tsd_t *tsd, arena_t *arena, tcache_t *tcache, 43*8e33eff8Schristos UNUSED size_t size, szind_t binind, bool zero, bool slow_path) { 44*8e33eff8Schristos void *ret; 45*8e33eff8Schristos cache_bin_t *bin; 46*8e33eff8Schristos bool tcache_success; 47*8e33eff8Schristos size_t usize JEMALLOC_CC_SILENCE_INIT(0); 48*8e33eff8Schristos 49*8e33eff8Schristos assert(binind < NBINS); 50*8e33eff8Schristos bin = tcache_small_bin_get(tcache, binind); 51*8e33eff8Schristos ret = cache_bin_alloc_easy(bin, &tcache_success); 52*8e33eff8Schristos assert(tcache_success == (ret != NULL)); 53*8e33eff8Schristos if (unlikely(!tcache_success)) { 54*8e33eff8Schristos bool tcache_hard_success; 55*8e33eff8Schristos arena = arena_choose(tsd, arena); 56*8e33eff8Schristos if (unlikely(arena == NULL)) { 57*8e33eff8Schristos return NULL; 58*8e33eff8Schristos } 59*8e33eff8Schristos 60*8e33eff8Schristos ret = tcache_alloc_small_hard(tsd_tsdn(tsd), arena, tcache, 61*8e33eff8Schristos bin, binind, &tcache_hard_success); 62*8e33eff8Schristos if (tcache_hard_success == false) { 63*8e33eff8Schristos return NULL; 64*8e33eff8Schristos } 65*8e33eff8Schristos } 66*8e33eff8Schristos 67*8e33eff8Schristos assert(ret); 68*8e33eff8Schristos /* 69*8e33eff8Schristos * Only compute usize if required. The checks in the following if 70*8e33eff8Schristos * statement are all static. 71*8e33eff8Schristos */ 72*8e33eff8Schristos if (config_prof || (slow_path && config_fill) || unlikely(zero)) { 73*8e33eff8Schristos usize = sz_index2size(binind); 74*8e33eff8Schristos assert(tcache_salloc(tsd_tsdn(tsd), ret) == usize); 75*8e33eff8Schristos } 76*8e33eff8Schristos 77*8e33eff8Schristos if (likely(!zero)) { 78*8e33eff8Schristos if (slow_path && config_fill) { 79*8e33eff8Schristos if (unlikely(opt_junk_alloc)) { 80*8e33eff8Schristos arena_alloc_junk_small(ret, &bin_infos[binind], 81*8e33eff8Schristos false); 82*8e33eff8Schristos } else if (unlikely(opt_zero)) { 83*8e33eff8Schristos memset(ret, 0, usize); 84*8e33eff8Schristos } 85*8e33eff8Schristos } 86*8e33eff8Schristos } else { 87*8e33eff8Schristos if (slow_path && config_fill && unlikely(opt_junk_alloc)) { 88*8e33eff8Schristos arena_alloc_junk_small(ret, &bin_infos[binind], true); 89*8e33eff8Schristos } 90*8e33eff8Schristos memset(ret, 0, usize); 91*8e33eff8Schristos } 92*8e33eff8Schristos 93*8e33eff8Schristos if (config_stats) { 94*8e33eff8Schristos bin->tstats.nrequests++; 95*8e33eff8Schristos } 96*8e33eff8Schristos if (config_prof) { 97*8e33eff8Schristos tcache->prof_accumbytes += usize; 98*8e33eff8Schristos } 99*8e33eff8Schristos tcache_event(tsd, tcache); 100*8e33eff8Schristos return ret; 101*8e33eff8Schristos } 102*8e33eff8Schristos 103*8e33eff8Schristos JEMALLOC_ALWAYS_INLINE void * 104*8e33eff8Schristos tcache_alloc_large(tsd_t *tsd, arena_t *arena, tcache_t *tcache, size_t size, 105*8e33eff8Schristos szind_t binind, bool zero, bool slow_path) { 106*8e33eff8Schristos void *ret; 107*8e33eff8Schristos cache_bin_t *bin; 108*8e33eff8Schristos bool tcache_success; 109*8e33eff8Schristos 110*8e33eff8Schristos assert(binind >= NBINS &&binind < nhbins); 111*8e33eff8Schristos bin = tcache_large_bin_get(tcache, binind); 112*8e33eff8Schristos ret = cache_bin_alloc_easy(bin, &tcache_success); 113*8e33eff8Schristos assert(tcache_success == (ret != NULL)); 114*8e33eff8Schristos if (unlikely(!tcache_success)) { 115*8e33eff8Schristos /* 116*8e33eff8Schristos * Only allocate one large object at a time, because it's quite 117*8e33eff8Schristos * expensive to create one and not use it. 118*8e33eff8Schristos */ 119*8e33eff8Schristos arena = arena_choose(tsd, arena); 120*8e33eff8Schristos if (unlikely(arena == NULL)) { 121*8e33eff8Schristos return NULL; 122*8e33eff8Schristos } 123*8e33eff8Schristos 124*8e33eff8Schristos ret = large_malloc(tsd_tsdn(tsd), arena, sz_s2u(size), zero); 125*8e33eff8Schristos if (ret == NULL) { 126*8e33eff8Schristos return NULL; 127*8e33eff8Schristos } 128*8e33eff8Schristos } else { 129*8e33eff8Schristos size_t usize JEMALLOC_CC_SILENCE_INIT(0); 130*8e33eff8Schristos 131*8e33eff8Schristos /* Only compute usize on demand */ 132*8e33eff8Schristos if (config_prof || (slow_path && config_fill) || 133*8e33eff8Schristos unlikely(zero)) { 134*8e33eff8Schristos usize = sz_index2size(binind); 135*8e33eff8Schristos assert(usize <= tcache_maxclass); 136*8e33eff8Schristos } 137*8e33eff8Schristos 138*8e33eff8Schristos if (likely(!zero)) { 139*8e33eff8Schristos if (slow_path && config_fill) { 140*8e33eff8Schristos if (unlikely(opt_junk_alloc)) { 141*8e33eff8Schristos memset(ret, JEMALLOC_ALLOC_JUNK, 142*8e33eff8Schristos usize); 143*8e33eff8Schristos } else if (unlikely(opt_zero)) { 144*8e33eff8Schristos memset(ret, 0, usize); 145*8e33eff8Schristos } 146*8e33eff8Schristos } 147*8e33eff8Schristos } else { 148*8e33eff8Schristos memset(ret, 0, usize); 149*8e33eff8Schristos } 150*8e33eff8Schristos 151*8e33eff8Schristos if (config_stats) { 152*8e33eff8Schristos bin->tstats.nrequests++; 153*8e33eff8Schristos } 154*8e33eff8Schristos if (config_prof) { 155*8e33eff8Schristos tcache->prof_accumbytes += usize; 156*8e33eff8Schristos } 157*8e33eff8Schristos } 158*8e33eff8Schristos 159*8e33eff8Schristos tcache_event(tsd, tcache); 160*8e33eff8Schristos return ret; 161*8e33eff8Schristos } 162*8e33eff8Schristos 163*8e33eff8Schristos JEMALLOC_ALWAYS_INLINE void 164*8e33eff8Schristos tcache_dalloc_small(tsd_t *tsd, tcache_t *tcache, void *ptr, szind_t binind, 165*8e33eff8Schristos bool slow_path) { 166*8e33eff8Schristos cache_bin_t *bin; 167*8e33eff8Schristos cache_bin_info_t *bin_info; 168*8e33eff8Schristos 169*8e33eff8Schristos assert(tcache_salloc(tsd_tsdn(tsd), ptr) <= SMALL_MAXCLASS); 170*8e33eff8Schristos 171*8e33eff8Schristos if (slow_path && config_fill && unlikely(opt_junk_free)) { 172*8e33eff8Schristos arena_dalloc_junk_small(ptr, &bin_infos[binind]); 173*8e33eff8Schristos } 174*8e33eff8Schristos 175*8e33eff8Schristos bin = tcache_small_bin_get(tcache, binind); 176*8e33eff8Schristos bin_info = &tcache_bin_info[binind]; 177*8e33eff8Schristos if (unlikely(bin->ncached == bin_info->ncached_max)) { 178*8e33eff8Schristos tcache_bin_flush_small(tsd, tcache, bin, binind, 179*8e33eff8Schristos (bin_info->ncached_max >> 1)); 180*8e33eff8Schristos } 181*8e33eff8Schristos assert(bin->ncached < bin_info->ncached_max); 182*8e33eff8Schristos bin->ncached++; 183*8e33eff8Schristos *(bin->avail - bin->ncached) = ptr; 184*8e33eff8Schristos 185*8e33eff8Schristos tcache_event(tsd, tcache); 186*8e33eff8Schristos } 187*8e33eff8Schristos 188*8e33eff8Schristos JEMALLOC_ALWAYS_INLINE void 189*8e33eff8Schristos tcache_dalloc_large(tsd_t *tsd, tcache_t *tcache, void *ptr, szind_t binind, 190*8e33eff8Schristos bool slow_path) { 191*8e33eff8Schristos cache_bin_t *bin; 192*8e33eff8Schristos cache_bin_info_t *bin_info; 193*8e33eff8Schristos 194*8e33eff8Schristos assert(tcache_salloc(tsd_tsdn(tsd), ptr) > SMALL_MAXCLASS); 195*8e33eff8Schristos assert(tcache_salloc(tsd_tsdn(tsd), ptr) <= tcache_maxclass); 196*8e33eff8Schristos 197*8e33eff8Schristos if (slow_path && config_fill && unlikely(opt_junk_free)) { 198*8e33eff8Schristos large_dalloc_junk(ptr, sz_index2size(binind)); 199*8e33eff8Schristos } 200*8e33eff8Schristos 201*8e33eff8Schristos bin = tcache_large_bin_get(tcache, binind); 202*8e33eff8Schristos bin_info = &tcache_bin_info[binind]; 203*8e33eff8Schristos if (unlikely(bin->ncached == bin_info->ncached_max)) { 204*8e33eff8Schristos tcache_bin_flush_large(tsd, bin, binind, 205*8e33eff8Schristos (bin_info->ncached_max >> 1), tcache); 206*8e33eff8Schristos } 207*8e33eff8Schristos assert(bin->ncached < bin_info->ncached_max); 208*8e33eff8Schristos bin->ncached++; 209*8e33eff8Schristos *(bin->avail - bin->ncached) = ptr; 210*8e33eff8Schristos 211*8e33eff8Schristos tcache_event(tsd, tcache); 212*8e33eff8Schristos } 213*8e33eff8Schristos 214*8e33eff8Schristos JEMALLOC_ALWAYS_INLINE tcache_t * 215*8e33eff8Schristos tcaches_get(tsd_t *tsd, unsigned ind) { 216*8e33eff8Schristos tcaches_t *elm = &tcaches[ind]; 217*8e33eff8Schristos if (unlikely(elm->tcache == NULL)) { 218*8e33eff8Schristos elm->tcache = tcache_create_explicit(tsd); 219*8e33eff8Schristos } 220*8e33eff8Schristos return elm->tcache; 221*8e33eff8Schristos } 222*8e33eff8Schristos 223*8e33eff8Schristos #endif /* JEMALLOC_INTERNAL_TCACHE_INLINES_H */ 224